diff options
author | mjacob <mjacob@cvs.openbsd.org> | 2001-04-04 22:07:41 +0000 |
---|---|---|
committer | mjacob <mjacob@cvs.openbsd.org> | 2001-04-04 22:07:41 +0000 |
commit | 66189cb3ad805011164c2b32e0a4e270f8de723a (patch) | |
tree | 04df7bf22d696a9ec501797f86812fda44fe484d /sys/dev/ic | |
parent | ba2ec9ad00ca8fb59a0a6b7541f20cbfd37726c8 (diff) |
Ansify source. Set poenings to maxcmds again. Turn on interrupt
driven mailbox commands if we've gotten past coldstart. Go to
a synchronous restart queue blockage model for REQUEST QUEUE
overflow conditions. Make sure that we only delete timers for
commands that haven't gotten expired timers.
Diffstat (limited to 'sys/dev/ic')
-rw-r--r-- | sys/dev/ic/isp_openbsd.c | 287 |
1 files changed, 154 insertions, 133 deletions
diff --git a/sys/dev/ic/isp_openbsd.c b/sys/dev/ic/isp_openbsd.c index 407e23bd5b2..da8874b76f2 100644 --- a/sys/dev/ic/isp_openbsd.c +++ b/sys/dev/ic/isp_openbsd.c @@ -1,8 +1,8 @@ -/* $OpenBSD: isp_openbsd.c,v 1.17 2001/02/12 23:47:11 mjacob Exp $ */ +/* $OpenBSD: isp_openbsd.c,v 1.18 2001/04/04 22:07:40 mjacob Exp $ */ /* * Platform (OpenBSD) dependent common attachment code for Qlogic adapters. * - * Copyright (c) 1999, 2000 by Matthew Jacob + * Copyright (c) 1999, 2000, 2001 by Matthew Jacob * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -60,16 +60,17 @@ */ #define _XT(xs) ((((xs)->timeout/1000) * hz) + (3 * hz)) -static void ispminphys __P((struct buf *)); -static int32_t ispcmd_slow __P((XS_T *)); -static int32_t ispcmd __P((XS_T *)); +static void ispminphys(struct buf *); +static int32_t ispcmd_slow(XS_T *); +static int32_t ispcmd(XS_T *); static struct scsi_device isp_dev = { NULL, NULL, NULL, NULL }; -static int isp_polled_cmd __P((struct ispsoftc *, XS_T *)); -static void isp_wdog __P((void *)); +static int isp_polled_cmd (struct ispsoftc *, XS_T *); +static void isp_wdog (void *); static void isp_requeue(void *); -static void isp_internal_restart(void *); +static void isp_trestart(void *); +static void isp_restart(struct ispsoftc *); struct cfdriver isp_cd = { NULL, "isp", DV_DULL @@ -80,8 +81,7 @@ struct cfdriver isp_cd = { * Complete attachment of hardware, include subdevices. */ void -isp_attach(isp) - struct ispsoftc *isp; +isp_attach(struct ispsoftc *isp) { struct scsi_link *lptr = &isp->isp_osinfo._link[0]; isp->isp_osinfo._adapter.scsi_minphys = ispminphys; @@ -97,15 +97,14 @@ isp_attach(isp) lptr->adapter_softc = isp; lptr->device = &isp_dev; lptr->adapter = &isp->isp_osinfo._adapter; - lptr->openings = isp->isp_maxcmds > 128? 128 : isp->isp_maxcmds; + lptr->openings = imin(isp->isp_maxcmds, MAXISPREQUEST(isp)); + isp->isp_osinfo._adapter.scsi_cmd = ispcmd_slow; if (IS_FC(isp)) { - isp->isp_osinfo._adapter.scsi_cmd = ispcmd; lptr->adapter_buswidth = MAX_FC_TARG; /* We can set max lun width here */ /* loopid set below */ } else { sdparam *sdp = isp->isp_param; - isp->isp_osinfo._adapter.scsi_cmd = ispcmd_slow; lptr->adapter_buswidth = MAX_TARGETS; /* We can set max lun width here */ lptr->adapter_target = sdp->isp_initiator_id; @@ -115,8 +114,7 @@ isp_attach(isp) lptrb->adapter_softc = isp; lptrb->device = &isp_dev; lptrb->adapter = &isp->isp_osinfo._adapter; - lptrb->openings = isp->isp_maxcmds > 128? - 128 : isp->isp_maxcmds; + lptrb->openings = lptr->openings; lptrb->adapter_buswidth = MAX_TARGETS; lptrb->adapter_target = sdp->isp_initiator_id; lptrb->flags = SDEV_2NDBUS; @@ -158,16 +156,6 @@ isp_attach(isp) ISP_UNLOCK(isp); lptr->adapter_target = defid; } - - /* - * After this point, we *could* be doing the new configuration - * schema which allows interrups, so we can do tsleep/wakeup - * for mailbox stuff at that point. - */ -#if 0 - isp->isp_osinfo.no_mbox_ints = 0; -#endif - /* * And attach children (if any). */ @@ -187,8 +175,7 @@ isp_attach(isp) */ static void -ispminphys(bp) - struct buf *bp; +ispminphys(struct buf *bp) { /* * XX: Only the 1020 has a 24 bit limit. @@ -200,14 +187,22 @@ ispminphys(bp) } static int32_t -ispcmd_slow(xs) - XS_T *xs; +ispcmd_slow(XS_T *xs) { + extern int cold; sdparam *sdp; int tgt, chan; u_int16_t f; struct ispsoftc *isp = XS_ISP(xs); + if (IS_FC(isp)) { + if (cold == 0) { + isp->isp_osinfo.no_mbox_ints = 0; + isp->isp_osinfo._adapter.scsi_cmd = ispcmd; + } + return (ispcmd(xs)); + } + /* * Have we completed discovery for this target on this adapter? */ @@ -219,31 +214,19 @@ ispcmd_slow(xs) (isp->isp_osinfo.discovered[chan] & (1 << tgt)) != 0) { return (ispcmd(xs)); } + if (cold == 0) { + isp->isp_osinfo.no_mbox_ints = 0; + } f = DPARM_DEFAULT; if (xs->sc_link->quirks & SDEV_NOSYNC) { - f ^= DPARM_SYNC; -#ifdef DEBUG - } else { - printf("%s: channel %d target %d can do SYNC xfers\n", - isp->isp_name, chan, tgt); -#endif + f &= ~DPARM_SYNC; } if (xs->sc_link->quirks & SDEV_NOWIDE) { - f ^= DPARM_WIDE; -#ifdef DEBUG - } else { - printf("%s: channel %d target %d can do WIDE xfers\n", - isp->isp_name, chan, tgt); -#endif + f &= ~DPARM_WIDE; } if (xs->sc_link->quirks & SDEV_NOTAGS) { - f ^= DPARM_TQING; -#ifdef DEBUG - } else { - printf("%s: channel %d target %d can do TAGGED xfers\n", - isp->isp_name, chan, tgt); -#endif + f &= ~DPARM_TQING; } /* @@ -282,9 +265,22 @@ ispcmd_slow(xs) return (ispcmd(xs)); } +static INLINE void isp_add2_blocked_queue(struct ispsoftc *, XS_T *); + +static INLINE void +isp_add2_blocked_queue(struct ispsoftc *isp, XS_T *xs) +{ + if (isp->isp_osinfo.wqf != NULL) { + isp->isp_osinfo.wqt->free_list.le_next = xs; + } else { + isp->isp_osinfo.wqf = xs; + } + isp->isp_osinfo.wqt = xs; + xs->free_list.le_next = NULL; +} + static int32_t -ispcmd(xs) - XS_T *xs; +ispcmd(XS_T *xs) { struct ispsoftc *isp; int result; @@ -294,7 +290,6 @@ ispcmd(xs) * Make sure that there's *some* kind of sane setting. */ timeout_set(&xs->stimeout, isp_wdog, isp); - timeout_del(&xs->stimeout); isp = XS_ISP(xs); @@ -321,21 +316,20 @@ ispcmd(xs) * Check for queue blockage... */ if (isp->isp_osinfo.blocked) { - isp_prt(isp, ISP_LOGDEBUG2, "blocked"); if (xs->flags & SCSI_POLL) { xs->error = XS_DRIVER_STUFFUP; ISP_UNLOCK(isp); return (TRY_AGAIN_LATER); } - if (isp->isp_osinfo.wqf != NULL) { - isp->isp_osinfo.wqt->free_list.le_next = xs; - } else { - isp->isp_osinfo.wqf = xs; + if (isp->isp_osinfo.blocked == 2) { + isp_restart(isp); + } + if (isp->isp_osinfo.blocked) { + isp_add2_blocked_queue(isp, xs); + ISP_UNLOCK(isp); + isp_prt(isp, ISP_LOGDEBUG0, "added to blocked queue"); + return (SUCCESSFULLY_QUEUED); } - isp->isp_osinfo.wqt = xs; - xs->free_list.le_next = NULL; - ISP_UNLOCK(isp); - return (SUCCESSFULLY_QUEUED); } if (xs->flags & SCSI_POLL) { @@ -349,32 +343,32 @@ ispcmd(xs) result = isp_start(xs); -#if 0 -{ - static int na[16] = { 0 }; - if (na[isp->isp_unit] < isp->isp_nactive) { - isp_prt(isp, ISP_LOGALL, "active hiwater %d", isp->isp_nactive); - na[isp->isp_unit] = isp->isp_nactive; - } -} -#endif - switch (result) { case CMD_QUEUED: result = SUCCESSFULLY_QUEUED; if (xs->timeout) { timeout_add(&xs->stimeout, _XT(xs)); + XS_CMD_S_TIMER(xs); + } + if (isp->isp_osinfo.hiwater < isp->isp_nactive) { + isp->isp_osinfo.hiwater = isp->isp_nactive; + isp_prt(isp, ISP_LOGDEBUG0, + "Active Hiwater Mark=%d", isp->isp_nactive); } break; case CMD_EAGAIN: -#if 0 - result = TRY_AGAIN_LATER; + isp->isp_osinfo.blocked |= 2; + isp_prt(isp, ISP_LOGDEBUG0, "blocking queue"); + isp_add2_blocked_queue(isp, xs); + result = SUCCESSFULLY_QUEUED; break; -#endif case CMD_RQLATER: - result = SUCCESSFULLY_QUEUED; + result = SUCCESSFULLY_QUEUED; /* Lie */ + isp_prt(isp, ISP_LOGDEBUG1, "retrying later for %d.%d", + XS_TGT(xs), XS_LUN(xs)); timeout_set(&xs->stimeout, isp_requeue, xs); timeout_add(&xs->stimeout, hz); + XS_CMD_S_TIMER(xs); break; case CMD_COMPLETE: result = COMPLETE; @@ -385,9 +379,7 @@ ispcmd(xs) } static int -isp_polled_cmd(isp, xs) - struct ispsoftc *isp; - XS_T *xs; +isp_polled_cmd(struct ispsoftc *isp, XS_T *xs) { int result; int infinite = 0, mswait; @@ -448,27 +440,32 @@ isp_polled_cmd(isp, xs) } void -isp_done(xs) - XS_T *xs; +isp_done(XS_T *xs) { XS_CMD_S_DONE(xs); if (XS_CMD_WDOG_P(xs) == 0) { - if (xs->timeout) { + struct ispsoftc *isp = XS_ISP(xs); + if (XS_CMD_TIMER_P(xs)) { timeout_del(&xs->stimeout); + XS_CMD_C_TIMER(xs); } if (XS_CMD_GRACE_P(xs)) { struct ispsoftc *isp = XS_ISP(xs); - isp_prt(isp, ISP_LOGDEBUG1, + isp_prt(isp, ISP_LOGWARN, "finished command on borrowed time"); } XS_CMD_S_CLEAR(xs); scsi_done(xs); + if (isp->isp_osinfo.blocked == 2) { + isp->isp_osinfo.blocked = 0; + isp_prt(isp, ISP_LOGDEBUG0, "restarting blocked queue"); + isp_restart(isp); + } } } static void -isp_wdog(arg) - void *arg; +isp_wdog(void *arg) { XS_T *xs = arg; struct ispsoftc *isp = XS_ISP(xs); @@ -510,8 +507,8 @@ isp_wdog(arg) } while (r != r1 && ++i < 1000); if (INT_PENDING(isp, r) && isp_intr(isp) && XS_CMD_DONE_P(xs)) { - isp_prt(isp, ISP_LOGDEBUG1, "watchdog cleanup (%x, %x)", - isp->isp_name, handle, r); + isp_prt(isp, ISP_LOGINFO, "watchdog cleanup (%x, %x)", + handle, r); XS_CMD_C_WDOG(xs); isp_done(xs); } else if (XS_CMD_GRACE_P(xs)) { @@ -536,11 +533,12 @@ isp_wdog(arg) u_int16_t iptr, optr; ispreq_t *mp; - isp_prt(isp, ISP_LOGDEBUG2, + isp_prt(isp, ISP_LOGINFO, "possible command timeout (%x, %x)", handle, r); XS_CMD_C_WDOG(xs); timeout_add(&xs->stimeout, _XT(xs)); + XS_CMD_S_TIMER(xs); if (isp_getrqentry(isp, &iptr, &optr, (void **) &mp)) { ISP_UNLOCK(isp); return; @@ -555,7 +553,7 @@ isp_wdog(arg) ISP_ADD_REQUEST(isp, iptr); } } else if (isp->isp_dblev) { - isp_prt(isp, ISP_LOGDEBUG2, "watchdog with no command"); + isp_prt(isp, ISP_LOGDEBUG1, "watchdog with no command"); } ISP_UNLOCK(isp); } @@ -568,8 +566,7 @@ isp_wdog(arg) * Locks are held before coming here. */ void -isp_uninit(isp) - struct ispsoftc *isp; +isp_uninit(struct ispsoftc *isp) { ISP_LOCK(isp); /* @@ -586,72 +583,100 @@ isp_uninit(isp) static void isp_requeue(void *arg) { + int r; struct scsi_xfer *xs = arg; struct ispsoftc *isp = XS_ISP(xs); ISP_LOCK(isp); - switch (ispcmd_slow(xs)) { - case SUCCESSFULLY_QUEUED: - printf("%s: isp_command_reque: queued %d.%d\n", - isp->isp_name, XS_TGT(xs), XS_LUN(xs)); + r = isp_start(xs); + switch (r) { + case CMD_QUEUED: + isp_prt(isp, ISP_LOGDEBUG1, "restarted command for %d.%d", + XS_TGT(xs), XS_LUN(xs)); if (xs->timeout) { timeout_set(&xs->stimeout, isp_wdog, isp); timeout_add(&xs->stimeout, _XT(xs)); + XS_CMD_S_TIMER(xs); } break; - case TRY_AGAIN_LATER: - printf("%s: EAGAIN for %d.%d\n", - isp->isp_name, XS_TGT(xs), XS_LUN(xs)); + case CMD_EAGAIN: + isp_prt(isp, ISP_LOGDEBUG0, "blocked cmd again"); + isp->isp_osinfo.blocked |= 2; + isp_add2_blocked_queue(isp, xs); + break; + case CMD_RQLATER: + isp_prt(isp, ISP_LOGDEBUG0, "%s for %d.%d", + (r == CMD_EAGAIN)? "CMD_EAGAIN" : "CMD_RQLATER", + XS_TGT(xs), XS_LUN(xs)); timeout_set(&xs->stimeout, isp_requeue, xs); timeout_add(&xs->stimeout, hz); + XS_CMD_S_TIMER(xs); break; - case COMPLETE: + case CMD_COMPLETE: /* can only be an error */ if (XS_NOERR(xs)) XS_SETERR(xs, XS_DRIVER_STUFFUP); - XS_CMD_S_DONE(xs); + isp_done(xs); break; } ISP_UNLOCK(isp); } /* - * Restart function after a LOOP UP event (e.g.), - * done as a timeout for some hysteresis. + * Restart function after a LOOP UP event or a commmand completing, + * somtimes done as a timeout for some hysteresis. */ static void -isp_internal_restart(void *arg) +isp_trestart(void *arg) { struct ispsoftc *isp = arg; - int result, nrestarted = 0; + struct scsi_xfer *list; ISP_LOCK(isp); - if (isp->isp_osinfo.blocked == 0) { - struct scsi_xfer *xs; - while ((xs = isp->isp_osinfo.wqf) != NULL) { - isp->isp_osinfo.wqf = xs->free_list.le_next; + isp->isp_osinfo.rtpend = 0; + list = isp->isp_osinfo.wqf; + if (isp->isp_osinfo.blocked == 0 && list != NULL) { + int nrestarted = 0; + + isp->isp_osinfo.wqf = NULL; + ISP_UNLOCK(isp); + do { + struct scsi_xfer *xs = list; + list = xs->free_list.le_next; xs->free_list.le_next = NULL; - result = isp_start(xs); - if (result != CMD_QUEUED) { - printf("%s: botched command restart (0x%x)\n", - isp->isp_name, result); - if (XS_NOERR(xs)) - XS_SETERR(xs, XS_DRIVER_STUFFUP); - XS_CMD_S_DONE(xs); - } else if (xs->timeout) { - timeout_add(&xs->stimeout, _XT(xs)); - } - nrestarted++; - } - printf("%s: requeued %d commands\n", isp->isp_name, nrestarted); + isp_requeue(xs); + if (isp->isp_osinfo.wqf == NULL) + nrestarted++; + } while (list != NULL); + isp_prt(isp, ISP_LOGDEBUG0, "requeued %d commands", nrestarted); + } else { + ISP_UNLOCK(isp); + } +} + +static void +isp_restart(struct ispsoftc *isp) +{ + struct scsi_xfer *list; + + list = isp->isp_osinfo.wqf; + if (isp->isp_osinfo.blocked == 0 && list != NULL) { + int nrestarted = 0; + + isp->isp_osinfo.wqf = NULL; + do { + struct scsi_xfer *xs = list; + list = xs->free_list.le_next; + xs->free_list.le_next = NULL; + isp_requeue(xs); + if (isp->isp_osinfo.wqf == NULL) + nrestarted++; + } while (list != NULL); + isp_prt(isp, ISP_LOGDEBUG0, "requeued %d commands", nrestarted); } - ISP_UNLOCK(isp); } int -isp_async(isp, cmd, arg) - struct ispsoftc *isp; - ispasync_t cmd; - void *arg; +isp_async(struct ispsoftc *isp, ispasync_t cmd, void *arg) { int bus, tgt; @@ -738,12 +763,15 @@ isp_async(isp, cmd, arg) * Hopefully we get here in time to minimize the number * of commands we are firing off that are sure to die. */ - isp->isp_osinfo.blocked = 1; + isp->isp_osinfo.blocked |= 1; isp_prt(isp, ISP_LOGINFO, "Loop DOWN"); break; case ISPASYNC_LOOP_UP: - isp->isp_osinfo.blocked = 0; - timeout_set(&isp->isp_osinfo.rqt, isp_internal_restart, isp); + isp->isp_osinfo.blocked &= ~1; + if (isp->isp_osinfo.rtpend == 0) { + timeout_set(&isp->isp_osinfo.rqt, isp_trestart, isp); + isp->isp_osinfo.rtpend = 1; + } timeout_add(&isp->isp_osinfo.rqt, 1); isp_prt(isp, ISP_LOGINFO, "Loop UP"); break; @@ -897,14 +925,7 @@ isp_async(isp, cmd, arg) } void -#ifdef __STDC__ isp_prt(struct ispsoftc *isp, int level, const char *fmt, ...) -#else -isp_log(isp, fmt, va_alist) - struct ispsoftc *isp; - char *fmt; - va_dcl; -#endif { va_list ap; if (level != ISP_LOGALL && (level & isp->isp_dblev) == 0) { |