diff options
author | Matt Jacob <mjacob@FreeBSD.org> | 2002-01-03 20:43:22 +0000 |
---|---|---|
committer | Matt Jacob <mjacob@FreeBSD.org> | 2002-01-03 20:43:22 +0000 |
commit | 2903b27203209c8b6e46bd877b6fc7c9b28a81ea (patch) | |
tree | 432d531bd42c741928abf5d6937ced643130d219 /sys/dev | |
parent | 7855d28a287dc0aee3f85df9eb5d5a9197ab2391 (diff) | |
download | src-2903b27203209c8b6e46bd877b6fc7c9b28a81ea.tar.gz src-2903b27203209c8b6e46bd877b6fc7c9b28a81ea.zip |
Implement REDUCED INTERRUPT OPERATION usage form FC cards- this allows the
firmware to delay completion of commands so that it can attempt to batch
a bunch of completions at once- either returning 16 bit handles in mailbox
registers, or in a resposne queue entry that has a whole wad of 16 bit handles.
Distinguish between 2300 and 2312 chipsets- if only because the revisions
on the chips have different meanings.
Add more instrumentation plus ISP_GET_STATS and ISP_CLR_STATS ioctls.
Run up the maximum number of response queue entities we'll look at
per interrupt.
If we haven't set HBA role yet, always return success from isp_fc_runstate.
MFC after: 2 weeks
Notes
Notes:
svn path=/head/; revision=88855
Diffstat (limited to 'sys/dev')
-rw-r--r-- | sys/dev/isp/isp.c | 117 | ||||
-rw-r--r-- | sys/dev/isp/isp_freebsd.c | 37 | ||||
-rw-r--r-- | sys/dev/isp/isp_inline.h | 20 | ||||
-rw-r--r-- | sys/dev/isp/isp_ioctl.h | 29 | ||||
-rw-r--r-- | sys/dev/isp/ispmbox.h | 6 | ||||
-rw-r--r-- | sys/dev/isp/ispvar.h | 11 |
6 files changed, 185 insertions, 35 deletions
diff --git a/sys/dev/isp/isp.c b/sys/dev/isp/isp.c index 79768856a5e7..094d029827cc 100644 --- a/sys/dev/isp/isp.c +++ b/sys/dev/isp/isp.c @@ -109,7 +109,7 @@ static const char sc4[] = "NVRAM"; /* * Local function prototypes. */ -static int isp_parse_async(struct ispsoftc *, int); +static int isp_parse_async(struct ispsoftc *, u_int16_t); static int isp_handle_other_response(struct ispsoftc *, int, isphdr_t *, u_int16_t *); static void @@ -213,7 +213,7 @@ isp_reset(struct ispsoftc *isp) * Set up default request/response queue in-pointer/out-pointer * register indices. */ - if (IS_2300(isp)) { + if (IS_23XX(isp)) { isp->isp_rqstinrp = BIU_REQINP; isp->isp_rqstoutrp = BIU_REQOUTP; isp->isp_respinrp = BIU_RSPINP; @@ -240,6 +240,7 @@ isp_reset(struct ispsoftc *isp) btype = "2200"; break; case ISP_HA_FC_2300: + case ISP_HA_FC_2312: btype = "2300"; break; default: @@ -535,7 +536,7 @@ again: #endif } else { ISP_WRITE(isp, RISC_MTR2100, 0x1212); - if (IS_2200(isp) || IS_2300(isp)) { + if (IS_2200(isp) || IS_23XX(isp)) { ISP_WRITE(isp, HCCR, HCCR_2X00_DISABLE_PARITY_PAUSE); } } @@ -553,7 +554,7 @@ again: * Avoid doing this on the 2312 because you can generate a PCI * parity error (chip breakage). */ - if (IS_2300(isp)) { + if (IS_23XX(isp)) { USEC_DELAY(5); } else { loops = MBOX_DELAY_COUNT; @@ -619,7 +620,7 @@ again: dodnld = 0; } - if (IS_2300(isp)) + if (IS_23XX(isp)) code_org = ISP_CODE_ORG_2300; else code_org = ISP_CODE_ORG; @@ -1204,7 +1205,7 @@ isp_fibre_init(struct ispsoftc *isp) * * NB: for the 2300, ICBOPT_EXTENDED is required. */ - if (IS_2200(isp) || IS_2300(isp)) { + if (IS_2200(isp) || IS_23XX(isp)) { icbp->icb_fwoptions |= ICBOPT_EXTENDED; /* * Prefer or force Point-To-Point instead Loop? @@ -1223,8 +1224,8 @@ isp_fibre_init(struct ispsoftc *isp) icbp->icb_xfwoptions |= ICBXOPT_LOOP_2_PTP; break; } - if (IS_2300(isp)) { - if (isp->isp_revision < 2) { + if (IS_23XX(isp)) { + if (!IS_2312(isp) && isp->isp_revision < 2) { icbp->icb_fwoptions &= ~ICBOPT_FAST_POST; } if (isp->isp_confopts & ISP_CFG_ONEGB) { @@ -1235,10 +1236,13 @@ isp_fibre_init(struct ispsoftc *isp) icbp->icb_zfwoptions |= ICBZOPT_RATE_AUTO; } } + icbp->icb_xfwoptions |= ICBXOPT_RIO_16BIT; + icbp->icb_racctimer = 4; + icbp->icb_idelaytimer = 8; } if ((IS_2200(isp) && ISP_FW_REVX(isp->isp_fwrev) >= - ISP_FW_REV(2, 1, 26)) || IS_2300(isp)) { + ISP_FW_REV(2, 1, 26)) || IS_23XX(isp)) { /* * Turn on LIP F8 async event (1) * Turn on generate AE 8013 on all LIP Resets (2) @@ -1252,7 +1256,7 @@ isp_fibre_init(struct ispsoftc *isp) } icbp->icb_logintime = 30; /* 30 second login timeout */ - if (IS_2300(isp)) { + if (IS_23XX(isp)) { ISP_WRITE(isp, isp->isp_rqstinrp, 0); ISP_WRITE(isp, isp->isp_rqstoutrp, 0); ISP_WRITE(isp, isp->isp_respinrp, 0); @@ -1517,7 +1521,7 @@ isp_fclink_test(struct ispsoftc *isp, int usdelay) return (-1); } fcp->isp_loopid = mbs.param[1]; - if (IS_2200(isp) || IS_2300(isp)) { + if (IS_2200(isp) || IS_23XX(isp)) { int topo = (int) mbs.param[6]; if (topo < TOPO_NL_PORT || topo > TOPO_PTP_STUB) topo = TOPO_PTP_STUB; @@ -1594,7 +1598,7 @@ not_on_fabric: } fcp->isp_gbspeed = 1; - if (IS_2300(isp)) { + if (IS_23XX(isp)) { mbs.param[0] = MBOX_GET_SET_DATA_RATE; mbs.param[1] = MBGSD_GET_RATE; /* mbs.param[2] undefined if we're just getting rate */ @@ -1849,7 +1853,7 @@ isp_pdb_sync(struct ispsoftc *isp) mbs.param[1] = loopid << 8; mbs.param[2] = portid >> 16; mbs.param[3] = portid & 0xffff; - if (IS_2200(isp) || IS_2300(isp)) { + if (IS_2200(isp) || IS_23XX(isp)) { /* only issue a PLOGI if not logged in */ mbs.param[1] |= 0x1; } @@ -2979,7 +2983,7 @@ isp_control(struct ispsoftc *isp, ispctl_t ctl, void *arg) * Limit our stack depth by sticking with the max likely number * of completions on a request queue at any one time. */ -#define MAX_REQUESTQ_COMPLETIONS 32 +#define MAX_REQUESTQ_COMPLETIONS 64 void isp_intr(struct ispsoftc *isp, u_int16_t isr, u_int16_t sema, u_int16_t mbox) @@ -3010,12 +3014,9 @@ isp_intr(struct ispsoftc *isp, u_int16_t isr, u_int16_t sema, u_int16_t mbox) "Mbox Command Async (0x%x) with no waiters", mbox); } - } else { - int fhandle = isp_parse_async(isp, (int) mbox); - isp_prt(isp, ISP_LOGDEBUG2, "Async Mbox 0x%x", mbox); - if (fhandle > 0) { - isp_fastpost_complete(isp, (u_int16_t) fhandle); - } + isp->isp_intmboxc++; + } else if (isp_parse_async(isp, mbox) < 0) { + return; } if (IS_FC(isp) || isp->isp_state != ISP_RUNSTATE) { ISP_WRITE(isp, HCCR, HCCR_CMD_CLEAR_RISC_INT); @@ -3046,7 +3047,7 @@ isp_intr(struct ispsoftc *isp, u_int16_t isr, u_int16_t sema, u_int16_t mbox) * * If we're a 2300, we can ask what hardware what it thinks. */ - if (IS_2300(isp)) { + if (IS_23XX(isp)) { optr = ISP_READ(isp, isp->isp_respoutrp); if (isp->isp_residx != optr) { isp_prt(isp, ISP_LOGWARN, "optr %x soft optr %x", @@ -3059,8 +3060,10 @@ isp_intr(struct ispsoftc *isp, u_int16_t isr, u_int16_t sema, u_int16_t mbox) /* * You *must* read the Response Queue In Pointer * prior to clearing the RISC interrupt. + * + * Debounce the 2300 if revision less than 2. */ - if (IS_2100(isp) || IS_2300(isp)) { + if (IS_2100(isp) || (IS_2300(isp) && isp->isp_revision < 2)) { i = 0; do { iptr = READ_RESPONSE_QUEUE_IN_POINTER(isp); @@ -3088,7 +3091,7 @@ isp_intr(struct ispsoftc *isp, u_int16_t isr, u_int16_t sema, u_int16_t mbox) * make sure the old interrupt went away (to avoid 'ringing' * effects), but that didn't stop this from occurring. */ - if (IS_2300(isp)) { + if (IS_23XX(isp)) { USEC_DELAY(100); iptr = READ_RESPONSE_QUEUE_IN_POINTER(isp); junk = ISP_READ(isp, BIU_R2HSTSLO); @@ -3125,6 +3128,15 @@ isp_intr(struct ispsoftc *isp, u_int16_t isr, u_int16_t sema, u_int16_t mbox) if (type == RQSTYPE_RESPONSE) { isp_get_response(isp, (ispstatusreq_t *) hp, sp); + } else if (type == RQSTYPE_RIO2) { + isp_rio2_t rio; + isp_get_rio2(isp, (isp_rio2_t *) hp, &rio); + for (i = 0; i < rio.req_header.rqs_seqno; i++) { + isp_fastpost_complete(isp, rio.req_handles[i]); + } + if (isp->isp_fpcchiwater < rio.req_header.rqs_seqno) + isp->isp_fpcchiwater = rio.req_header.rqs_seqno; + continue; } else { if (!isp_handle_other_response(isp, type, hp, &optr)) { MEMZERO(hp, QENTRY_LEN); /* PERF */ @@ -3350,12 +3362,15 @@ isp_intr(struct ispsoftc *isp, u_int16_t isr, u_int16_t sema, u_int16_t mbox) * While we're at it, reqad the requst queue out pointer. */ isp->isp_reqodx = READ_REQUEST_QUEUE_OUT_POINTER(isp); + if (isp->isp_rscchiwater < ndone) + isp->isp_rscchiwater = ndone; } isp->isp_residx = optr; for (i = 0; i < ndone; i++) { xs = complist[i]; if (xs) { + isp->isp_rsltccmplt++; isp_done(xs); } } @@ -3366,16 +3381,16 @@ isp_intr(struct ispsoftc *isp, u_int16_t isr, u_int16_t sema, u_int16_t mbox) */ static int -isp_parse_async(struct ispsoftc *isp, int mbox) +isp_parse_async(struct ispsoftc *isp, u_int16_t mbox) { int bus; - u_int16_t fast_post_handle = 0; if (IS_DUALBUS(isp)) { bus = ISP_READ(isp, OUTMAILBOX6); } else { bus = 0; } + isp_prt(isp, ISP_LOGDEBUG2, "Async Mbox 0x%x", mbox); switch (mbox) { case ASYNC_BUS_RESET: @@ -3477,10 +3492,32 @@ isp_parse_async(struct ispsoftc *isp, int mbox) isp->isp_sendmarker |= (1 << bus); break; + /* + * We can use bus, which will always be zero for FC cards, + * as a mailbox pattern accumulator to be checked below. + */ + case ASYNC_RIO5: + bus = 0x1ce; /* outgoing mailbox regs 1-3, 6-7 */ + break; + + case ASYNC_RIO4: + bus = 0x14e; /* outgoing mailbox regs 1-3, 6 */ + break; + + case ASYNC_RIO3: + bus = 0x10e; /* outgoing mailbox regs 1-3 */ + break; + + case ASYNC_RIO2: + bus = 0x106; /* outgoing mailbox regs 1-2 */ + break; + + case ASYNC_RIO1: case ASYNC_CMD_CMPLT: - fast_post_handle = ISP_READ(isp, OUTMAILBOX1); - isp_prt(isp, ISP_LOGDEBUG3, "fast post completion of %u", - fast_post_handle); + bus = 0x102; /* outgoing mailbox regs 1 */ + break; + + case ASYNC_RIO_RESP: break; case ASYNC_CTIO_DONE: @@ -3642,7 +3679,28 @@ isp_parse_async(struct ispsoftc *isp, int mbox) isp_prt(isp, ISP_LOGWARN, "Unknown Async Code 0x%x", mbox); break; } - return (fast_post_handle); + + if (bus & 0x100) { + int i, nh; + u_int16_t handles[5]; + + for (nh = 0, i = 1; i < MAX_MAILBOX; i++) { + if ((bus & (1 << i)) == 0) { + continue; + } + handles[nh++] = ISP_READ(isp, MBOX_OFF(i)); + } + for (i = 0; i < nh; i++) { + isp_fastpost_complete(isp, handles[i]); + isp_prt(isp, ISP_LOGDEBUG3, + "fast post completion of %u", handles[i]); + } + if (isp->isp_fpcchiwater < nh) + isp->isp_fpcchiwater = nh; + } else { + isp->isp_intoasync++; + } + return (0); } /* @@ -4058,6 +4116,7 @@ isp_fastpost_complete(struct ispsoftc *isp, u_int16_t fph) } if (isp->isp_nactive) isp->isp_nactive--; + isp->isp_fphccmplt++; isp_done(xs); } diff --git a/sys/dev/isp/isp_freebsd.c b/sys/dev/isp/isp_freebsd.c index dd2be3345362..593ac7d629a6 100644 --- a/sys/dev/isp/isp_freebsd.c +++ b/sys/dev/isp/isp_freebsd.c @@ -308,6 +308,41 @@ ispioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct thread *td) ISP_UNLOCK(isp); break; } + case ISP_GET_STATS: + { + isp_stats_t *sp = (isp_stats_t *) addr; + + MEMZERO(sp, sizeof (*sp)); + sp->isp_stat_version = ISP_STATS_VERSION; + sp->isp_type = isp->isp_type; + sp->isp_revision = isp->isp_revision; + ISP_LOCK(isp); + sp->isp_stats[ISP_INTCNT] = isp->isp_intcnt; + sp->isp_stats[ISP_INTBOGUS] = isp->isp_intbogus; + sp->isp_stats[ISP_INTMBOXC] = isp->isp_intmboxc; + sp->isp_stats[ISP_INGOASYNC] = isp->isp_intoasync; + sp->isp_stats[ISP_RSLTCCMPLT] = isp->isp_rsltccmplt; + sp->isp_stats[ISP_FPHCCMCPLT] = isp->isp_fphccmplt; + sp->isp_stats[ISP_RSCCHIWAT] = isp->isp_rscchiwater; + sp->isp_stats[ISP_FPCCHIWAT] = isp->isp_fpcchiwater; + ISP_UNLOCK(isp); + retval = 0; + break; + } + case ISP_CLR_STATS: + ISP_LOCK(isp); + isp->isp_intcnt = 0; + isp->isp_intbogus = 0; + isp->isp_intmboxc = 0; + isp->isp_intoasync = 0; + isp->isp_rsltccmplt = 0; + isp->isp_fphccmplt = 0; + isp->isp_rscchiwater = 0; + isp->isp_fpcchiwater = 0; + ISP_UNLOCK(isp); + retval = 0; + break; + default: break; } @@ -1664,7 +1699,7 @@ isp_watchdog(void *arg) isp_destroy_handle(isp, handle); xpt_print_path(xs->ccb_h.path); isp_prt(isp, ISP_LOGWARN, - "watchdog timeout for handle %x", handle); + "watchdog timeout for handle 0x%x", handle); XS_SETERR(xs, CAM_CMD_TIMEOUT); XS_CMD_C_WDOG(xs); isp_done(xs); diff --git a/sys/dev/isp/isp_inline.h b/sys/dev/isp/isp_inline.h index 0bb42d96230c..bc61e7818ad5 100644 --- a/sys/dev/isp/isp_inline.h +++ b/sys/dev/isp/isp_inline.h @@ -209,7 +209,7 @@ isp_fc_runstate(struct ispsoftc *isp, int tval) fcparam *fcp; int *tptr; - if (IS_SCSI(isp)) + if (IS_SCSI(isp) || isp->isp_role == ISP_ROLE_NONE) return (0); tptr = tval? &tval : NULL; @@ -269,6 +269,8 @@ isp_get_response(struct ispsoftc *, ispstatusreq_t *, ispstatusreq_t *); static INLINE void isp_get_response_x(struct ispsoftc *, ispstatus_cont_t *, ispstatus_cont_t *); static INLINE void +isp_get_rio2(struct ispsoftc *, isp_rio2_t *, isp_rio2_t *); +static INLINE void isp_put_icb(struct ispsoftc *, isp_icb_t *, isp_icb_t *); static INLINE void isp_get_pdb(struct ispsoftc *, isp_pdb_t *, isp_pdb_t *); @@ -556,6 +558,22 @@ isp_get_response_x(struct ispsoftc *isp, ispstatus_cont_t *cpsrc, } static INLINE void +isp_get_rio2(struct ispsoftc *isp, isp_rio2_t *r2src, isp_rio2_t *r2dst) +{ + int i; + isp_copy_in_hdr(isp, &r2src->req_header, &r2dst->req_header); + if (r2dst->req_header.rqs_seqno > 30) + r2dst->req_header.rqs_seqno = 30; + for (i = 0; i < r2dst->req_header.rqs_seqno; i++) { + ISP_IOXGET_16(isp, &r2src->req_handles[i], + r2dst->req_handles[i]); + } + while (i < 30) { + r2dst->req_handles[i++] = 0; + } +} + +static INLINE void isp_put_icb(struct ispsoftc *isp, isp_icb_t *Is, isp_icb_t *Id) { int i; diff --git a/sys/dev/isp/isp_ioctl.h b/sys/dev/isp/isp_ioctl.h index 5ed8a91cc49b..b52b2b538fbb 100644 --- a/sys/dev/isp/isp_ioctl.h +++ b/sys/dev/isp/isp_ioctl.h @@ -72,5 +72,32 @@ struct isp_fc_device { u_int64_t node_wwn; u_int64_t port_wwn; }; - #define ISP_FC_GETDINFO _IOWR(ISP_IOC, 4, struct isp_fc_device) + +/* + * Get/Clear Stats + */ +#define ISP_STATS_VERSION 0 +typedef struct { + uint8_t isp_stat_version; + uint8_t isp_type; /* (ro) reflects chip type */ + uint8_t isp_revision; /* (ro) reflects chip version */ + uint8_t unused1; + uint32_t unused2; + /* + * Statistics Counters + */ +#define ISP_NSTATS 16 +#define ISP_INTCNT 0 +#define ISP_INTBOGUS 1 +#define ISP_INTMBOXC 2 +#define ISP_INGOASYNC 3 +#define ISP_RSLTCCMPLT 4 +#define ISP_FPHCCMCPLT 5 +#define ISP_RSCCHIWAT 6 +#define ISP_FPCCHIWAT 7 + uint64_t isp_stats[ISP_NSTATS]; +} isp_stats_t; + +#define ISP_GET_STATS _IOR(ISP_IOC, 6, isp_stats_t) +#define ISP_CLR_STATS _IO(ISP_IOC, 7) diff --git a/sys/dev/isp/ispmbox.h b/sys/dev/isp/ispmbox.h index ac4613c39a5a..6204f46fd831 100644 --- a/sys/dev/isp/ispmbox.h +++ b/sys/dev/isp/ispmbox.h @@ -641,9 +641,11 @@ typedef struct isp_icb { #define ICBXOPT_RIO_OFF 0 #define ICBXOPT_RIO_16BIT 1 #define ICBXOPT_RIO_32BIT 2 -#define ICBXOPT_RIO_16BIT_DELAY 3 -#define ICBXOPT_RIO_32BIT_DELAY 4 +#define ICBXOPT_RIO_16BIT_IOCB 3 +#define ICBXOPT_RIO_32BIT_IOCB 4 +#define ICBZOPT_ENA_RDXFR_RDY 0x01 +#define ICBZOPT_ENA_OOF (1 << 6) /* out of order frame handling */ /* These 3 only apply to the 2300 */ #define ICBZOPT_RATE_ONEGB (MBGSD_ONEGB << 14) #define ICBZOPT_RATE_TWOGB (MBGSD_TWOGB << 14) diff --git a/sys/dev/isp/ispvar.h b/sys/dev/isp/ispvar.h index c905d8bb4fab..b0b694d70be1 100644 --- a/sys/dev/isp/ispvar.h +++ b/sys/dev/isp/ispvar.h @@ -371,6 +371,12 @@ typedef struct ispsoftc { */ u_int64_t isp_intcnt; /* total int count */ u_int64_t isp_intbogus; /* spurious int count */ + u_int64_t isp_intmboxc; /* mbox completions */ + u_int64_t isp_intoasync; /* other async */ + u_int64_t isp_rsltccmplt; /* CMDs on result q */ + u_int64_t isp_fphccmplt; /* CMDs via fastpost */ + u_int16_t isp_rscchiwater; + u_int16_t isp_fpcchiwater; /* * Volatile state @@ -508,6 +514,7 @@ typedef struct ispsoftc { #define ISP_HA_FC_2100 0x10 #define ISP_HA_FC_2200 0x20 #define ISP_HA_FC_2300 0x30 +#define ISP_HA_FC_2312 0x40 #define IS_SCSI(isp) (isp->isp_type & ISP_HA_SCSI) #define IS_1240(isp) (isp->isp_type == ISP_HA_SCSI_1240) @@ -523,7 +530,9 @@ typedef struct ispsoftc { #define IS_FC(isp) ((isp)->isp_type & ISP_HA_FC) #define IS_2100(isp) ((isp)->isp_type == ISP_HA_FC_2100) #define IS_2200(isp) ((isp)->isp_type == ISP_HA_FC_2200) -#define IS_2300(isp) ((isp)->isp_type >= ISP_HA_FC_2300) +#define IS_23XX(isp) ((isp)->isp_type >= ISP_HA_FC_2300) +#define IS_2300(isp) ((isp)->isp_type == ISP_HA_FC_2300) +#define IS_2312(isp) ((isp)->isp_type == ISP_HA_FC_2312) /* * DMA cookie macros |