diff options
-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 */ |