diff options
author | Miod Vallat <miod@cvs.openbsd.org> | 2008-01-01 22:54:29 +0000 |
---|---|---|
committer | Miod Vallat <miod@cvs.openbsd.org> | 2008-01-01 22:54:29 +0000 |
commit | 883994669f8a59021bf6a2fb7589922767a54c9a (patch) | |
tree | 2af7a1d39fe8ed2470caed15b68fe0864d593446 | |
parent | 3b00105ccd268e1e1bda2a3c641251640f0cc791 (diff) |
Match on Cougar boards, and try to drive them like Jaguars on steroids. On
wide Cougars, use one command queue per target and disable lun support, so
that we do not overflow the board's memory; and since we are behaving as
a Jaguar, do not do tagged queuing or synchronous transfer negotiation.
Tested on two MVME328XT-2 (4220 and second revision artwork 4220) narrow
Cougar-I (but wide external connectors), but probes fail with select timeout
so far; I could not get various Motorola BUG to probe devices on these boards
either, so we're even (and maybe both my boards are toast, but I won't bet
money on this).
-rw-r--r-- | sys/arch/mvme88k/dev/vs.c | 228 | ||||
-rw-r--r-- | sys/arch/mvme88k/dev/vsreg.h | 15 | ||||
-rw-r--r-- | sys/arch/mvme88k/dev/vsvar.h | 9 |
3 files changed, 212 insertions, 40 deletions
diff --git a/sys/arch/mvme88k/dev/vs.c b/sys/arch/mvme88k/dev/vs.c index 25ce4c6852d..5fb11a37726 100644 --- a/sys/arch/mvme88k/dev/vs.c +++ b/sys/arch/mvme88k/dev/vs.c @@ -1,4 +1,4 @@ -/* $OpenBSD: vs.c,v 1.67 2008/01/01 17:21:29 miod Exp $ */ +/* $OpenBSD: vs.c,v 1.68 2008/01/01 22:54:28 miod Exp $ */ /* * Copyright (c) 2004, Miodrag Vallat. @@ -109,6 +109,7 @@ struct vs_cb *vs_find_queue(struct scsi_link *, struct vs_softc *); void vs_reset(struct vs_softc *, int); void vs_resync(struct vs_softc *); void vs_scsidone(struct vs_softc *, struct vs_cb *); +int vs_unit_value(int, int, int); static __inline__ void vs_free(struct vs_softc *, struct vs_cb *); static __inline__ void vs_clear_return_info(struct vs_softc *); @@ -121,13 +122,22 @@ vsmatch(struct device *device, void *cf, void *args) bus_space_tag_t iot = ca->ca_iot; bus_space_handle_t ioh; int rc; + u_int16_t id; if (bus_space_map(iot, ca->ca_paddr, S_SHORTIO, 0, &ioh) != 0) return 0; - rc = badaddr((vaddr_t)bus_space_vaddr(iot, ioh), 1); + rc = badaddr((vaddr_t)bus_space_vaddr(iot, ioh) + sh_CSS + CSB_TYPE, 2); if (rc == 0) { - if (bus_space_read_2(iot, ioh, sh_CSS + CSB_TYPE) != JAGUAR) + id = bus_space_read_2(iot, ioh, sh_CSS + CSB_TYPE); + if (id != JAGUAR && id != COUGAR) rc = 1; + /* + * Note that this will reject Cougar boards configured with + * less than 2KB of short I/O memory. + * Is it worth checking for a Cougar signature at lower + * addresses, knowing that we can't really work unless + * the board is jumped to enable the whole 2KB? + */ } bus_space_unmap(iot, ioh, S_SHORTIO); @@ -164,6 +174,7 @@ vsattach(struct device *parent, struct device *self, void *args) return; } + sc->sc_bid = csb_read(2, CSB_TYPE); sc->sc_ipl = ca->ca_ipl; sc->sc_nvec = ca->ca_vec; sc->sc_evec = evec; @@ -194,13 +205,12 @@ vsattach(struct device *parent, struct device *self, void *args) sc_link = &sc->sc_link[bus]; sc_link->adapter = &vs_scsiswitch; - sc_link->adapter_buswidth = 8; + sc_link->adapter_buswidth = sc->sc_width[bus]; sc_link->adapter_softc = sc; sc_link->adapter_target = sc->sc_id[bus]; sc_link->device = &vs_scsidev; -#if 0 - sc_link->luns = 1; -#endif + if (sc->sc_bid != JAGUAR) + sc_link->luns = 1; sc_link->openings = 1; if (bus != 0) sc_link->flags = SDEV_2NDBUS; @@ -222,6 +232,13 @@ vsattach(struct device *parent, struct device *self, void *args) if (sc->sc_id[bus] < 0) continue; + if (sc->sc_width[bus] == 0) { + printf("%s: daughterboard disabled, " + "not enough on-board memory\n", + sc->sc_dev.dv_xname); + continue; + } + bzero(&saa, sizeof(saa)); saa.saa_sc_link = &sc->sc_link[bus]; @@ -242,7 +259,7 @@ vs_print_addr(struct vs_softc *sc, struct scsi_xfer *xs) sc_print_addr(xs->sc_link); /* print bus number too if appropriate */ - if (sc->sc_id[1] >= 0) + if (sc->sc_width[1] >= 0) printf("(bus %d) ", !!(xs->sc_link->flags & SDEV_2NDBUS)); } @@ -295,6 +312,9 @@ vs_poll(struct vs_softc *sc, struct vs_cb *cb) xs->error = XS_SELTIMEOUT; xs->status = -1; xs->flags |= ITSDONE; +#ifdef VS_DEBUG + printf("%s: polled command timed out\n", __func__); +#endif vs_free(sc, cb); scsi_done(xs); } else @@ -324,7 +344,7 @@ thaw_all_queues(struct vs_softc *sc) { int i; - for (i = 1; i < NUM_WQ; i++) + for (i = 1; i <= sc->sc_nwq; i++) thaw_queue(sc, i); } @@ -339,6 +359,10 @@ vs_scsidone(struct vs_softc *sc, struct vs_cb *cb) xs->resid = xs->datalen - len; error = vs_read(2, sh_RET_IOPB + IOPB_STATUS); +#ifdef VS_DEBUG + printf("%s: queue %d, len %u (resid %d) error %d\n", + __func__, cb->cb_q, len, xs->resid, error); +#endif if ((error & 0xff) == SCSI_SELECTION_TO) { xs->error = XS_SELTIMEOUT; xs->status = -1; @@ -416,7 +440,7 @@ vs_scsicmd(struct scsi_xfer *xs) /* * We should only provide the iopb len if the controller is not * able to compute it from the SCSI command group. - * Note that it has no knowledge of group 2. + * Note that Jaguar has no knowledge of group 2. */ switch ((xs->cmd->opcode) >> 5) { case 0: @@ -424,17 +448,31 @@ vs_scsicmd(struct scsi_xfer *xs) case 5: iopb_len = 0; break; + case 2: + if (sc->sc_bid == COUGAR) + iopb_len = 0; + else + /* FALLTHROUGH */ default: iopb_len = IOPB_SHORT_SIZE + xs->cmdlen; break; } +#ifdef VS_DEBUG + printf("%s: sending SCSI command %02x (length %d, iopb length %d) on queue %d\n", + __func__, xs->cmd->opcode, xs->cmdlen, iopb_len, queue); +#endif bus_space_write_region_1(sc->sc_iot, sc->sc_ioh, iopb + IOPB_SCSI_DATA, (u_int8_t *)xs->cmd, xs->cmdlen); vs_write(2, iopb + IOPB_CMD, IOPB_PASSTHROUGH); vs_write(2, iopb + IOPB_UNIT, - IOPB_UNIT_VALUE(!!(slp->flags & SDEV_2NDBUS), slp->target, slp->lun)); + vs_unit_value(slp->flags & SDEV_2NDBUS, slp->target, slp->lun)); +#ifdef VS_DEBUG + printf("%s: target %d lun %d encoded as %04x\n", + __func__, slp->target, slp->lun, (u_int) + vs_unit_value(slp->flags & SDEV_2NDBUS, slp->target, slp->lun)); +#endif vs_write(1, iopb + IOPB_NVCT, sc->sc_nvec); vs_write(1, iopb + IOPB_EVCT, sc->sc_evec); @@ -494,6 +532,9 @@ vs_chksense(struct scsi_xfer *xs) struct vs_softc *sc = slp->adapter_softc; struct scsi_sense *ss; +#ifdef VS_DEBUG + printf("%s: target %d\n", slp->target); +#endif /* ack and clear the error */ if (CRSW & M_CRSW_ER) CRB_CLR_ER; @@ -521,7 +562,7 @@ vs_chksense(struct scsi_xfer *xs) mce_iopb_write(4, IOPB_BUFF, kvtop((vaddr_t)&xs->sense)); mce_iopb_write(4, IOPB_LENGTH, sizeof(struct scsi_sense_data)); mce_iopb_write(2, IOPB_UNIT, - IOPB_UNIT_VALUE(!!(slp->flags & SDEV_2NDBUS), slp->target, slp->lun)); + vs_unit_value(slp->flags & SDEV_2NDBUS, slp->target, slp->lun)); vs_bzero(sh_MCE, CQE_SIZE); mce_write(2, CQE_IOPB_ADDR, sh_MCE_IOPB); @@ -564,10 +605,8 @@ vs_getcqe(struct vs_softc *sc, bus_addr_t *cqep, bus_addr_t *iopbp) int vs_initialize(struct vs_softc *sc) { - int i, msr, dbid; - - for (i = 0; i < NUM_WQ; i++) - sc->sc_cb[i].cb_q = i; + int i, msr, id; + u_int targets; /* * Reset the board, and wait for it to get ready. @@ -593,10 +632,32 @@ vs_initialize(struct vs_softc *sc) delay(1000); } + /* describe the board */ + switch (sc->sc_bid) { + default: + case JAGUAR: + printf("Jaguar, "); + break; + case COUGAR: + id = csb_read(1, CSB_EXTID); + switch (id) { + case 0x00: + printf("Cougar, "); + break; + case 0x02: + printf("Cougar II, "); + break; + default: + printf("unknown Cougar %02x, ", id); + break; + } + break; + } + /* initialize channels id */ sc->sc_id[0] = csb_read(1, CSB_PID); sc->sc_id[1] = -1; - switch (dbid = csb_read(1, CSB_DBID)) { + switch (id = csb_read(1, CSB_DBID)) { case DBID_SCSI2: case DBID_SCSI: #if 0 @@ -610,7 +671,65 @@ vs_initialize(struct vs_softc *sc) case DBID_NONE: break; default: - printf("unknown daughterboard id %x, ", dbid); + printf("unknown daughterboard id %x, ", id); + break; + } + + /* + * On cougar boards, find how many work queues we can use, + * and whether we are on wide or narrow buses. + */ + switch (sc->sc_bid) { + case COUGAR: + sc->sc_nwq = csb_read(2, CSB_NWQ); + /* + * Despite what the documentation says, this value is not + * always provided. If it is invalid, decide on the number + * of available work queues from the memory size, as the + * firmware does. + */ +#ifdef VS_DEBUG + printf("%s: controller reports %d work queues\n", + __func__, sc->sc_nwq); +#endif + if (sc->sc_nwq != 0x0f && sc->sc_nwq != 0xff) { + if (csb_read(2, CSB_BSIZE) >= 0x0100) + sc->sc_nwq = 0xff; /* >= 256KB, 255 WQ */ + else + sc->sc_nwq = 0x0f; /* < 256KB, 15 WQ */ + } +#ifdef VS_DEBUG + printf("%s: driver deducts %d work queues\n", + __func__, sc->sc_nwq); +#endif + if (sc->sc_nwq > NUM_WQ) + sc->sc_nwq = NUM_WQ; + + sc->sc_width[0] = csb_read(1, CSB_PFECID) & 0x02 ? 16 : 8; + targets = sc->sc_width[0] - 1; + if (sc->sc_id[1] >= 0) { + sc->sc_width[1] = + csb_read(1, CSB_SFECID) & 0x02 ? 16 : 8; + targets += sc->sc_width[1] - 1; + } else + sc->sc_width[1] = 0; + + if (sc->sc_nwq > targets) + sc->sc_nwq = targets; + else { + /* + * We can't drive the daugther board if there is not + * enough on-board memory for all the work queues. + * XXX This might work by moving everything off-board? + */ + if (sc->sc_nwq < targets) + sc->sc_width[1] = 0; + } + break; + default: + case JAGUAR: + sc->sc_nwq = JAGUAR_MAX_WQ; + sc->sc_width[0] = sc->sc_width[1] = 8; break; } @@ -622,8 +741,8 @@ vs_initialize(struct vs_softc *sc) cib_write(2, CIB_BURST, 0); cib_write(2, CIB_NVECT, (sc->sc_ipl << 8) | sc->sc_nvec); cib_write(2, CIB_EVECT, (sc->sc_ipl << 8) | sc->sc_evec); - cib_write(2, CIB_PID, 0x08); /* XXX default */ - cib_write(2, CIB_SID, 0x08); + cib_write(2, CIB_PID, 0x08); /* use default */ + cib_write(2, CIB_SID, 0x08); /* use default */ cib_write(2, CIB_CRBO, sh_CRB); cib_write(4, CIB_SELECT, SELECTION_TIMEOUT); cib_write(4, CIB_WQTIMO, 4); @@ -655,7 +774,14 @@ vs_initialize(struct vs_softc *sc) do_vspoll(sc, NULL, 1); /* initialize work queues */ - for (i = 1; i < NUM_WQ; i++) { +#ifdef VS_DEBUG + printf("%s: initializing %d work queues\n", + __func__, sc->sc_nwq); +#endif + for (i = 0; i <= sc->sc_nwq; i++) + sc->sc_cb[i].cb_q = i; + + for (i = 1; i <= sc->sc_nwq; i++) { /* Wait until we can use the command queue entry. */ while (mce_read(2, CQE_QECR) & M_QECR_GO) ; @@ -668,8 +794,13 @@ vs_initialize(struct vs_softc *sc) mce_iopb_write(2, WQCF_ILVL, 0 /* sc->sc_ipl */); mce_iopb_write(2, WQCF_WORKQ, i); mce_iopb_write(2, WQCF_WOPT, M_WOPT_FE | M_WOPT_IWQ); - mce_iopb_write(2, WQCF_SLOTS, JAGUAR_MAX_Q_SIZ); + if (sc->sc_bid == JAGUAR) + mce_iopb_write(2, WQCF_SLOTS, JAGUAR_MAX_Q_SIZ); mce_iopb_write(4, WQCF_CMDTO, 4); /* 1 second */ + if (sc->sc_bid != JAGUAR) + mce_iopb_write(2, WQCF_UNIT, + vs_unit_value(i > sc->sc_width[0], + i - sc->sc_width[0], 0)); vs_bzero(sh_MCE, CQE_SIZE); mce_write(2, CQE_IOPB_ADDR, sh_MCE_IOPB); @@ -704,10 +835,10 @@ vs_resync(struct vs_softc *sc) int bus, target; for (bus = 0; bus < 2; bus++) { - if (sc->sc_id[bus] < 0) + if (sc->sc_id[bus] < 0 || sc->sc_width[bus] == 0) break; - for (target = 0; target < 8; target++) { + for (target = 0; target < sc->sc_width[bus]; target++) { if (target == sc->sc_id[bus]) continue; @@ -722,7 +853,7 @@ vs_resync(struct vs_softc *sc) mce_iopb_write(1, DRCF_EVCT, sc->sc_evec); mce_iopb_write(2, DRCF_ILVL, 0); mce_iopb_write(2, DRCF_UNIT, - IOPB_UNIT_VALUE(bus, target, 0)); + vs_unit_value(bus, target, 0)); vs_bzero(sh_MCE, CQE_SIZE); mce_write(2, CQE_IOPB_ADDR, sh_MCE_IOPB); @@ -820,8 +951,17 @@ vs_nintr(void *vsc) * to point to address 0. But then, we should have caught * the controller error above. */ - if (cb != NULL) + if (cb != NULL) { +#ifdef VS_DEBUG + printf("%s: interrupt for queue %d\n", __func__, cb->cb_q); +#endif vs_scsidone(sc, cb); + } else { +#ifdef VS_DEBUG + printf("%s: normal interrupt but no related command???\n", + __func__); +#endif + } /* ack the interrupt */ if (CRSW & M_CRSW_ER) @@ -852,6 +992,10 @@ vs_eintr(void *vsc) cb = (struct vs_cb *)crb_read(4, CRB_CTAG); xs = cb != NULL ? cb->cb_xs : NULL; +#ifdef VS_DEBUG + printf("%s: error interrupt, crsw %04x, error %d, queue %d\n", + __func__, (u_int)crsw, ecode, cb ? cb->cb_q : -1); +#endif vs_print_addr(sc, xs); if (crsw & M_CRSW_RST) { @@ -921,15 +1065,15 @@ vs_find_queue(struct scsi_link *sl, struct vs_softc *sc) u_int q; /* - * Map the target number (0-7) to the 1-7 range, target 0 picks - * the host adapter target number (since host adapter commands - * are issued on queue #0). + * Map the target number (0-7/15) to the 1-7/15 range, target 0 + * picks the host adapter target number (since host adapter + * commands are issued on queue #0). */ q = sl->target; if (q == 0) q = sl->adapter_target; if (sl->flags & SDEV_2NDBUS) - q += 7; /* map to queues 8-14 */ + q += sc->sc_width[0] - 1; /* map to 8-14 or 16-30 */ if ((cb = &sc->sc_cb[q])->cb_xs == NULL) return (cb); @@ -938,6 +1082,30 @@ vs_find_queue(struct scsi_link *sl, struct vs_softc *sc) } /* + * Encode a specific target. + */ +int +vs_unit_value(int bus, int tgt, int lun) +{ + int unit = 0; + + if (bus != 0) + unit |= M_UNIT_BUS; /* secondary bus */ + + if (tgt > 7 || lun > 7) { + /* extended addressing (for Cougar II-Wide only) */ + unit |= M_UNIT_EXT; + unit |= (lun & 0x3f) << 8; + unit |= (tgt & 0x0f) << 0; + } else { + unit |= lun << 3; + unit |= tgt << 0; + } + + return (unit); +} + +/* * Useful functions for scatter/gather list */ diff --git a/sys/arch/mvme88k/dev/vsreg.h b/sys/arch/mvme88k/dev/vsreg.h index d0ac33613e5..57bc800a19c 100644 --- a/sys/arch/mvme88k/dev/vsreg.h +++ b/sys/arch/mvme88k/dev/vsreg.h @@ -1,4 +1,4 @@ -/* $OpenBSD: vsreg.h,v 1.14 2006/12/21 02:28:47 krw Exp $ */ +/* $OpenBSD: vsreg.h,v 1.15 2008/01/01 22:54:28 miod Exp $ */ /* * Copyright (c) 2004, Miodrag Vallat. * Copyright (c) 1999 Steve Murphree, Jr. @@ -41,7 +41,8 @@ #define JAGUAR_MIN_Q_SIZ 2 #define JAGUAR_MAX_CTLR_CMDS 80 /* Interphase says so */ -#define JAGUAR_MAX_Q_SIZ (JAGUAR_MAX_CTLR_CMDS / NUM_WQ) +#define JAGUAR_MAX_Q_SIZ (JAGUAR_MAX_CTLR_CMDS / JAGUAR_MAX_WQ) +#define JAGUAR_MAX_WQ (2 * 7) /* * COUGAR specific device limits @@ -56,7 +57,7 @@ #define NUM_CQE 10 #define NUM_IOPB NUM_CQE -#define NUM_WQ 15 +#define NUM_WQ (2 * 15) /* * Master Control Status Block (MCSB) @@ -186,15 +187,17 @@ * Configuration Status Block (CSB) */ -#define CSB_TYPE 0x000000 /* jaguar/cougar */ +#define CSB_TYPE 0x000000 /* board ID */ #define COUGAR 0x4220 #define JAGUAR 0x0000 +#define CSB_EXTID 0x000002 /* cougar extended ID */ #define CSB_PCODE 0x000003 /* product code */ #define CSB_PVAR 0x000009 /* product variation */ #define CSB_FREV 0x00000d /* firmware revision level */ #define CSB_FDATE 0x000012 /* firmware release date */ #define CSB_SSIZE 0x00001a /* system memory size in KB */ #define CSB_BSIZE 0x00001c /* buffer memory size in KB */ +#define CSB_NWQ 0x00001e /* number of work queues (C) */ #define CSB_PFECID 0x000020 /* primary bus FEC id */ #define CSB_SFECID 0x000021 /* secondary bus FEC id */ #define CSB_PID 0x000022 /* primary bus id */ @@ -268,6 +271,7 @@ #define WQCF_WORKQ 0x00001c /* work queue number */ #define WQCF_WOPT 0x00001e /* work queue options */ #define WQCF_SLOTS 0x000020 /* # of slots in work queues */ +#define WQCF_UNIT 0x000022 /* unit address (C) */ #define WQCF_CMDTO 0x000024 /* command timeout */ /* @@ -342,9 +346,6 @@ #define CNTR_ISSUE_ABORT 0x4e /* abort has been issued */ #define CNTR_DOWNLOAD_FIRMWARE 0x4f /* download firmware (COUGAR) */ -#define IOPB_UNIT_VALUE(bus, target, lun) \ - (((bus) << 6) | ((lun) << 3) | (target & 7)) - /* * Memory types */ diff --git a/sys/arch/mvme88k/dev/vsvar.h b/sys/arch/mvme88k/dev/vsvar.h index b7e91c62b01..36d947f25fd 100644 --- a/sys/arch/mvme88k/dev/vsvar.h +++ b/sys/arch/mvme88k/dev/vsvar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: vsvar.h,v 1.18 2005/12/27 21:38:13 miod Exp $ */ +/* $OpenBSD: vsvar.h,v 1.19 2008/01/01 22:54:28 miod Exp $ */ /* * Copyright (c) 2004, Miodrag Vallat. * Copyright (c) 1999 Steve Murphree, Jr. @@ -92,6 +92,7 @@ struct vs_cb { struct vs_softc { struct device sc_dev; + int sc_bid; /* board id */ paddr_t sc_paddr; bus_space_tag_t sc_iot; bus_space_handle_t sc_ioh; @@ -99,9 +100,11 @@ struct vs_softc { char sc_intrname_e[16 + 4]; int sc_ipl; int sc_evec, sc_nvec; - int sc_id[2]; + u_int sc_nwq; /* number of work queues */ + int sc_id[2]; /* host id per bus */ + int sc_width[2]; /* number of targets per bus */ struct scsi_link sc_link[2]; - struct vs_cb sc_cb[NUM_WQ]; + struct vs_cb sc_cb[1 + NUM_WQ]; }; /* Access macros */ |