Index: sys/dev/ic/osiop.c =================================================================== RCS file: /cvsroot/syssrc/sys/dev/ic/osiop.c,v retrieving revision 1.9 diff -u -r1.9 osiop.c --- sys/dev/ic/osiop.c 2002/04/05 18:27:54 1.9 +++ sys/dev/ic/osiop.c 2002/07/10 16:14:16 @@ -98,10 +98,14 @@ #include #include +#include #include #include +/* 53C700 script */ +#include + /* 53C710 script */ #include @@ -116,6 +120,7 @@ void osiop_init(struct osiop_softc *); void osiop_reset(struct osiop_softc *); void osiop_resetbus(struct osiop_softc *); +void osiop_write_dsa(struct osiop_softc *, struct osiop_acb *); void osiop_start(struct osiop_softc *); int osiop_checkintr(struct osiop_softc *, u_int8_t, u_int8_t, u_int8_t, int *); void osiop_select(struct osiop_softc *); @@ -191,6 +196,8 @@ #define OSIOP_TRACE(a,b,c,d) #endif +#define SIZEOF_ARRAY(a) (sizeof(a) / sizeof(a[0])) + void osiop_attach(sc) struct osiop_softc *sc; @@ -230,8 +237,68 @@ /* * Copy and sync script + */ + switch(sc->sc_rev) { + case OSIOP_VARIANT_NCR53C700: + + /* Copy the raw script. */ + memcpy(sc->sc_script, oosiop_script, sizeof(oosiop_script)); + + /* + * The 53c700 can't do relative jumps, so we have to + * adjust all script offsets used in the script. + */ + for(i = 0; i < SIZEOF_ARRAY(LABELPATCHES); i++) + sc->sc_script[LABELPATCHES[i]] += sc->sc_scrdma->dm_segs[0].ds_addr; + + /* + * Certain block transfer instructions in our script + * always involve the same count of bytes; these + * correspond to the constant .count values set up + * in the ACB data structure below. For example, + * all data structures always have a status.count value + * of one. We take advantage of these constant values + * to fix up all count values in instructions that we + * can now, leaving us only to fix up their address + * values at transfer time. + * + * We can't do this all of the time - for example, + * the counts for command and scatter/gather need + * to be set at script-runtime. + * + * Note that the script offsets we have are for + * data pointers only. I didn't bother creating + * externals for the data counts, because count + * and pointer are always used together. The count + * immediately precedes the pointer in the script. + * We also take advantage of the fact that the + * count fields in the unfixed script are zero. + */ +#define FIXED_COUNT(name, count) \ + for(i = 0; i < SIZEOF_ARRAY(name); i++) \ + sc->sc_script[name[i] - 1] |= (count) + FIXED_COUNT(E_ds_Status_Used, 1); + FIXED_COUNT(E_ds_Msg_Used, 1); + FIXED_COUNT(E_ds_MsgIn_Used, 1); + FIXED_COUNT(E_ds_ExtMsg_Used, 1); + FIXED_COUNT(E_ds_SyncMsg_Used, 3); +#undef FIXED_COUNT + break; + + case OSIOP_VARIANT_NCR53C710: + memcpy(sc->sc_script, osiop_script, sizeof(osiop_script)); + break; + } + + /* + * If the byte order of the chip is not the same as + * the byte order of the CPU, we need to byteswap + * the script. */ - memcpy(sc->sc_script, osiop_script, sizeof(osiop_script)); + if (sc->sc_byteorder != OSIOP_BYTEORDER_NATIVE) { + for(i = 0; i < SIZEOF_ARRAY(osiop_script); i++) + sc->sc_script[i] = bswap32(sc->sc_script[i]); + } bus_dmamap_sync(sc->sc_dmat, sc->sc_scrdma, 0, sizeof(osiop_script), BUS_DMASYNC_PREWRITE); @@ -324,8 +391,19 @@ acb++; } - printf(": NCR53C710 rev %d, %dMHz, SCSI ID %d\n", - osiop_read_1(sc, OSIOP_CTEST8) >> 4, sc->sc_clock_freq, sc->sc_id); + printf(": "); + switch(sc->sc_rev) { + case OSIOP_VARIANT_NCR53C700: + printf("NCR53C700 rev %d", + osiop_read_1(sc, OSIOP_CTEST7) >> 4); + break; + case OSIOP_VARIANT_NCR53C710: + printf("NCR53C710 rev %d", + osiop_read_1(sc, OSIOP_CTEST8) >> 4); + break; + } + printf(", %dMHz, SCSI ID %d\n", + sc->sc_clock_freq, sc->sc_id); /* * Initialize all @@ -548,6 +626,7 @@ i--; } sstat0 = osiop_read_1(sc, OSIOP_SSTAT0); + delay(25); dstat = osiop_read_1(sc, OSIOP_DSTAT); if (osiop_checkintr(sc, istat, dstat, sstat0, &status)) { if (acb != sc->sc_nexus) @@ -832,6 +911,8 @@ struct osiop_acb *acb; int i, s; u_int8_t stat; + bus_size_t rst_reg, dmode_reg; + u_int8_t rst_bit; #ifdef OSIOP_DEBUG printf("%s: resetting chip\n", sc->sc_dev.dv_xname); @@ -850,11 +931,23 @@ osiop_write_1(sc, OSIOP_ISTAT, osiop_read_1(sc, OSIOP_ISTAT) | OSIOP_ISTAT_ABRT); /* reset chip */ - osiop_write_1(sc, OSIOP_ISTAT, - osiop_read_1(sc, OSIOP_ISTAT) | OSIOP_ISTAT_RST); + switch(sc->sc_rev) { + case OSIOP_VARIANT_NCR53C700: + rst_reg = OSIOP_DCNTL; + rst_bit = OSIOP_DCNTL_RST; + dmode_reg = OSIOP_DMODE_53C700; + break; + case OSIOP_VARIANT_NCR53C710: + rst_reg = OSIOP_ISTAT; + rst_bit = OSIOP_ISTAT_RST; + dmode_reg = OSIOP_DMODE_53C710; + break; + } + osiop_write_1(sc, rst_reg, + osiop_read_1(sc, rst_reg) | rst_bit); delay(100); - osiop_write_1(sc, OSIOP_ISTAT, - osiop_read_1(sc, OSIOP_ISTAT) & ~OSIOP_ISTAT_RST); + osiop_write_1(sc, rst_reg, + osiop_read_1(sc, rst_reg) & ~rst_bit); delay(100); /* @@ -864,14 +957,15 @@ OSIOP_ARB_FULL | OSIOP_SCNTL0_EPC | OSIOP_SCNTL0_EPG); osiop_write_1(sc, OSIOP_SCNTL1, OSIOP_SCNTL1_ESR); osiop_write_1(sc, OSIOP_DCNTL, sc->sc_dcntl); - osiop_write_1(sc, OSIOP_DMODE, OSIOP_DMODE_BL4); + osiop_write_1(sc, dmode_reg, OSIOP_DMODE_BL4); /* don't enable interrupts yet */ osiop_write_1(sc, OSIOP_SIEN, 0x00); osiop_write_1(sc, OSIOP_DIEN, 0x00); osiop_write_1(sc, OSIOP_SCID, OSIOP_SCID_VALUE(sc->sc_id)); osiop_write_1(sc, OSIOP_DWT, 0x00); - osiop_write_1(sc, OSIOP_CTEST0, osiop_read_1(sc, OSIOP_CTEST0) - | OSIOP_CTEST0_BTD | OSIOP_CTEST0_EAN); + if (sc->sc_rev != OSIOP_VARIANT_NCR53C700) + osiop_write_1(sc, OSIOP_CTEST0, osiop_read_1(sc, OSIOP_CTEST0) + | OSIOP_CTEST0_BTD | OSIOP_CTEST0_EAN); osiop_write_1(sc, OSIOP_CTEST7, osiop_read_1(sc, OSIOP_CTEST7) | sc->sc_ctest7); @@ -885,6 +979,7 @@ stat = osiop_read_1(sc, OSIOP_ISTAT); if (stat & OSIOP_ISTAT_SIP) osiop_read_1(sc, OSIOP_SSTAT0); + delay(25); if (stat & OSIOP_ISTAT_DIP) osiop_read_1(sc, OSIOP_DSTAT); @@ -912,8 +1007,10 @@ /* enable SCSI and DMA interrupts */ sc->sc_sien = OSIOP_SIEN_M_A | OSIOP_SIEN_STO | /*OSIOP_SIEN_SEL |*/ OSIOP_SIEN_SGE | OSIOP_SIEN_UDC | OSIOP_SIEN_RST | OSIOP_SIEN_PAR; - sc->sc_dien = OSIOP_DIEN_BF | OSIOP_DIEN_ABRT | OSIOP_DIEN_SIR | + sc->sc_dien = OSIOP_DIEN_ABRT | OSIOP_DIEN_SIR | /*OSIOP_DIEN_WTD |*/ OSIOP_DIEN_IID; + if (sc->sc_rev != OSIOP_VARIANT_NCR53C700) + sc->sc_dien |= OSIOP_DIEN_BF; osiop_write_1(sc, OSIOP_SIEN, sc->sc_sien); osiop_write_1(sc, OSIOP_DIEN, sc->sc_dien); } @@ -932,6 +1029,90 @@ } /* + * On the 53c710, this loads the DSA with the address of the + * data structure we'd like our script to use. On the 53c700, + * since it doesn't have a DSA, we have to stuff the values + * in the data structure directly into the script. + */ + +void +osiop_write_dsa(sc, acb) + struct osiop_softc *sc; + struct osiop_acb *acb; +{ + int i; + int off; + u_int32_t inst; + int need_swap; + struct osiop_ds *ds = acb->ds; + + switch(sc->sc_rev) { + case OSIOP_VARIANT_NCR53C700: + + need_swap = (sc->sc_byteorder != OSIOP_BYTEORDER_NATIVE); + + for(i = 0; i < SIZEOF_ARRAY(E_ds_Device_Used); i++) { + off = E_ds_Device_Used[i] - 1; + inst = oosiop_script[off] | (ds->scsi_addr & 0x00ff0000); + sc->sc_script[off] = (need_swap ? bswap32(inst) : inst); + } + + /* Some macros for clarity. */ +#define FOREACH_OFF(sym, body) do { \ + for(i = 0; i < SIZEOF_ARRAY(sym); i++) { off = sym[i]; body; } \ +} while(/* CONSTCOND */ 0) +#define STUFF_ADDR(what) \ + inst = ds->what.addr; \ + sc->sc_script[off] = (need_swap ? bswap32(inst) : inst) +#define STUFF_FULL(what) \ + inst = ds->what.addr; \ + sc->sc_script[off--] = (need_swap ? bswap32(inst) : inst); \ + inst = oosiop_script[off] | ds->what.count; \ + sc->sc_script[off] = (need_swap ? bswap32(inst) : inst) + + FOREACH_OFF(E_ds_MsgOut_Used, STUFF_FULL(id)); + FOREACH_OFF(E_ds_Cmd_Used, STUFF_FULL(cmd)); + FOREACH_OFF(E_ds_Status_Used, STUFF_ADDR(status)); + FOREACH_OFF(E_ds_Msg_Used, STUFF_ADDR(msg)); + FOREACH_OFF(E_ds_MsgIn_Used, STUFF_ADDR(msgin)); + FOREACH_OFF(E_ds_ExtMsg_Used, STUFF_ADDR(extmsg)); + FOREACH_OFF(E_ds_SyncMsg_Used, STUFF_ADDR(synmsg)); + + /* + * The DMA scatter/gather buffers are handled + * differently. To avoid a bunch of external + * symbols in the script (OSIOP_NSG of them) + * there is only E_ds_Data1_Used, with exactly + * OSIOP_NSG * 2 references. We rely on the + * scripts compiler laying out the _Used + * array such that _Used[0] and _Used[OSIOP_NSG] + * are really ds_Data1, [1] and [OSIOP_NSG + 1] + * are really ds_Data2, etc. + */ + for(i = 0; i < OSIOP_NSG; i++) { + off = E_ds_Data1_Used[i]; + STUFF_FULL(data[i]); + off = E_ds_Data1_Used[OSIOP_NSG + i]; + STUFF_FULL(data[i]); + } + +#undef FOREACH_OFF +#undef STUFF_COUNT +#undef STUFF_FULL + + /* Resync the script. */ + bus_dmamap_sync(sc->sc_dmat, sc->sc_scrdma, + 0, sizeof(oosiop_script), BUS_DMASYNC_PREWRITE); + + break; + case OSIOP_VARIANT_NCR53C710: + osiop_write_4(sc, OSIOP_DSA, + sc->sc_dsdma->dm_segs[0].ds_addr + acb->dsoffset); + break; + } +} + +/* * Setup Data Storage for 53C710 and start SCRIPTS processing */ @@ -956,7 +1137,8 @@ printf("istat %02x sfbr %02x lcrc %02x sien %02x dien %02x\n", osiop_read_1(sc, OSIOP_ISTAT), osiop_read_1(sc, OSIOP_SFBR), - osiop_read_1(sc, OSIOP_LCRC), + (sc->sc_rev == OSIOP_VARIANT_NCR53C700 + ? 0 : osiop_read_1(sc, OSIOP_LCRC)), osiop_read_1(sc, OSIOP_SIEN), osiop_read_1(sc, OSIOP_DIEN)); #ifdef DDB @@ -1072,14 +1254,14 @@ sc->sc_dev.dv_xname); osiop_write_4(sc, OSIOP_TEMP, 0); osiop_write_1(sc, OSIOP_SBCL, ti->sbcl); - osiop_write_4(sc, OSIOP_DSA, - dsdma->dm_segs[0].ds_addr + acb->dsoffset); + osiop_write_dsa(sc, acb); osiop_write_4(sc, OSIOP_DSP, sc->sc_scrdma->dm_segs[0].ds_addr + Ent_scripts); OSIOP_TRACE('s', 1, 0, 0); } else { if ((osiop_read_1(sc, OSIOP_ISTAT) & OSIOP_ISTAT_CON) == 0) { - osiop_write_1(sc, OSIOP_ISTAT, OSIOP_ISTAT_SIGP); + if (sc->sc_rev != OSIOP_VARIANT_NCR53C700) + osiop_write_1(sc, OSIOP_ISTAT, OSIOP_ISTAT_SIGP); OSIOP_TRACE('s', 2, 0, 0); } else { OSIOP_TRACE('s', 3, @@ -1109,17 +1291,29 @@ bus_addr_t scraddr = sc->sc_scrdma->dm_segs[0].ds_addr; int target = 0; int dfifo, dbc, intcode, sstat1; + bus_size_t clf_reg; + u_int8_t clf_bit; + u_int8_t dfifo_bo; dfifo = osiop_read_1(sc, OSIOP_DFIFO); dbc = osiop_read_4(sc, OSIOP_DBC) & 0x00ffffff; sstat1 = osiop_read_1(sc, OSIOP_SSTAT1); - osiop_write_1(sc, OSIOP_CTEST8, - osiop_read_1(sc, OSIOP_CTEST8) | OSIOP_CTEST8_CLF); + if (sc->sc_rev == OSIOP_VARIANT_NCR53C700) { + clf_reg = OSIOP_DFIFO; + clf_bit = OSIOP_DFIFO_CLF; + dfifo_bo = OSIOP_DFIFO_BO_53C700; + } else { + clf_reg = OSIOP_CTEST8; + clf_bit = OSIOP_CTEST8_CLF; + dfifo_bo = OSIOP_DFIFO_BO_53C710; + } + osiop_write_1(sc, clf_reg, + osiop_read_1(sc, clf_reg) | clf_bit); while ((osiop_read_1(sc, OSIOP_CTEST1) & OSIOP_CTEST1_FMT) != OSIOP_CTEST1_FMT) ; - osiop_write_1(sc, OSIOP_CTEST8, - osiop_read_1(sc, OSIOP_CTEST8) & ~OSIOP_CTEST8_CLF); + osiop_write_1(sc, clf_reg, + osiop_read_1(sc, clf_reg) & ~clf_bit); intcode = osiop_read_4(sc, OSIOP_DSPS); #ifdef OSIOP_DEBUG osiopints++; @@ -1156,7 +1350,8 @@ /* Normal completion status, or check condition */ struct osiop_tinfo *ti; #ifdef OSIOP_DEBUG - if (osiop_read_4(sc, OSIOP_DSA) != + if (sc->sc_rev != OSIOP_VARIANT_NCR53C700 && + osiop_read_4(sc, OSIOP_DSA) != dsdma->dm_segs[0].ds_addr + acb->dsoffset) { printf("osiop: invalid dsa: %x %lx\n", osiop_read_4(sc, OSIOP_DSA), @@ -1248,7 +1443,7 @@ sc->sc_dev.dv_xname); #endif if (acb->datalen > 0) { - int adjust = (dfifo - (dbc & 0x7f)) & 0x7f; + int adjust = (dfifo - (dbc & dfifo_bo)) & dfifo_bo; if (sstat1 & OSIOP_SSTAT1_ORF) adjust++; if (sstat1 & OSIOP_SSTAT1_OLF) @@ -1519,7 +1714,10 @@ return (0); } if (dstat & OSIOP_DSTAT_SIR && intcode == A_int_reconnect) { - int reselid = ffs(osiop_read_4(sc, OSIOP_SCRATCH) & 0xff) - 1; + /* XXX this needs to be addressed for the 53c700 */ + int reselid = ffs((sc->sc_rev == OSIOP_VARIANT_NCR53C700 ? + osiop_read_1(sc, OSIOP_SFBR) : + osiop_read_4(sc, OSIOP_SCRATCH) & 0xff)) - 1; int reselun = osiop_read_1(sc, OSIOP_SFBR) & 0x07; #ifdef OSIOP_DEBUG u_int8_t resmsg; @@ -1565,8 +1763,7 @@ sc->sc_nexus = acb; sc->sc_flags |= acb->intstat; acb->intstat = 0; - osiop_write_4(sc, OSIOP_DSA, - dsdma->dm_segs[0].ds_addr + acb->dsoffset); + osiop_write_dsa(sc, acb); osiop_write_1(sc, OSIOP_SXFER, sc->sc_tinfo[reselid].sxfer); osiop_write_1(sc, OSIOP_SBCL, @@ -1617,8 +1814,7 @@ } target = sc->sc_nexus->xs->xs_periph->periph_target; osiop_write_4(sc, OSIOP_TEMP, 0); - osiop_write_4(sc, OSIOP_DSA, - dsdma->dm_segs[0].ds_addr + sc->sc_nexus->dsoffset); + osiop_write_dsa(sc, sc->sc_nexus); osiop_write_1(sc, OSIOP_SXFER, sc->sc_tinfo[target].sxfer); osiop_write_1(sc, OSIOP_SBCL, sc->sc_tinfo[target].sbcl); osiop_write_4(sc, OSIOP_DSP, scraddr + Ent_scripts); @@ -1683,7 +1879,8 @@ printf("osiop_chkintr: istat %x dstat %x sstat0 %x " "dsps %x dsa %x sbcl %x sts %x msg %x %x sfbr %x\n", istat, dstat, sstat0, intcode, - osiop_read_4(sc, OSIOP_DSA), + (sc->sc_rev == OSIOP_VARIANT_NCR53C700 + ? 0: osiop_read_4(sc, OSIOP_DSA)), osiop_read_1(sc, OSIOP_SBCL), ds->stat[0], ds->msgbuf[0], ds->msgbuf[1], osiop_read_1(sc, OSIOP_SFBR)); @@ -1810,7 +2007,8 @@ periph->periphtarget, osiop_read_1(sc, OSIOP_SBCL), osiop_read_1(sc, OSIOP_SFBR), - osiop_read_1(sc, OSIOP_LCRC), + (sc->sc_rev == OSIOP_VARIANT_NCR53C700 + ? 0 : osiop_read_1(sc, OSIOP_LCRC)), osiop_read_4(sc, OSIOP_DSP) - sc->sc_scrdma->dm_segs[0].ds_addr); } Index: sys/dev/ic/osiopreg.h =================================================================== RCS file: /cvsroot/syssrc/sys/dev/ic/osiopreg.h,v retrieving revision 1.1 diff -u -r1.1 osiopreg.h --- sys/dev/ic/osiopreg.h 2001/04/30 04:47:51 1.1 +++ sys/dev/ic/osiopreg.h 2002/07/10 16:14:16 @@ -108,9 +108,10 @@ #define OSIOP_DSPS 0x30 /* rw: DMA SCRIPTS Pointer Save reg */ +#define OSIOP_DMODE_53C700 (0x34+BL0) /* rw: DMA Mode reg */ #define OSIOP_SCRATCH 0x34 /* rw: Scratch register */ -#define OSIOP_DMODE (0x38+BL0) /* rw: DMA Mode reg */ +#define OSIOP_DMODE_53C710 (0x38+BL0) /* rw: DMA Mode reg */ #define OSIOP_DIEN (0x38+BL1) /* rw: DMA Interrupt Enable */ #define OSIOP_DWT (0x38+BL2) /* rw: DMA Watchdog Timer */ #define OSIOP_DCNTL (0x38+BL3) /* rw: DMA Control reg */ @@ -318,8 +319,10 @@ /* DMA FIFO register (dfifo) */ -#define OSIOP_DFIFO_FLF 0x80 /* Flush (spill) DMA FIFO */ -#define OSIOP_DFIFO_BO 0x7f /* FIFO byte offset counter */ +#define OSIOP_DFIFO_FLF 0x80 /* Flush (spill) DMA FIFO (53C700 only) */ +#define OSIOP_DFIFO_CLF 0x40 /* Clear DMA FIFO (53C700 only) */ +#define OSIOP_DFIFO_BO_53C710 0x7f /* FIFO byte offset counter */ +#define OSIOP_DFIFO_BO_53C700 0x3f /* FIFO byte offset counter */ /* Interrupt status register (istat) */ @@ -375,4 +378,5 @@ #define OSIOP_DCNTL_LLM 0x08 /* Enable SCSI Low-level mode */ #define OSIOP_DCNTL_STD 0x04 /* Start DMA operation */ #define OSIOP_DCNTL_FA 0x02 /* Fast arbitration */ -#define OSIOP_DCNTL_COM 0x01 /* 53C700 Compatibility */ +#define OSIOP_DCNTL_RST 0x01 /* Software reset (53C700 only) */ +#define OSIOP_DCNTL_COM 0x01 /* 53C700 Compatibility (53C710 only) */ Index: sys/dev/ic/osiopvar.h =================================================================== RCS file: /cvsroot/syssrc/sys/dev/ic/osiopvar.h,v retrieving revision 1.3 diff -u -r1.3 osiopvar.h --- sys/dev/ic/osiopvar.h 2002/05/14 02:58:35 1.3 +++ sys/dev/ic/osiopvar.h 2002/07/10 16:14:16 @@ -65,14 +65,18 @@ */ #define osiop_read_1(sc, reg) \ - bus_space_read_1((sc)->sc_bst, (sc)->sc_reg, reg) + bus_space_read_1((sc)->sc_bst, (sc)->sc_reg, reg ^ sc->sc_byteorder) #define osiop_write_1(sc, reg, val) \ - bus_space_write_1((sc)->sc_bst, (sc)->sc_reg, reg, val) + bus_space_write_1((sc)->sc_bst, (sc)->sc_reg, reg ^ sc->sc_byteorder, val) #define osiop_read_4(sc, reg) \ - bus_space_read_4((sc)->sc_bst, (sc)->sc_reg, reg) + (sc->sc_byteorder ? \ + bswap32(bus_space_read_4((sc)->sc_bst, (sc)->sc_reg, reg)) : \ + bus_space_read_4((sc)->sc_bst, (sc)->sc_reg, reg)) + #define osiop_write_4(sc, reg, val) \ - bus_space_write_4((sc)->sc_bst, (sc)->sc_reg, reg, val) + bus_space_write_4((sc)->sc_bst, (sc)->sc_reg, reg, \ + (sc->sc_byteorder ? bswap32(val) : val)) /* * The largest single request will be MAXPHYS bytes which will require @@ -222,6 +226,12 @@ int sc_clock_freq; int sc_tcp[4]; + int sc_rev; +#define OSIOP_VARIANT_NCR53C700 (0) +#define OSIOP_VARIANT_NCR53C710 (1) + bus_size_t sc_byteorder; +#define OSIOP_BYTEORDER_NATIVE (0x00) +#define OSIOP_BYTEORDER_NONNATIVE (0x03) int sc_flags; #define OSIOP_INTSOFF 0x80 /* Interrupts turned off */ #define OSIOP_INTDEFER 0x40 /* MD interrupt has been deferred */