1 1.19 andvar /* $NetBSD: oosiop.c,v 1.19 2024/02/09 22:08:34 andvar Exp $ */ 2 1.1 tsutsui 3 1.1 tsutsui /* 4 1.1 tsutsui * Copyright (c) 2001 Shuichiro URATA. All rights reserved. 5 1.1 tsutsui * 6 1.1 tsutsui * Redistribution and use in source and binary forms, with or without 7 1.1 tsutsui * modification, are permitted provided that the following conditions 8 1.1 tsutsui * are met: 9 1.1 tsutsui * 1. Redistributions of source code must retain the above copyright 10 1.1 tsutsui * notice, this list of conditions and the following disclaimer. 11 1.1 tsutsui * 2. Redistributions in binary form must reproduce the above copyright 12 1.1 tsutsui * notice, this list of conditions and the following disclaimer in the 13 1.1 tsutsui * documentation and/or other materials provided with the distribution. 14 1.1 tsutsui * 3. The name of the author may not be used to endorse or promote products 15 1.1 tsutsui * derived from this software without specific prior written permission. 16 1.1 tsutsui * 17 1.1 tsutsui * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 1.1 tsutsui * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 1.1 tsutsui * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 1.1 tsutsui * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 1.1 tsutsui * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 1.1 tsutsui * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 1.1 tsutsui * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 1.1 tsutsui * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 1.1 tsutsui * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 1.1 tsutsui * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 1.1 tsutsui */ 28 1.1 tsutsui 29 1.1 tsutsui /* 30 1.1 tsutsui * NCR53C700 SCSI I/O processor (OOSIOP) driver 31 1.1 tsutsui * 32 1.1 tsutsui * TODO: 33 1.1 tsutsui * - More better error handling. 34 1.1 tsutsui * - Implement tagged queuing. 35 1.1 tsutsui */ 36 1.2 lukem 37 1.2 lukem #include <sys/cdefs.h> 38 1.19 andvar __KERNEL_RCSID(0, "$NetBSD: oosiop.c,v 1.19 2024/02/09 22:08:34 andvar Exp $"); 39 1.1 tsutsui 40 1.1 tsutsui #include <sys/param.h> 41 1.1 tsutsui #include <sys/systm.h> 42 1.1 tsutsui #include <sys/callout.h> 43 1.1 tsutsui #include <sys/kernel.h> 44 1.1 tsutsui #include <sys/device.h> 45 1.1 tsutsui #include <sys/buf.h> 46 1.1 tsutsui #include <sys/malloc.h> 47 1.1 tsutsui #include <sys/queue.h> 48 1.1 tsutsui 49 1.1 tsutsui #include <dev/scsipi/scsi_all.h> 50 1.1 tsutsui #include <dev/scsipi/scsipi_all.h> 51 1.1 tsutsui #include <dev/scsipi/scsiconf.h> 52 1.1 tsutsui #include <dev/scsipi/scsi_message.h> 53 1.1 tsutsui 54 1.11 ad #include <sys/cpu.h> 55 1.11 ad #include <sys/bus.h> 56 1.1 tsutsui 57 1.1 tsutsui #include <dev/ic/oosiopreg.h> 58 1.1 tsutsui #include <dev/ic/oosiopvar.h> 59 1.1 tsutsui #include <dev/microcode/siop/oosiop.out> 60 1.1 tsutsui 61 1.1 tsutsui static int oosiop_alloc_cb(struct oosiop_softc *, int); 62 1.1 tsutsui 63 1.9 perry static inline void oosiop_relocate_io(struct oosiop_softc *, bus_addr_t); 64 1.9 perry static inline void oosiop_relocate_tc(struct oosiop_softc *, bus_addr_t); 65 1.9 perry static inline void oosiop_fixup_select(struct oosiop_softc *, bus_addr_t, 66 1.1 tsutsui int); 67 1.9 perry static inline void oosiop_fixup_jump(struct oosiop_softc *, bus_addr_t, 68 1.1 tsutsui bus_addr_t); 69 1.9 perry static inline void oosiop_fixup_move(struct oosiop_softc *, bus_addr_t, 70 1.1 tsutsui bus_size_t, bus_addr_t); 71 1.1 tsutsui 72 1.1 tsutsui static void oosiop_load_script(struct oosiop_softc *); 73 1.1 tsutsui static void oosiop_setup_sgdma(struct oosiop_softc *, struct oosiop_cb *); 74 1.1 tsutsui static void oosiop_setup_dma(struct oosiop_softc *); 75 1.1 tsutsui static void oosiop_flush_fifo(struct oosiop_softc *); 76 1.1 tsutsui static void oosiop_clear_fifo(struct oosiop_softc *); 77 1.1 tsutsui static void oosiop_phasemismatch(struct oosiop_softc *); 78 1.1 tsutsui static void oosiop_setup_syncxfer(struct oosiop_softc *); 79 1.1 tsutsui static void oosiop_set_syncparam(struct oosiop_softc *, int, int, int); 80 1.1 tsutsui static void oosiop_minphys(struct buf *); 81 1.1 tsutsui static void oosiop_scsipi_request(struct scsipi_channel *, 82 1.1 tsutsui scsipi_adapter_req_t, void *); 83 1.1 tsutsui static void oosiop_done(struct oosiop_softc *, struct oosiop_cb *); 84 1.1 tsutsui static void oosiop_timeout(void *); 85 1.1 tsutsui static void oosiop_reset(struct oosiop_softc *); 86 1.1 tsutsui static void oosiop_reset_bus(struct oosiop_softc *); 87 1.1 tsutsui static void oosiop_scriptintr(struct oosiop_softc *); 88 1.1 tsutsui static void oosiop_msgin(struct oosiop_softc *, struct oosiop_cb *); 89 1.1 tsutsui 90 1.1 tsutsui /* Trap interrupt code for unexpected data I/O */ 91 1.1 tsutsui #define DATAIN_TRAP 0xdead0001 92 1.1 tsutsui #define DATAOUT_TRAP 0xdead0002 93 1.1 tsutsui 94 1.19 andvar /* Possible TP and SCF combination */ 95 1.1 tsutsui static const struct { 96 1.6 tsutsui uint8_t tp; 97 1.6 tsutsui uint8_t scf; 98 1.1 tsutsui } synctbl[] = { 99 1.1 tsutsui {0, 1}, /* SCLK / 4.0 */ 100 1.1 tsutsui {1, 1}, /* SCLK / 5.0 */ 101 1.1 tsutsui {2, 1}, /* SCLK / 6.0 */ 102 1.1 tsutsui {3, 1}, /* SCLK / 7.0 */ 103 1.1 tsutsui {1, 2}, /* SCLK / 7.5 */ 104 1.1 tsutsui {4, 1}, /* SCLK / 8.0 */ 105 1.1 tsutsui {5, 1}, /* SCLK / 9.0 */ 106 1.1 tsutsui {6, 1}, /* SCLK / 10.0 */ 107 1.1 tsutsui {3, 2}, /* SCLK / 10.5 */ 108 1.1 tsutsui {7, 1}, /* SCLK / 11.0 */ 109 1.1 tsutsui {4, 2}, /* SCLK / 12.0 */ 110 1.1 tsutsui {5, 2}, /* SCLK / 13.5 */ 111 1.1 tsutsui {3, 3}, /* SCLK / 14.0 */ 112 1.1 tsutsui {6, 2}, /* SCLK / 15.0 */ 113 1.1 tsutsui {4, 3}, /* SCLK / 16.0 */ 114 1.1 tsutsui {7, 2}, /* SCLK / 16.5 */ 115 1.1 tsutsui {5, 3}, /* SCLK / 18.0 */ 116 1.1 tsutsui {6, 3}, /* SCLK / 20.0 */ 117 1.1 tsutsui {7, 3} /* SCLK / 22.0 */ 118 1.1 tsutsui }; 119 1.1 tsutsui #define NSYNCTBL (sizeof(synctbl) / sizeof(synctbl[0])) 120 1.1 tsutsui 121 1.1 tsutsui #define oosiop_period(sc, tp, scf) \ 122 1.1 tsutsui (((1000000000 / (sc)->sc_freq) * (tp) * (scf)) / 40) 123 1.1 tsutsui 124 1.1 tsutsui void 125 1.1 tsutsui oosiop_attach(struct oosiop_softc *sc) 126 1.1 tsutsui { 127 1.1 tsutsui bus_size_t scrsize; 128 1.1 tsutsui bus_dma_segment_t seg; 129 1.1 tsutsui struct oosiop_cb *cb; 130 1.1 tsutsui int err, i, nseg; 131 1.1 tsutsui 132 1.1 tsutsui /* 133 1.1 tsutsui * Allocate DMA-safe memory for the script and map it. 134 1.1 tsutsui */ 135 1.1 tsutsui scrsize = sizeof(oosiop_script); 136 1.1 tsutsui err = bus_dmamem_alloc(sc->sc_dmat, scrsize, PAGE_SIZE, 0, &seg, 1, 137 1.1 tsutsui &nseg, BUS_DMA_NOWAIT); 138 1.1 tsutsui if (err) { 139 1.12 tsutsui aprint_error(": failed to allocate script memory, err=%d\n", 140 1.12 tsutsui err); 141 1.1 tsutsui return; 142 1.1 tsutsui } 143 1.1 tsutsui err = bus_dmamem_map(sc->sc_dmat, &seg, nseg, scrsize, 144 1.10 christos (void **)&sc->sc_scr, BUS_DMA_NOWAIT | BUS_DMA_COHERENT); 145 1.1 tsutsui if (err) { 146 1.12 tsutsui aprint_error(": failed to map script memory, err=%d\n", err); 147 1.1 tsutsui return; 148 1.1 tsutsui } 149 1.1 tsutsui err = bus_dmamap_create(sc->sc_dmat, scrsize, 1, scrsize, 0, 150 1.1 tsutsui BUS_DMA_NOWAIT, &sc->sc_scrdma); 151 1.1 tsutsui if (err) { 152 1.12 tsutsui aprint_error(": failed to create script map, err=%d\n", err); 153 1.1 tsutsui return; 154 1.1 tsutsui } 155 1.1 tsutsui err = bus_dmamap_load(sc->sc_dmat, sc->sc_scrdma, sc->sc_scr, scrsize, 156 1.1 tsutsui NULL, BUS_DMA_NOWAIT | BUS_DMA_WRITE); 157 1.1 tsutsui if (err) { 158 1.12 tsutsui aprint_error(": failed to load script map, err=%d\n", err); 159 1.1 tsutsui return; 160 1.1 tsutsui } 161 1.1 tsutsui sc->sc_scrbase = sc->sc_scrdma->dm_segs[0].ds_addr; 162 1.1 tsutsui 163 1.1 tsutsui /* Initialize command block array */ 164 1.1 tsutsui TAILQ_INIT(&sc->sc_free_cb); 165 1.1 tsutsui TAILQ_INIT(&sc->sc_cbq); 166 1.1 tsutsui if (oosiop_alloc_cb(sc, OOSIOP_NCB) != 0) 167 1.1 tsutsui return; 168 1.1 tsutsui 169 1.1 tsutsui /* Use first cb to reselection msgin buffer */ 170 1.1 tsutsui cb = TAILQ_FIRST(&sc->sc_free_cb); 171 1.1 tsutsui sc->sc_reselbuf = cb->xferdma->dm_segs[0].ds_addr + 172 1.1 tsutsui offsetof(struct oosiop_xfer, msgin[0]); 173 1.1 tsutsui 174 1.1 tsutsui for (i = 0; i < OOSIOP_NTGT; i++) { 175 1.1 tsutsui sc->sc_tgt[i].nexus = NULL; 176 1.1 tsutsui sc->sc_tgt[i].flags = 0; 177 1.1 tsutsui } 178 1.1 tsutsui 179 1.1 tsutsui /* Setup asynchronous clock divisor parameters */ 180 1.1 tsutsui if (sc->sc_freq <= 25000000) { 181 1.1 tsutsui sc->sc_ccf = 10; 182 1.1 tsutsui sc->sc_dcntl = OOSIOP_DCNTL_CF_1; 183 1.1 tsutsui } else if (sc->sc_freq <= 37500000) { 184 1.1 tsutsui sc->sc_ccf = 15; 185 1.1 tsutsui sc->sc_dcntl = OOSIOP_DCNTL_CF_1_5; 186 1.1 tsutsui } else if (sc->sc_freq <= 50000000) { 187 1.1 tsutsui sc->sc_ccf = 20; 188 1.1 tsutsui sc->sc_dcntl = OOSIOP_DCNTL_CF_2; 189 1.1 tsutsui } else { 190 1.1 tsutsui sc->sc_ccf = 30; 191 1.1 tsutsui sc->sc_dcntl = OOSIOP_DCNTL_CF_3; 192 1.1 tsutsui } 193 1.1 tsutsui 194 1.1 tsutsui if (sc->sc_chip == OOSIOP_700) 195 1.1 tsutsui sc->sc_minperiod = oosiop_period(sc, 4, sc->sc_ccf); 196 1.1 tsutsui else 197 1.1 tsutsui sc->sc_minperiod = oosiop_period(sc, 4, 10); 198 1.1 tsutsui 199 1.1 tsutsui if (sc->sc_minperiod < 25) 200 1.1 tsutsui sc->sc_minperiod = 25; /* limit to 10MB/s */ 201 1.1 tsutsui 202 1.12 tsutsui aprint_normal(": NCR53C700%s rev %d, %dMHz, SCSI ID %d\n", 203 1.1 tsutsui sc->sc_chip == OOSIOP_700_66 ? "-66" : "", 204 1.1 tsutsui oosiop_read_1(sc, OOSIOP_CTEST7) >> 4, 205 1.1 tsutsui sc->sc_freq / 1000000, sc->sc_id); 206 1.1 tsutsui /* 207 1.1 tsutsui * Reset all 208 1.1 tsutsui */ 209 1.1 tsutsui oosiop_reset(sc); 210 1.1 tsutsui oosiop_reset_bus(sc); 211 1.1 tsutsui 212 1.1 tsutsui /* 213 1.1 tsutsui * Start SCRIPTS processor 214 1.1 tsutsui */ 215 1.1 tsutsui oosiop_load_script(sc); 216 1.1 tsutsui sc->sc_active = 0; 217 1.1 tsutsui oosiop_write_4(sc, OOSIOP_DSP, sc->sc_scrbase + Ent_wait_reselect); 218 1.1 tsutsui 219 1.1 tsutsui /* 220 1.1 tsutsui * Fill in the scsipi_adapter. 221 1.1 tsutsui */ 222 1.12 tsutsui sc->sc_adapter.adapt_dev = sc->sc_dev; 223 1.1 tsutsui sc->sc_adapter.adapt_nchannels = 1; 224 1.1 tsutsui sc->sc_adapter.adapt_openings = OOSIOP_NCB; 225 1.1 tsutsui sc->sc_adapter.adapt_max_periph = 1; 226 1.1 tsutsui sc->sc_adapter.adapt_ioctl = NULL; 227 1.1 tsutsui sc->sc_adapter.adapt_minphys = oosiop_minphys; 228 1.1 tsutsui sc->sc_adapter.adapt_request = oosiop_scsipi_request; 229 1.1 tsutsui 230 1.1 tsutsui /* 231 1.1 tsutsui * Fill in the scsipi_channel. 232 1.1 tsutsui */ 233 1.1 tsutsui sc->sc_channel.chan_adapter = &sc->sc_adapter; 234 1.1 tsutsui sc->sc_channel.chan_bustype = &scsi_bustype; 235 1.1 tsutsui sc->sc_channel.chan_channel = 0; 236 1.1 tsutsui sc->sc_channel.chan_ntargets = OOSIOP_NTGT; 237 1.1 tsutsui sc->sc_channel.chan_nluns = 8; 238 1.1 tsutsui sc->sc_channel.chan_id = sc->sc_id; 239 1.1 tsutsui 240 1.1 tsutsui /* 241 1.1 tsutsui * Now try to attach all the sub devices. 242 1.1 tsutsui */ 243 1.18 thorpej config_found(sc->sc_dev, &sc->sc_channel, scsiprint, CFARGS_NONE); 244 1.1 tsutsui } 245 1.1 tsutsui 246 1.1 tsutsui static int 247 1.1 tsutsui oosiop_alloc_cb(struct oosiop_softc *sc, int ncb) 248 1.1 tsutsui { 249 1.1 tsutsui struct oosiop_cb *cb; 250 1.14 riastrad void *xfer_kva; 251 1.1 tsutsui struct oosiop_xfer *xfer; 252 1.1 tsutsui bus_size_t xfersize; 253 1.1 tsutsui bus_dma_segment_t seg; 254 1.1 tsutsui int i, s, err, nseg; 255 1.1 tsutsui 256 1.1 tsutsui /* 257 1.1 tsutsui * Allocate oosiop_cb. 258 1.1 tsutsui */ 259 1.16 chs cb = malloc(sizeof(struct oosiop_cb) * ncb, M_DEVBUF, M_WAITOK|M_ZERO); 260 1.1 tsutsui 261 1.1 tsutsui /* 262 1.1 tsutsui * Allocate DMA-safe memory for the oosiop_xfer and map it. 263 1.1 tsutsui */ 264 1.1 tsutsui xfersize = sizeof(struct oosiop_xfer) * ncb; 265 1.1 tsutsui err = bus_dmamem_alloc(sc->sc_dmat, xfersize, PAGE_SIZE, 0, &seg, 1, 266 1.1 tsutsui &nseg, BUS_DMA_NOWAIT); 267 1.1 tsutsui if (err) { 268 1.1 tsutsui printf(": failed to allocate xfer block memory, err=%d\n", err); 269 1.14 riastrad goto fail1; 270 1.1 tsutsui } 271 1.14 riastrad KASSERT(nseg == 1); 272 1.14 riastrad err = bus_dmamem_map(sc->sc_dmat, &seg, nseg, xfersize, &xfer_kva, 273 1.14 riastrad BUS_DMA_NOWAIT | BUS_DMA_COHERENT); 274 1.1 tsutsui if (err) { 275 1.1 tsutsui printf(": failed to map xfer block memory, err=%d\n", err); 276 1.14 riastrad goto fail2; 277 1.1 tsutsui } 278 1.14 riastrad xfer = xfer_kva; 279 1.1 tsutsui 280 1.1 tsutsui /* Initialize each command block */ 281 1.1 tsutsui for (i = 0; i < ncb; i++) { 282 1.1 tsutsui err = bus_dmamap_create(sc->sc_dmat, PAGE_SIZE, 1, PAGE_SIZE, 283 1.14 riastrad 0, BUS_DMA_NOWAIT, &cb[i].cmddma); 284 1.1 tsutsui if (err) { 285 1.1 tsutsui printf(": failed to create cmddma map, err=%d\n", err); 286 1.14 riastrad goto loop_fail0; 287 1.1 tsutsui } 288 1.1 tsutsui err = bus_dmamap_create(sc->sc_dmat, OOSIOP_MAX_XFER, 289 1.1 tsutsui OOSIOP_NSG, OOSIOP_DBC_MAX, 0, BUS_DMA_NOWAIT, 290 1.14 riastrad &cb[i].datadma); 291 1.1 tsutsui if (err) { 292 1.1 tsutsui printf(": failed to create datadma map, err=%d\n", err); 293 1.14 riastrad goto loop_fail1; 294 1.1 tsutsui } 295 1.1 tsutsui 296 1.1 tsutsui err = bus_dmamap_create(sc->sc_dmat, 297 1.1 tsutsui sizeof(struct oosiop_xfer), 1, sizeof(struct oosiop_xfer), 298 1.14 riastrad 0, BUS_DMA_NOWAIT, &cb[i].xferdma); 299 1.1 tsutsui if (err) { 300 1.1 tsutsui printf(": failed to create xfer block map, err=%d\n", 301 1.1 tsutsui err); 302 1.14 riastrad goto loop_fail2; 303 1.1 tsutsui } 304 1.15 skrll err = bus_dmamap_load(sc->sc_dmat, cb[i].xferdma, &xfer[i], 305 1.1 tsutsui sizeof(struct oosiop_xfer), NULL, BUS_DMA_NOWAIT); 306 1.1 tsutsui if (err) { 307 1.1 tsutsui printf(": failed to load xfer block, err=%d\n", err); 308 1.14 riastrad goto loop_fail3; 309 1.1 tsutsui } 310 1.1 tsutsui 311 1.14 riastrad cb[i].xfer = &xfer[i]; 312 1.14 riastrad continue; 313 1.1 tsutsui 314 1.14 riastrad loop_fail4: __unused 315 1.14 riastrad bus_dmamap_unload(sc->sc_dmat, cb[i].xferdma); 316 1.14 riastrad loop_fail3: bus_dmamap_destroy(sc->sc_dmat, cb[i].xferdma); 317 1.14 riastrad loop_fail2: bus_dmamap_destroy(sc->sc_dmat, cb[i].datadma); 318 1.14 riastrad loop_fail1: bus_dmamap_destroy(sc->sc_dmat, cb[i].cmddma); 319 1.14 riastrad loop_fail0: goto fail3; 320 1.14 riastrad } 321 1.14 riastrad 322 1.14 riastrad for (i = 0; i < ncb; i++) { 323 1.1 tsutsui s = splbio(); 324 1.14 riastrad TAILQ_INSERT_TAIL(&sc->sc_free_cb, &cb[i], chain); 325 1.1 tsutsui splx(s); 326 1.14 riastrad } 327 1.1 tsutsui 328 1.14 riastrad /* Success! */ 329 1.14 riastrad return 0; 330 1.1 tsutsui 331 1.14 riastrad fail3: while (i--) { 332 1.14 riastrad bus_dmamap_unload(sc->sc_dmat, cb[i].xferdma); 333 1.14 riastrad bus_dmamap_destroy(sc->sc_dmat, cb[i].xferdma); 334 1.14 riastrad bus_dmamap_destroy(sc->sc_dmat, cb[i].datadma); 335 1.14 riastrad bus_dmamap_destroy(sc->sc_dmat, cb[i].cmddma); 336 1.14 riastrad } 337 1.14 riastrad bus_dmamem_unmap(sc->sc_dmat, xfer_kva, xfersize); 338 1.14 riastrad fail2: bus_dmamem_free(sc->sc_dmat, &seg, 1); 339 1.14 riastrad fail1: free(cb, M_DEVBUF); 340 1.16 chs KASSERT(err); 341 1.14 riastrad return err; 342 1.1 tsutsui } 343 1.1 tsutsui 344 1.9 perry static inline void 345 1.1 tsutsui oosiop_relocate_io(struct oosiop_softc *sc, bus_addr_t addr) 346 1.1 tsutsui { 347 1.6 tsutsui uint32_t dcmd; 348 1.1 tsutsui int32_t dsps; 349 1.1 tsutsui 350 1.1 tsutsui dcmd = le32toh(sc->sc_scr[addr / 4 + 0]); 351 1.1 tsutsui dsps = le32toh(sc->sc_scr[addr / 4 + 1]); 352 1.1 tsutsui 353 1.1 tsutsui /* convert relative to absolute */ 354 1.1 tsutsui if (dcmd & 0x04000000) { 355 1.1 tsutsui dcmd &= ~0x04000000; 356 1.1 tsutsui #if 0 357 1.1 tsutsui /* 358 1.5 wiz * sign extension isn't needed here because 359 1.1 tsutsui * ncr53cxxx.c generates 32 bit dsps. 360 1.1 tsutsui */ 361 1.1 tsutsui dsps <<= 8; 362 1.1 tsutsui dsps >>= 8; 363 1.1 tsutsui #endif 364 1.1 tsutsui sc->sc_scr[addr / 4 + 0] = htole32(dcmd); 365 1.1 tsutsui dsps += addr + 8; 366 1.1 tsutsui } 367 1.1 tsutsui 368 1.1 tsutsui sc->sc_scr[addr / 4 + 1] = htole32(dsps + sc->sc_scrbase); 369 1.1 tsutsui } 370 1.1 tsutsui 371 1.9 perry static inline void 372 1.1 tsutsui oosiop_relocate_tc(struct oosiop_softc *sc, bus_addr_t addr) 373 1.1 tsutsui { 374 1.6 tsutsui uint32_t dcmd; 375 1.1 tsutsui int32_t dsps; 376 1.1 tsutsui 377 1.1 tsutsui dcmd = le32toh(sc->sc_scr[addr / 4 + 0]); 378 1.1 tsutsui dsps = le32toh(sc->sc_scr[addr / 4 + 1]); 379 1.1 tsutsui 380 1.1 tsutsui /* convert relative to absolute */ 381 1.1 tsutsui if (dcmd & 0x00800000) { 382 1.1 tsutsui dcmd &= ~0x00800000; 383 1.1 tsutsui sc->sc_scr[addr / 4] = htole32(dcmd); 384 1.1 tsutsui #if 0 385 1.1 tsutsui /* 386 1.5 wiz * sign extension isn't needed here because 387 1.1 tsutsui * ncr53cxxx.c generates 32 bit dsps. 388 1.1 tsutsui */ 389 1.1 tsutsui dsps <<= 8; 390 1.1 tsutsui dsps >>= 8; 391 1.1 tsutsui #endif 392 1.1 tsutsui dsps += addr + 8; 393 1.1 tsutsui } 394 1.1 tsutsui 395 1.1 tsutsui sc->sc_scr[addr / 4 + 1] = htole32(dsps + sc->sc_scrbase); 396 1.1 tsutsui } 397 1.1 tsutsui 398 1.9 perry static inline void 399 1.1 tsutsui oosiop_fixup_select(struct oosiop_softc *sc, bus_addr_t addr, int id) 400 1.1 tsutsui { 401 1.6 tsutsui uint32_t dcmd; 402 1.1 tsutsui 403 1.1 tsutsui dcmd = le32toh(sc->sc_scr[addr / 4]); 404 1.1 tsutsui dcmd &= 0xff00ffff; 405 1.1 tsutsui dcmd |= 0x00010000 << id; 406 1.1 tsutsui sc->sc_scr[addr / 4] = htole32(dcmd); 407 1.1 tsutsui } 408 1.1 tsutsui 409 1.9 perry static inline void 410 1.1 tsutsui oosiop_fixup_jump(struct oosiop_softc *sc, bus_addr_t addr, bus_addr_t dst) 411 1.1 tsutsui { 412 1.1 tsutsui 413 1.1 tsutsui sc->sc_scr[addr / 4 + 1] = htole32(dst); 414 1.1 tsutsui } 415 1.1 tsutsui 416 1.9 perry static inline void 417 1.1 tsutsui oosiop_fixup_move(struct oosiop_softc *sc, bus_addr_t addr, bus_size_t dbc, 418 1.1 tsutsui bus_addr_t dsps) 419 1.1 tsutsui { 420 1.6 tsutsui uint32_t dcmd; 421 1.1 tsutsui 422 1.1 tsutsui dcmd = le32toh(sc->sc_scr[addr / 4]); 423 1.1 tsutsui dcmd &= 0xff000000; 424 1.1 tsutsui dcmd |= dbc & 0x00ffffff; 425 1.1 tsutsui sc->sc_scr[addr / 4 + 0] = htole32(dcmd); 426 1.1 tsutsui sc->sc_scr[addr / 4 + 1] = htole32(dsps); 427 1.1 tsutsui } 428 1.1 tsutsui 429 1.1 tsutsui static void 430 1.1 tsutsui oosiop_load_script(struct oosiop_softc *sc) 431 1.1 tsutsui { 432 1.1 tsutsui int i; 433 1.1 tsutsui 434 1.1 tsutsui /* load script */ 435 1.1 tsutsui for (i = 0; i < sizeof(oosiop_script) / sizeof(oosiop_script[0]); i++) 436 1.1 tsutsui sc->sc_scr[i] = htole32(oosiop_script[i]); 437 1.1 tsutsui 438 1.1 tsutsui /* relocate script */ 439 1.1 tsutsui for (i = 0; i < (sizeof(oosiop_script) / 8); i++) { 440 1.1 tsutsui switch (oosiop_script[i * 2] >> 27) { 441 1.1 tsutsui case 0x08: /* select */ 442 1.1 tsutsui case 0x0a: /* wait reselect */ 443 1.1 tsutsui oosiop_relocate_io(sc, i * 8); 444 1.1 tsutsui break; 445 1.1 tsutsui case 0x10: /* jump */ 446 1.1 tsutsui case 0x11: /* call */ 447 1.1 tsutsui oosiop_relocate_tc(sc, i * 8); 448 1.1 tsutsui break; 449 1.1 tsutsui } 450 1.1 tsutsui } 451 1.1 tsutsui 452 1.1 tsutsui oosiop_fixup_move(sc, Ent_p_resel_msgin_move, 1, sc->sc_reselbuf); 453 1.1 tsutsui OOSIOP_SCRIPT_SYNC(sc, BUS_DMASYNC_PREWRITE); 454 1.1 tsutsui } 455 1.1 tsutsui 456 1.1 tsutsui static void 457 1.1 tsutsui oosiop_setup_sgdma(struct oosiop_softc *sc, struct oosiop_cb *cb) 458 1.1 tsutsui { 459 1.4 tsutsui int i, n, off, control; 460 1.1 tsutsui struct oosiop_xfer *xfer; 461 1.1 tsutsui 462 1.1 tsutsui OOSIOP_XFERSCR_SYNC(sc, cb, 463 1.1 tsutsui BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 464 1.1 tsutsui 465 1.1 tsutsui off = cb->curdp; 466 1.1 tsutsui xfer = cb->xfer; 467 1.4 tsutsui control = cb->xs->xs_control; 468 1.1 tsutsui 469 1.4 tsutsui if (control & (XS_CTL_DATA_IN | XS_CTL_DATA_OUT)) { 470 1.4 tsutsui /* Find start segment */ 471 1.1 tsutsui for (i = 0; i < cb->datadma->dm_nsegs; i++) { 472 1.1 tsutsui if (off < cb->datadma->dm_segs[i].ds_len) 473 1.1 tsutsui break; 474 1.1 tsutsui off -= cb->datadma->dm_segs[i].ds_len; 475 1.1 tsutsui } 476 1.1 tsutsui 477 1.4 tsutsui /* build MOVE block */ 478 1.4 tsutsui if (control & XS_CTL_DATA_IN) { 479 1.4 tsutsui n = 0; 480 1.4 tsutsui while (i < cb->datadma->dm_nsegs) { 481 1.4 tsutsui xfer->datain_scr[n * 2 + 0] = 482 1.4 tsutsui htole32(0x09000000 | 483 1.4 tsutsui (cb->datadma->dm_segs[i].ds_len - off)); 484 1.4 tsutsui xfer->datain_scr[n * 2 + 1] = 485 1.4 tsutsui htole32(cb->datadma->dm_segs[i].ds_addr + 486 1.4 tsutsui off); 487 1.4 tsutsui n++; 488 1.4 tsutsui i++; 489 1.4 tsutsui off = 0; 490 1.4 tsutsui } 491 1.4 tsutsui xfer->datain_scr[n * 2 + 0] = htole32(0x80080000); 492 1.1 tsutsui xfer->datain_scr[n * 2 + 1] = 493 1.4 tsutsui htole32(sc->sc_scrbase + Ent_phasedispatch); 494 1.4 tsutsui } 495 1.4 tsutsui if (control & XS_CTL_DATA_OUT) { 496 1.4 tsutsui n = 0; 497 1.4 tsutsui while (i < cb->datadma->dm_nsegs) { 498 1.4 tsutsui xfer->dataout_scr[n * 2 + 0] = 499 1.4 tsutsui htole32(0x08000000 | 500 1.4 tsutsui (cb->datadma->dm_segs[i].ds_len - off)); 501 1.4 tsutsui xfer->dataout_scr[n * 2 + 1] = 502 1.4 tsutsui htole32(cb->datadma->dm_segs[i].ds_addr + 503 1.4 tsutsui off); 504 1.4 tsutsui n++; 505 1.4 tsutsui i++; 506 1.4 tsutsui off = 0; 507 1.4 tsutsui } 508 1.4 tsutsui xfer->dataout_scr[n * 2 + 0] = htole32(0x80080000); 509 1.4 tsutsui xfer->dataout_scr[n * 2 + 1] = 510 1.4 tsutsui htole32(sc->sc_scrbase + Ent_phasedispatch); 511 1.1 tsutsui } 512 1.4 tsutsui } 513 1.4 tsutsui if ((control & XS_CTL_DATA_IN) == 0) { 514 1.1 tsutsui xfer->datain_scr[0] = htole32(0x98080000); 515 1.1 tsutsui xfer->datain_scr[1] = htole32(DATAIN_TRAP); 516 1.1 tsutsui } 517 1.4 tsutsui if ((control & XS_CTL_DATA_OUT) == 0) { 518 1.1 tsutsui xfer->dataout_scr[0] = htole32(0x98080000); 519 1.1 tsutsui xfer->dataout_scr[1] = htole32(DATAOUT_TRAP); 520 1.1 tsutsui } 521 1.1 tsutsui OOSIOP_XFERSCR_SYNC(sc, cb, 522 1.1 tsutsui BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 523 1.1 tsutsui } 524 1.1 tsutsui 525 1.1 tsutsui /* 526 1.1 tsutsui * Setup DMA pointer into script. 527 1.1 tsutsui */ 528 1.1 tsutsui static void 529 1.1 tsutsui oosiop_setup_dma(struct oosiop_softc *sc) 530 1.1 tsutsui { 531 1.1 tsutsui struct oosiop_cb *cb; 532 1.1 tsutsui bus_addr_t xferbase; 533 1.1 tsutsui 534 1.1 tsutsui cb = sc->sc_curcb; 535 1.1 tsutsui xferbase = cb->xferdma->dm_segs[0].ds_addr; 536 1.1 tsutsui 537 1.1 tsutsui OOSIOP_SCRIPT_SYNC(sc, BUS_DMASYNC_POSTWRITE); 538 1.1 tsutsui 539 1.1 tsutsui oosiop_fixup_select(sc, Ent_p_select, cb->id); 540 1.7 perry oosiop_fixup_jump(sc, Ent_p_datain_jump, xferbase + 541 1.1 tsutsui offsetof(struct oosiop_xfer, datain_scr[0])); 542 1.1 tsutsui oosiop_fixup_jump(sc, Ent_p_dataout_jump, xferbase + 543 1.1 tsutsui offsetof(struct oosiop_xfer, dataout_scr[0])); 544 1.1 tsutsui oosiop_fixup_move(sc, Ent_p_msgin_move, 1, xferbase + 545 1.1 tsutsui offsetof(struct oosiop_xfer, msgin[0])); 546 1.1 tsutsui oosiop_fixup_move(sc, Ent_p_extmsglen_move, 1, xferbase + 547 1.1 tsutsui offsetof(struct oosiop_xfer, msgin[1])); 548 1.1 tsutsui oosiop_fixup_move(sc, Ent_p_msgout_move, cb->msgoutlen, xferbase + 549 1.1 tsutsui offsetof(struct oosiop_xfer, msgout[0])); 550 1.1 tsutsui oosiop_fixup_move(sc, Ent_p_status_move, 1, xferbase + 551 1.1 tsutsui offsetof(struct oosiop_xfer, status)); 552 1.1 tsutsui oosiop_fixup_move(sc, Ent_p_cmdout_move, cb->xs->cmdlen, 553 1.1 tsutsui cb->cmddma->dm_segs[0].ds_addr); 554 1.1 tsutsui 555 1.1 tsutsui OOSIOP_SCRIPT_SYNC(sc, BUS_DMASYNC_PREWRITE); 556 1.1 tsutsui } 557 1.1 tsutsui 558 1.1 tsutsui static void 559 1.1 tsutsui oosiop_flush_fifo(struct oosiop_softc *sc) 560 1.1 tsutsui { 561 1.1 tsutsui 562 1.1 tsutsui oosiop_write_1(sc, OOSIOP_DFIFO, oosiop_read_1(sc, OOSIOP_DFIFO) | 563 1.1 tsutsui OOSIOP_DFIFO_FLF); 564 1.1 tsutsui while ((oosiop_read_1(sc, OOSIOP_CTEST1) & OOSIOP_CTEST1_FMT) != 565 1.1 tsutsui OOSIOP_CTEST1_FMT) 566 1.1 tsutsui ; 567 1.1 tsutsui oosiop_write_1(sc, OOSIOP_DFIFO, oosiop_read_1(sc, OOSIOP_DFIFO) & 568 1.1 tsutsui ~OOSIOP_DFIFO_FLF); 569 1.1 tsutsui } 570 1.1 tsutsui 571 1.1 tsutsui static void 572 1.1 tsutsui oosiop_clear_fifo(struct oosiop_softc *sc) 573 1.1 tsutsui { 574 1.1 tsutsui 575 1.1 tsutsui oosiop_write_1(sc, OOSIOP_DFIFO, oosiop_read_1(sc, OOSIOP_DFIFO) | 576 1.1 tsutsui OOSIOP_DFIFO_CLF); 577 1.1 tsutsui while ((oosiop_read_1(sc, OOSIOP_CTEST1) & OOSIOP_CTEST1_FMT) != 578 1.1 tsutsui OOSIOP_CTEST1_FMT) 579 1.1 tsutsui ; 580 1.1 tsutsui oosiop_write_1(sc, OOSIOP_DFIFO, oosiop_read_1(sc, OOSIOP_DFIFO) & 581 1.1 tsutsui ~OOSIOP_DFIFO_CLF); 582 1.1 tsutsui } 583 1.1 tsutsui 584 1.1 tsutsui static void 585 1.1 tsutsui oosiop_phasemismatch(struct oosiop_softc *sc) 586 1.1 tsutsui { 587 1.1 tsutsui struct oosiop_cb *cb; 588 1.6 tsutsui uint32_t dsp, dbc, n, i, len; 589 1.6 tsutsui uint8_t dfifo, sstat1; 590 1.1 tsutsui 591 1.1 tsutsui cb = sc->sc_curcb; 592 1.1 tsutsui if (cb == NULL) 593 1.1 tsutsui return; 594 1.1 tsutsui 595 1.1 tsutsui dsp = oosiop_read_4(sc, OOSIOP_DSP); 596 1.1 tsutsui dbc = oosiop_read_4(sc, OOSIOP_DBC) & OOSIOP_DBC_MAX; 597 1.1 tsutsui len = 0; 598 1.1 tsutsui 599 1.1 tsutsui n = dsp - cb->xferdma->dm_segs[0].ds_addr - 8; 600 1.1 tsutsui if (n >= offsetof(struct oosiop_xfer, datain_scr[0]) && 601 1.1 tsutsui n < offsetof(struct oosiop_xfer, datain_scr[OOSIOP_NSG * 2])) { 602 1.1 tsutsui n -= offsetof(struct oosiop_xfer, datain_scr[0]); 603 1.1 tsutsui n >>= 3; 604 1.1 tsutsui OOSIOP_DINSCR_SYNC(sc, cb, 605 1.1 tsutsui BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 606 1.1 tsutsui for (i = 0; i <= n; i++) 607 1.1 tsutsui len += le32toh(cb->xfer->datain_scr[i * 2]) & 608 1.1 tsutsui 0x00ffffff; 609 1.1 tsutsui OOSIOP_DINSCR_SYNC(sc, cb, 610 1.1 tsutsui BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 611 1.1 tsutsui /* All data in the chip are already flushed */ 612 1.1 tsutsui } else if (n >= offsetof(struct oosiop_xfer, dataout_scr[0]) && 613 1.1 tsutsui n < offsetof(struct oosiop_xfer, dataout_scr[OOSIOP_NSG * 2])) { 614 1.1 tsutsui n -= offsetof(struct oosiop_xfer, dataout_scr[0]); 615 1.1 tsutsui n >>= 3; 616 1.1 tsutsui OOSIOP_DOUTSCR_SYNC(sc, cb, 617 1.1 tsutsui BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 618 1.1 tsutsui for (i = 0; i <= n; i++) 619 1.1 tsutsui len += le32toh(cb->xfer->dataout_scr[i * 2]) & 620 1.1 tsutsui 0x00ffffff; 621 1.1 tsutsui OOSIOP_DOUTSCR_SYNC(sc, cb, 622 1.1 tsutsui BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 623 1.1 tsutsui 624 1.1 tsutsui dfifo = oosiop_read_1(sc, OOSIOP_DFIFO); 625 1.1 tsutsui dbc += ((dfifo & OOSIOP_DFIFO_BO) - (dbc & OOSIOP_DFIFO_BO)) & 626 1.1 tsutsui OOSIOP_DFIFO_BO; 627 1.1 tsutsui 628 1.1 tsutsui sstat1 = oosiop_read_1(sc, OOSIOP_SSTAT1); 629 1.1 tsutsui if (sstat1 & OOSIOP_SSTAT1_OLF) 630 1.1 tsutsui dbc++; 631 1.7 perry if ((sc->sc_tgt[cb->id].sxfer != 0) && 632 1.1 tsutsui (sstat1 & OOSIOP_SSTAT1_ORF) != 0) 633 1.1 tsutsui dbc++; 634 1.1 tsutsui 635 1.1 tsutsui oosiop_clear_fifo(sc); 636 1.1 tsutsui } else { 637 1.12 tsutsui printf("%s: phase mismatch addr=%08x\n", 638 1.12 tsutsui device_xname(sc->sc_dev), 639 1.1 tsutsui oosiop_read_4(sc, OOSIOP_DSP) - 8); 640 1.1 tsutsui oosiop_clear_fifo(sc); 641 1.1 tsutsui return; 642 1.1 tsutsui } 643 1.1 tsutsui 644 1.1 tsutsui len -= dbc; 645 1.1 tsutsui if (len) { 646 1.1 tsutsui cb->curdp += len; 647 1.1 tsutsui oosiop_setup_sgdma(sc, cb); 648 1.1 tsutsui } 649 1.1 tsutsui } 650 1.1 tsutsui 651 1.1 tsutsui static void 652 1.1 tsutsui oosiop_setup_syncxfer(struct oosiop_softc *sc) 653 1.1 tsutsui { 654 1.1 tsutsui int id; 655 1.1 tsutsui 656 1.1 tsutsui id = sc->sc_curcb->id; 657 1.1 tsutsui if (sc->sc_chip != OOSIOP_700) 658 1.1 tsutsui oosiop_write_1(sc, OOSIOP_SBCL, sc->sc_tgt[id].scf); 659 1.1 tsutsui 660 1.1 tsutsui oosiop_write_1(sc, OOSIOP_SXFER, sc->sc_tgt[id].sxfer); 661 1.1 tsutsui } 662 1.1 tsutsui 663 1.1 tsutsui static void 664 1.1 tsutsui oosiop_set_syncparam(struct oosiop_softc *sc, int id, int period, int offset) 665 1.1 tsutsui { 666 1.1 tsutsui int i, p; 667 1.1 tsutsui struct scsipi_xfer_mode xm; 668 1.1 tsutsui 669 1.1 tsutsui xm.xm_target = id; 670 1.1 tsutsui xm.xm_mode = 0; 671 1.1 tsutsui xm.xm_period = 0; 672 1.1 tsutsui xm.xm_offset = 0; 673 1.1 tsutsui 674 1.1 tsutsui if (offset == 0) { 675 1.1 tsutsui /* Asynchronous */ 676 1.1 tsutsui sc->sc_tgt[id].scf = 0; 677 1.1 tsutsui sc->sc_tgt[id].sxfer = 0; 678 1.1 tsutsui } else { 679 1.1 tsutsui /* Synchronous */ 680 1.1 tsutsui if (sc->sc_chip == OOSIOP_700) { 681 1.1 tsutsui for (i = 4; i < 12; i++) { 682 1.1 tsutsui p = oosiop_period(sc, i, sc->sc_ccf); 683 1.1 tsutsui if (p >= period) 684 1.1 tsutsui break; 685 1.1 tsutsui } 686 1.1 tsutsui if (i == 12) { 687 1.1 tsutsui printf("%s: target %d period too large\n", 688 1.12 tsutsui device_xname(sc->sc_dev), id); 689 1.1 tsutsui i = 11; /* XXX */ 690 1.1 tsutsui } 691 1.1 tsutsui sc->sc_tgt[id].scf = 0; 692 1.1 tsutsui sc->sc_tgt[id].sxfer = ((i - 4) << 4) | offset; 693 1.1 tsutsui } else { 694 1.1 tsutsui for (i = 0; i < NSYNCTBL; i++) { 695 1.1 tsutsui p = oosiop_period(sc, synctbl[i].tp + 4, 696 1.1 tsutsui (synctbl[i].scf + 1) * 5); 697 1.1 tsutsui if (p >= period) 698 1.1 tsutsui break; 699 1.1 tsutsui } 700 1.1 tsutsui if (i == NSYNCTBL) { 701 1.1 tsutsui printf("%s: target %d period too large\n", 702 1.12 tsutsui device_xname(sc->sc_dev), id); 703 1.1 tsutsui i = NSYNCTBL - 1; /* XXX */ 704 1.1 tsutsui } 705 1.1 tsutsui sc->sc_tgt[id].scf = synctbl[i].scf; 706 1.1 tsutsui sc->sc_tgt[id].sxfer = (synctbl[i].tp << 4) | offset; 707 1.1 tsutsui } 708 1.1 tsutsui 709 1.1 tsutsui xm.xm_mode |= PERIPH_CAP_SYNC; 710 1.1 tsutsui xm.xm_period = period; 711 1.1 tsutsui xm.xm_offset = offset; 712 1.1 tsutsui } 713 1.1 tsutsui 714 1.1 tsutsui scsipi_async_event(&sc->sc_channel, ASYNC_EVENT_XFER_MODE, &xm); 715 1.1 tsutsui } 716 1.1 tsutsui 717 1.1 tsutsui static void 718 1.1 tsutsui oosiop_minphys(struct buf *bp) 719 1.1 tsutsui { 720 1.1 tsutsui 721 1.1 tsutsui if (bp->b_bcount > OOSIOP_MAX_XFER) 722 1.1 tsutsui bp->b_bcount = OOSIOP_MAX_XFER; 723 1.1 tsutsui minphys(bp); 724 1.1 tsutsui } 725 1.1 tsutsui 726 1.1 tsutsui static void 727 1.1 tsutsui oosiop_scsipi_request(struct scsipi_channel *chan, scsipi_adapter_req_t req, 728 1.1 tsutsui void *arg) 729 1.1 tsutsui { 730 1.1 tsutsui struct scsipi_xfer *xs; 731 1.1 tsutsui struct oosiop_softc *sc; 732 1.1 tsutsui struct oosiop_cb *cb; 733 1.1 tsutsui struct oosiop_xfer *xfer; 734 1.1 tsutsui struct scsipi_xfer_mode *xm; 735 1.1 tsutsui int s, err; 736 1.1 tsutsui 737 1.12 tsutsui sc = device_private(chan->chan_adapter->adapt_dev); 738 1.1 tsutsui 739 1.1 tsutsui switch (req) { 740 1.1 tsutsui case ADAPTER_REQ_RUN_XFER: 741 1.1 tsutsui xs = arg; 742 1.1 tsutsui 743 1.1 tsutsui s = splbio(); 744 1.1 tsutsui cb = TAILQ_FIRST(&sc->sc_free_cb); 745 1.1 tsutsui TAILQ_REMOVE(&sc->sc_free_cb, cb, chain); 746 1.1 tsutsui splx(s); 747 1.1 tsutsui 748 1.1 tsutsui cb->xs = xs; 749 1.1 tsutsui cb->flags = 0; 750 1.1 tsutsui cb->id = xs->xs_periph->periph_target; 751 1.1 tsutsui cb->lun = xs->xs_periph->periph_lun; 752 1.1 tsutsui cb->curdp = 0; 753 1.1 tsutsui cb->savedp = 0; 754 1.1 tsutsui xfer = cb->xfer; 755 1.1 tsutsui 756 1.1 tsutsui /* Setup SCSI command buffer DMA */ 757 1.1 tsutsui err = bus_dmamap_load(sc->sc_dmat, cb->cmddma, xs->cmd, 758 1.1 tsutsui xs->cmdlen, NULL, ((xs->xs_control & XS_CTL_NOSLEEP) ? 759 1.1 tsutsui BUS_DMA_NOWAIT : BUS_DMA_WAITOK) | BUS_DMA_WRITE); 760 1.1 tsutsui if (err) { 761 1.1 tsutsui printf("%s: unable to load cmd DMA map: %d", 762 1.12 tsutsui device_xname(sc->sc_dev), err); 763 1.1 tsutsui xs->error = XS_RESOURCE_SHORTAGE; 764 1.1 tsutsui TAILQ_INSERT_TAIL(&sc->sc_free_cb, cb, chain); 765 1.1 tsutsui scsipi_done(xs); 766 1.1 tsutsui return; 767 1.1 tsutsui } 768 1.1 tsutsui bus_dmamap_sync(sc->sc_dmat, cb->cmddma, 0, xs->cmdlen, 769 1.1 tsutsui BUS_DMASYNC_PREWRITE); 770 1.1 tsutsui 771 1.1 tsutsui /* Setup data buffer DMA */ 772 1.1 tsutsui if (xs->xs_control & (XS_CTL_DATA_IN | XS_CTL_DATA_OUT)) { 773 1.1 tsutsui err = bus_dmamap_load(sc->sc_dmat, cb->datadma, 774 1.1 tsutsui xs->data, xs->datalen, NULL, 775 1.1 tsutsui ((xs->xs_control & XS_CTL_NOSLEEP) ? 776 1.1 tsutsui BUS_DMA_NOWAIT : BUS_DMA_WAITOK) | 777 1.1 tsutsui BUS_DMA_STREAMING | 778 1.1 tsutsui ((xs->xs_control & XS_CTL_DATA_IN) ? BUS_DMA_READ : 779 1.1 tsutsui BUS_DMA_WRITE)); 780 1.1 tsutsui if (err) { 781 1.1 tsutsui printf("%s: unable to load data DMA map: %d", 782 1.12 tsutsui device_xname(sc->sc_dev), err); 783 1.1 tsutsui xs->error = XS_RESOURCE_SHORTAGE; 784 1.1 tsutsui bus_dmamap_unload(sc->sc_dmat, cb->cmddma); 785 1.1 tsutsui TAILQ_INSERT_TAIL(&sc->sc_free_cb, cb, chain); 786 1.1 tsutsui scsipi_done(xs); 787 1.1 tsutsui return; 788 1.1 tsutsui } 789 1.1 tsutsui bus_dmamap_sync(sc->sc_dmat, cb->datadma, 790 1.1 tsutsui 0, xs->datalen, 791 1.1 tsutsui BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 792 1.1 tsutsui } 793 1.1 tsutsui 794 1.1 tsutsui oosiop_setup_sgdma(sc, cb); 795 1.1 tsutsui 796 1.1 tsutsui /* Setup msgout buffer */ 797 1.1 tsutsui OOSIOP_XFERMSG_SYNC(sc, cb, 798 1.1 tsutsui BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 799 1.1 tsutsui xfer->msgout[0] = MSG_IDENTIFY(cb->lun, 800 1.1 tsutsui (xs->xs_control & XS_CTL_REQSENSE) == 0); 801 1.1 tsutsui cb->msgoutlen = 1; 802 1.1 tsutsui 803 1.1 tsutsui if (sc->sc_tgt[cb->id].flags & TGTF_SYNCNEG) { 804 1.1 tsutsui /* Send SDTR */ 805 1.1 tsutsui xfer->msgout[1] = MSG_EXTENDED; 806 1.1 tsutsui xfer->msgout[2] = MSG_EXT_SDTR_LEN; 807 1.1 tsutsui xfer->msgout[3] = MSG_EXT_SDTR; 808 1.1 tsutsui xfer->msgout[4] = sc->sc_minperiod; 809 1.1 tsutsui xfer->msgout[5] = OOSIOP_MAX_OFFSET; 810 1.1 tsutsui cb->msgoutlen = 6; 811 1.1 tsutsui sc->sc_tgt[cb->id].flags &= ~TGTF_SYNCNEG; 812 1.1 tsutsui sc->sc_tgt[cb->id].flags |= TGTF_WAITSDTR; 813 1.1 tsutsui } 814 1.1 tsutsui 815 1.1 tsutsui xfer->status = SCSI_OOSIOP_NOSTATUS; 816 1.1 tsutsui 817 1.1 tsutsui OOSIOP_XFERMSG_SYNC(sc, cb, 818 1.1 tsutsui BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 819 1.1 tsutsui 820 1.1 tsutsui s = splbio(); 821 1.1 tsutsui 822 1.1 tsutsui TAILQ_INSERT_TAIL(&sc->sc_cbq, cb, chain); 823 1.1 tsutsui 824 1.1 tsutsui if (!sc->sc_active) { 825 1.1 tsutsui /* Abort script to start selection */ 826 1.1 tsutsui oosiop_write_1(sc, OOSIOP_ISTAT, OOSIOP_ISTAT_ABRT); 827 1.1 tsutsui } 828 1.1 tsutsui if (xs->xs_control & XS_CTL_POLL) { 829 1.1 tsutsui /* Poll for command completion */ 830 1.1 tsutsui while ((xs->xs_status & XS_STS_DONE) == 0) { 831 1.1 tsutsui delay(1000); 832 1.1 tsutsui oosiop_intr(sc); 833 1.1 tsutsui } 834 1.1 tsutsui } 835 1.1 tsutsui 836 1.1 tsutsui splx(s); 837 1.1 tsutsui 838 1.1 tsutsui return; 839 1.1 tsutsui 840 1.1 tsutsui case ADAPTER_REQ_GROW_RESOURCES: 841 1.1 tsutsui return; 842 1.1 tsutsui 843 1.1 tsutsui case ADAPTER_REQ_SET_XFER_MODE: 844 1.1 tsutsui xm = arg; 845 1.1 tsutsui if (xm->xm_mode & PERIPH_CAP_SYNC) 846 1.1 tsutsui sc->sc_tgt[xm->xm_target].flags |= TGTF_SYNCNEG; 847 1.1 tsutsui else 848 1.1 tsutsui oosiop_set_syncparam(sc, xm->xm_target, 0, 0); 849 1.1 tsutsui 850 1.1 tsutsui return; 851 1.1 tsutsui } 852 1.1 tsutsui } 853 1.1 tsutsui 854 1.1 tsutsui static void 855 1.1 tsutsui oosiop_done(struct oosiop_softc *sc, struct oosiop_cb *cb) 856 1.1 tsutsui { 857 1.1 tsutsui struct scsipi_xfer *xs; 858 1.1 tsutsui 859 1.1 tsutsui xs = cb->xs; 860 1.1 tsutsui if (cb == sc->sc_curcb) 861 1.1 tsutsui sc->sc_curcb = NULL; 862 1.1 tsutsui if (cb == sc->sc_lastcb) 863 1.1 tsutsui sc->sc_lastcb = NULL; 864 1.1 tsutsui sc->sc_tgt[cb->id].nexus = NULL; 865 1.1 tsutsui 866 1.1 tsutsui callout_stop(&xs->xs_callout); 867 1.1 tsutsui 868 1.1 tsutsui bus_dmamap_sync(sc->sc_dmat, cb->cmddma, 0, xs->cmdlen, 869 1.1 tsutsui BUS_DMASYNC_POSTWRITE); 870 1.1 tsutsui bus_dmamap_unload(sc->sc_dmat, cb->cmddma); 871 1.1 tsutsui 872 1.1 tsutsui if (xs->datalen > 0) { 873 1.1 tsutsui bus_dmamap_sync(sc->sc_dmat, cb->datadma, 0, xs->datalen, 874 1.1 tsutsui BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 875 1.1 tsutsui bus_dmamap_unload(sc->sc_dmat, cb->datadma); 876 1.1 tsutsui } 877 1.1 tsutsui 878 1.1 tsutsui xs->status = cb->xfer->status; 879 1.1 tsutsui xs->resid = 0; /* XXX */ 880 1.1 tsutsui 881 1.1 tsutsui if (cb->flags & CBF_SELTOUT) 882 1.1 tsutsui xs->error = XS_SELTIMEOUT; 883 1.1 tsutsui else if (cb->flags & CBF_TIMEOUT) 884 1.1 tsutsui xs->error = XS_TIMEOUT; 885 1.1 tsutsui else switch (xs->status) { 886 1.1 tsutsui case SCSI_OK: 887 1.1 tsutsui xs->error = XS_NOERROR; 888 1.1 tsutsui break; 889 1.1 tsutsui 890 1.1 tsutsui case SCSI_BUSY: 891 1.1 tsutsui case SCSI_CHECK: 892 1.1 tsutsui xs->error = XS_BUSY; 893 1.1 tsutsui break; 894 1.1 tsutsui case SCSI_OOSIOP_NOSTATUS: 895 1.1 tsutsui /* the status byte was not updated, cmd was aborted. */ 896 1.1 tsutsui xs->error = XS_SELTIMEOUT; 897 1.1 tsutsui break; 898 1.1 tsutsui 899 1.1 tsutsui default: 900 1.1 tsutsui xs->error = XS_RESET; 901 1.1 tsutsui break; 902 1.1 tsutsui } 903 1.1 tsutsui 904 1.1 tsutsui scsipi_done(xs); 905 1.1 tsutsui 906 1.1 tsutsui /* Put it on the free list. */ 907 1.1 tsutsui TAILQ_INSERT_TAIL(&sc->sc_free_cb, cb, chain); 908 1.1 tsutsui } 909 1.1 tsutsui 910 1.1 tsutsui static void 911 1.1 tsutsui oosiop_timeout(void *arg) 912 1.1 tsutsui { 913 1.1 tsutsui struct oosiop_cb *cb; 914 1.1 tsutsui struct scsipi_periph *periph; 915 1.1 tsutsui struct oosiop_softc *sc; 916 1.1 tsutsui int s; 917 1.1 tsutsui 918 1.1 tsutsui cb = arg; 919 1.1 tsutsui periph = cb->xs->xs_periph; 920 1.12 tsutsui sc = device_private(periph->periph_channel->chan_adapter->adapt_dev); 921 1.1 tsutsui scsipi_printaddr(periph); 922 1.1 tsutsui printf("timed out\n"); 923 1.1 tsutsui 924 1.1 tsutsui s = splbio(); 925 1.1 tsutsui 926 1.1 tsutsui cb->flags |= CBF_TIMEOUT; 927 1.1 tsutsui oosiop_done(sc, cb); 928 1.1 tsutsui 929 1.1 tsutsui splx(s); 930 1.1 tsutsui } 931 1.1 tsutsui 932 1.1 tsutsui static void 933 1.1 tsutsui oosiop_reset(struct oosiop_softc *sc) 934 1.1 tsutsui { 935 1.1 tsutsui int i, s; 936 1.1 tsutsui 937 1.1 tsutsui s = splbio(); 938 1.1 tsutsui 939 1.1 tsutsui /* Stop SCRIPTS processor */ 940 1.1 tsutsui oosiop_write_1(sc, OOSIOP_ISTAT, OOSIOP_ISTAT_ABRT); 941 1.1 tsutsui delay(100); 942 1.1 tsutsui oosiop_write_1(sc, OOSIOP_ISTAT, 0); 943 1.1 tsutsui 944 1.1 tsutsui /* Reset the chip */ 945 1.1 tsutsui oosiop_write_1(sc, OOSIOP_DCNTL, sc->sc_dcntl | OOSIOP_DCNTL_RST); 946 1.1 tsutsui delay(100); 947 1.1 tsutsui oosiop_write_1(sc, OOSIOP_DCNTL, sc->sc_dcntl); 948 1.1 tsutsui delay(10000); 949 1.1 tsutsui 950 1.1 tsutsui /* Set up various chip parameters */ 951 1.1 tsutsui oosiop_write_1(sc, OOSIOP_SCNTL0, OOSIOP_ARB_FULL | OOSIOP_SCNTL0_EPG); 952 1.1 tsutsui oosiop_write_1(sc, OOSIOP_SCNTL1, OOSIOP_SCNTL1_ESR); 953 1.1 tsutsui oosiop_write_1(sc, OOSIOP_DCNTL, sc->sc_dcntl); 954 1.1 tsutsui oosiop_write_1(sc, OOSIOP_DMODE, OOSIOP_DMODE_BL_8); 955 1.1 tsutsui oosiop_write_1(sc, OOSIOP_SCID, OOSIOP_SCID_VALUE(sc->sc_id)); 956 1.1 tsutsui oosiop_write_1(sc, OOSIOP_DWT, 0xff); /* Enable DMA timeout */ 957 1.1 tsutsui oosiop_write_1(sc, OOSIOP_CTEST7, 0); 958 1.1 tsutsui oosiop_write_1(sc, OOSIOP_SXFER, 0); 959 1.1 tsutsui 960 1.1 tsutsui /* Clear all interrupts */ 961 1.1 tsutsui (void)oosiop_read_1(sc, OOSIOP_SSTAT0); 962 1.1 tsutsui (void)oosiop_read_1(sc, OOSIOP_SSTAT1); 963 1.1 tsutsui (void)oosiop_read_1(sc, OOSIOP_DSTAT); 964 1.1 tsutsui 965 1.1 tsutsui /* Enable interrupts */ 966 1.1 tsutsui oosiop_write_1(sc, OOSIOP_SIEN, 967 1.1 tsutsui OOSIOP_SIEN_M_A | OOSIOP_SIEN_STO | OOSIOP_SIEN_SGE | 968 1.1 tsutsui OOSIOP_SIEN_UDC | OOSIOP_SIEN_RST | OOSIOP_SIEN_PAR); 969 1.1 tsutsui oosiop_write_1(sc, OOSIOP_DIEN, 970 1.1 tsutsui OOSIOP_DIEN_ABRT | OOSIOP_DIEN_SSI | OOSIOP_DIEN_SIR | 971 1.1 tsutsui OOSIOP_DIEN_WTD | OOSIOP_DIEN_IID); 972 1.1 tsutsui 973 1.1 tsutsui /* Set target state to asynchronous */ 974 1.1 tsutsui for (i = 0; i < OOSIOP_NTGT; i++) { 975 1.1 tsutsui sc->sc_tgt[i].flags = 0; 976 1.1 tsutsui sc->sc_tgt[i].scf = 0; 977 1.1 tsutsui sc->sc_tgt[i].sxfer = 0; 978 1.1 tsutsui } 979 1.1 tsutsui 980 1.1 tsutsui splx(s); 981 1.1 tsutsui } 982 1.1 tsutsui 983 1.1 tsutsui static void 984 1.1 tsutsui oosiop_reset_bus(struct oosiop_softc *sc) 985 1.1 tsutsui { 986 1.1 tsutsui int s, i; 987 1.1 tsutsui 988 1.1 tsutsui s = splbio(); 989 1.1 tsutsui 990 1.1 tsutsui /* Assert SCSI RST */ 991 1.1 tsutsui oosiop_write_1(sc, OOSIOP_SCNTL1, OOSIOP_SCNTL1_RST); 992 1.1 tsutsui delay(25); /* Reset hold time (25us) */ 993 1.1 tsutsui oosiop_write_1(sc, OOSIOP_SCNTL1, 0); 994 1.1 tsutsui 995 1.1 tsutsui /* Remove all nexuses */ 996 1.1 tsutsui for (i = 0; i < OOSIOP_NTGT; i++) { 997 1.1 tsutsui if (sc->sc_tgt[i].nexus) { 998 1.1 tsutsui sc->sc_tgt[i].nexus->xfer->status = 999 1.1 tsutsui SCSI_OOSIOP_NOSTATUS; /* XXX */ 1000 1.1 tsutsui oosiop_done(sc, sc->sc_tgt[i].nexus); 1001 1.1 tsutsui } 1002 1.1 tsutsui } 1003 1.1 tsutsui 1004 1.1 tsutsui sc->sc_curcb = NULL; 1005 1.1 tsutsui 1006 1.1 tsutsui delay(250000); /* Reset to selection (250ms) */ 1007 1.1 tsutsui 1008 1.1 tsutsui splx(s); 1009 1.1 tsutsui } 1010 1.1 tsutsui 1011 1.1 tsutsui /* 1012 1.1 tsutsui * interrupt handler 1013 1.1 tsutsui */ 1014 1.1 tsutsui int 1015 1.1 tsutsui oosiop_intr(struct oosiop_softc *sc) 1016 1.1 tsutsui { 1017 1.1 tsutsui struct oosiop_cb *cb; 1018 1.6 tsutsui uint32_t dcmd; 1019 1.1 tsutsui int timeout; 1020 1.6 tsutsui uint8_t istat, dstat, sstat0; 1021 1.1 tsutsui 1022 1.1 tsutsui istat = oosiop_read_1(sc, OOSIOP_ISTAT); 1023 1.1 tsutsui 1024 1.1 tsutsui if ((istat & (OOSIOP_ISTAT_SIP | OOSIOP_ISTAT_DIP)) == 0) 1025 1.1 tsutsui return (0); 1026 1.1 tsutsui 1027 1.1 tsutsui sc->sc_nextdsp = Ent_wait_reselect; 1028 1.1 tsutsui 1029 1.1 tsutsui /* DMA interrupts */ 1030 1.1 tsutsui if (istat & OOSIOP_ISTAT_DIP) { 1031 1.1 tsutsui oosiop_write_1(sc, OOSIOP_ISTAT, 0); 1032 1.1 tsutsui 1033 1.1 tsutsui dstat = oosiop_read_1(sc, OOSIOP_DSTAT); 1034 1.1 tsutsui 1035 1.1 tsutsui if (dstat & OOSIOP_DSTAT_ABRT) { 1036 1.1 tsutsui sc->sc_nextdsp = oosiop_read_4(sc, OOSIOP_DSP) - 1037 1.1 tsutsui sc->sc_scrbase - 8; 1038 1.1 tsutsui 1039 1.1 tsutsui if (sc->sc_nextdsp == Ent_p_resel_msgin_move && 1040 1.1 tsutsui (oosiop_read_1(sc, OOSIOP_SBCL) & OOSIOP_ACK)) { 1041 1.1 tsutsui if ((dstat & OOSIOP_DSTAT_DFE) == 0) 1042 1.1 tsutsui oosiop_flush_fifo(sc); 1043 1.1 tsutsui sc->sc_nextdsp += 8; 1044 1.1 tsutsui } 1045 1.1 tsutsui } 1046 1.1 tsutsui 1047 1.1 tsutsui if (dstat & OOSIOP_DSTAT_SSI) { 1048 1.1 tsutsui sc->sc_nextdsp = oosiop_read_4(sc, OOSIOP_DSP) - 1049 1.1 tsutsui sc->sc_scrbase; 1050 1.12 tsutsui printf("%s: single step %08x\n", 1051 1.12 tsutsui device_xname(sc->sc_dev), sc->sc_nextdsp); 1052 1.1 tsutsui } 1053 1.1 tsutsui 1054 1.1 tsutsui if (dstat & OOSIOP_DSTAT_SIR) { 1055 1.1 tsutsui if ((dstat & OOSIOP_DSTAT_DFE) == 0) 1056 1.1 tsutsui oosiop_flush_fifo(sc); 1057 1.1 tsutsui oosiop_scriptintr(sc); 1058 1.1 tsutsui } 1059 1.1 tsutsui 1060 1.1 tsutsui if (dstat & OOSIOP_DSTAT_WTD) { 1061 1.12 tsutsui printf("%s: DMA time out\n", device_xname(sc->sc_dev)); 1062 1.1 tsutsui oosiop_reset(sc); 1063 1.1 tsutsui } 1064 1.1 tsutsui 1065 1.1 tsutsui if (dstat & OOSIOP_DSTAT_IID) { 1066 1.1 tsutsui dcmd = oosiop_read_4(sc, OOSIOP_DBC); 1067 1.1 tsutsui if ((dcmd & 0xf8000000) == 0x48000000) { 1068 1.1 tsutsui printf("%s: REQ asserted on WAIT DISCONNECT\n", 1069 1.12 tsutsui device_xname(sc->sc_dev)); 1070 1.1 tsutsui sc->sc_nextdsp = Ent_phasedispatch; /* XXX */ 1071 1.1 tsutsui } else { 1072 1.1 tsutsui printf("%s: invalid SCRIPTS instruction " 1073 1.1 tsutsui "addr=%08x dcmd=%08x dsps=%08x\n", 1074 1.12 tsutsui device_xname(sc->sc_dev), 1075 1.1 tsutsui oosiop_read_4(sc, OOSIOP_DSP) - 8, dcmd, 1076 1.1 tsutsui oosiop_read_4(sc, OOSIOP_DSPS)); 1077 1.1 tsutsui oosiop_reset(sc); 1078 1.1 tsutsui OOSIOP_SCRIPT_SYNC(sc, BUS_DMASYNC_POSTWRITE); 1079 1.1 tsutsui oosiop_load_script(sc); 1080 1.1 tsutsui } 1081 1.1 tsutsui } 1082 1.1 tsutsui 1083 1.1 tsutsui if ((dstat & OOSIOP_DSTAT_DFE) == 0) 1084 1.1 tsutsui oosiop_clear_fifo(sc); 1085 1.1 tsutsui } 1086 1.1 tsutsui 1087 1.1 tsutsui /* SCSI interrupts */ 1088 1.1 tsutsui if (istat & OOSIOP_ISTAT_SIP) { 1089 1.1 tsutsui if (istat & OOSIOP_ISTAT_DIP) 1090 1.1 tsutsui delay(1); 1091 1.1 tsutsui sstat0 = oosiop_read_1(sc, OOSIOP_SSTAT0); 1092 1.1 tsutsui 1093 1.1 tsutsui if (sstat0 & OOSIOP_SSTAT0_M_A) { 1094 1.1 tsutsui /* SCSI phase mismatch during MOVE operation */ 1095 1.1 tsutsui oosiop_phasemismatch(sc); 1096 1.1 tsutsui sc->sc_nextdsp = Ent_phasedispatch; 1097 1.1 tsutsui } 1098 1.1 tsutsui 1099 1.1 tsutsui if (sstat0 & OOSIOP_SSTAT0_STO) { 1100 1.1 tsutsui if (sc->sc_curcb) { 1101 1.1 tsutsui sc->sc_curcb->flags |= CBF_SELTOUT; 1102 1.1 tsutsui oosiop_done(sc, sc->sc_curcb); 1103 1.1 tsutsui } 1104 1.1 tsutsui } 1105 1.1 tsutsui 1106 1.1 tsutsui if (sstat0 & OOSIOP_SSTAT0_SGE) { 1107 1.12 tsutsui printf("%s: SCSI gross error\n", 1108 1.12 tsutsui device_xname(sc->sc_dev)); 1109 1.1 tsutsui oosiop_reset(sc); 1110 1.1 tsutsui } 1111 1.1 tsutsui 1112 1.1 tsutsui if (sstat0 & OOSIOP_SSTAT0_UDC) { 1113 1.1 tsutsui /* XXX */ 1114 1.1 tsutsui if (sc->sc_curcb) { 1115 1.1 tsutsui printf("%s: unexpected disconnect\n", 1116 1.12 tsutsui device_xname(sc->sc_dev)); 1117 1.1 tsutsui oosiop_done(sc, sc->sc_curcb); 1118 1.1 tsutsui } 1119 1.1 tsutsui } 1120 1.1 tsutsui 1121 1.1 tsutsui if (sstat0 & OOSIOP_SSTAT0_RST) 1122 1.1 tsutsui oosiop_reset(sc); 1123 1.1 tsutsui 1124 1.1 tsutsui if (sstat0 & OOSIOP_SSTAT0_PAR) 1125 1.12 tsutsui printf("%s: parity error\n", device_xname(sc->sc_dev)); 1126 1.1 tsutsui } 1127 1.1 tsutsui 1128 1.1 tsutsui /* Start next command if available */ 1129 1.1 tsutsui if (sc->sc_nextdsp == Ent_wait_reselect && TAILQ_FIRST(&sc->sc_cbq)) { 1130 1.1 tsutsui cb = sc->sc_curcb = TAILQ_FIRST(&sc->sc_cbq); 1131 1.1 tsutsui TAILQ_REMOVE(&sc->sc_cbq, cb, chain); 1132 1.1 tsutsui sc->sc_tgt[cb->id].nexus = cb; 1133 1.1 tsutsui 1134 1.1 tsutsui oosiop_setup_dma(sc); 1135 1.1 tsutsui oosiop_setup_syncxfer(sc); 1136 1.1 tsutsui sc->sc_lastcb = cb; 1137 1.1 tsutsui sc->sc_nextdsp = Ent_start_select; 1138 1.1 tsutsui 1139 1.1 tsutsui /* Schedule timeout */ 1140 1.1 tsutsui if ((cb->xs->xs_control & XS_CTL_POLL) == 0) { 1141 1.1 tsutsui timeout = mstohz(cb->xs->timeout) + 1; 1142 1.1 tsutsui callout_reset(&cb->xs->xs_callout, timeout, 1143 1.1 tsutsui oosiop_timeout, cb); 1144 1.1 tsutsui } 1145 1.1 tsutsui } 1146 1.1 tsutsui 1147 1.1 tsutsui sc->sc_active = (sc->sc_nextdsp != Ent_wait_reselect); 1148 1.1 tsutsui 1149 1.1 tsutsui /* Restart script */ 1150 1.1 tsutsui oosiop_write_4(sc, OOSIOP_DSP, sc->sc_nextdsp + sc->sc_scrbase); 1151 1.1 tsutsui 1152 1.1 tsutsui return (1); 1153 1.1 tsutsui } 1154 1.1 tsutsui 1155 1.1 tsutsui static void 1156 1.1 tsutsui oosiop_scriptintr(struct oosiop_softc *sc) 1157 1.1 tsutsui { 1158 1.1 tsutsui struct oosiop_cb *cb; 1159 1.6 tsutsui uint32_t icode; 1160 1.6 tsutsui uint32_t dsp; 1161 1.1 tsutsui int i; 1162 1.6 tsutsui uint8_t sfbr, resid, resmsg; 1163 1.1 tsutsui 1164 1.1 tsutsui cb = sc->sc_curcb; 1165 1.1 tsutsui icode = oosiop_read_4(sc, OOSIOP_DSPS); 1166 1.1 tsutsui 1167 1.1 tsutsui switch (icode) { 1168 1.1 tsutsui case A_int_done: 1169 1.1 tsutsui if (cb) 1170 1.1 tsutsui oosiop_done(sc, cb); 1171 1.1 tsutsui break; 1172 1.1 tsutsui 1173 1.1 tsutsui case A_int_msgin: 1174 1.1 tsutsui if (cb) 1175 1.1 tsutsui oosiop_msgin(sc, cb); 1176 1.1 tsutsui break; 1177 1.1 tsutsui 1178 1.1 tsutsui case A_int_extmsg: 1179 1.1 tsutsui /* extended message in DMA setup request */ 1180 1.1 tsutsui sfbr = oosiop_read_1(sc, OOSIOP_SFBR); 1181 1.1 tsutsui OOSIOP_SCRIPT_SYNC(sc, BUS_DMASYNC_POSTWRITE); 1182 1.1 tsutsui oosiop_fixup_move(sc, Ent_p_extmsgin_move, sfbr, 1183 1.1 tsutsui cb->xferdma->dm_segs[0].ds_addr + 1184 1.1 tsutsui offsetof(struct oosiop_xfer, msgin[2])); 1185 1.1 tsutsui OOSIOP_SCRIPT_SYNC(sc, BUS_DMASYNC_PREWRITE); 1186 1.1 tsutsui sc->sc_nextdsp = Ent_rcv_extmsg; 1187 1.1 tsutsui break; 1188 1.1 tsutsui 1189 1.1 tsutsui case A_int_resel: 1190 1.1 tsutsui /* reselected */ 1191 1.1 tsutsui resid = oosiop_read_1(sc, OOSIOP_SFBR); 1192 1.1 tsutsui for (i = 0; i < OOSIOP_NTGT; i++) 1193 1.1 tsutsui if (resid & (1 << i)) 1194 1.1 tsutsui break; 1195 1.1 tsutsui if (i == OOSIOP_NTGT) { 1196 1.1 tsutsui printf("%s: missing reselection target id\n", 1197 1.12 tsutsui device_xname(sc->sc_dev)); 1198 1.1 tsutsui break; 1199 1.1 tsutsui } 1200 1.1 tsutsui sc->sc_resid = i; 1201 1.1 tsutsui sc->sc_nextdsp = Ent_wait_resel_identify; 1202 1.1 tsutsui 1203 1.1 tsutsui if (cb) { 1204 1.1 tsutsui /* Current command was lost arbitration */ 1205 1.1 tsutsui sc->sc_tgt[cb->id].nexus = NULL; 1206 1.1 tsutsui TAILQ_INSERT_HEAD(&sc->sc_cbq, cb, chain); 1207 1.1 tsutsui sc->sc_curcb = NULL; 1208 1.1 tsutsui } 1209 1.1 tsutsui 1210 1.1 tsutsui break; 1211 1.1 tsutsui 1212 1.1 tsutsui case A_int_res_id: 1213 1.1 tsutsui cb = sc->sc_tgt[sc->sc_resid].nexus; 1214 1.1 tsutsui resmsg = oosiop_read_1(sc, OOSIOP_SFBR); 1215 1.1 tsutsui if (MSG_ISIDENTIFY(resmsg) && cb && 1216 1.1 tsutsui (resmsg & MSG_IDENTIFY_LUNMASK) == cb->lun) { 1217 1.1 tsutsui sc->sc_curcb = cb; 1218 1.1 tsutsui if (cb != sc->sc_lastcb) { 1219 1.1 tsutsui oosiop_setup_dma(sc); 1220 1.1 tsutsui oosiop_setup_syncxfer(sc); 1221 1.1 tsutsui sc->sc_lastcb = cb; 1222 1.1 tsutsui } 1223 1.1 tsutsui if (cb->curdp != cb->savedp) { 1224 1.1 tsutsui cb->curdp = cb->savedp; 1225 1.1 tsutsui oosiop_setup_sgdma(sc, cb); 1226 1.1 tsutsui } 1227 1.1 tsutsui sc->sc_nextdsp = Ent_ack_msgin; 1228 1.1 tsutsui } else { 1229 1.1 tsutsui /* Reselection from invalid target */ 1230 1.1 tsutsui oosiop_reset_bus(sc); 1231 1.1 tsutsui } 1232 1.1 tsutsui break; 1233 1.1 tsutsui 1234 1.1 tsutsui case A_int_resfail: 1235 1.1 tsutsui /* reselect failed */ 1236 1.1 tsutsui break; 1237 1.1 tsutsui 1238 1.1 tsutsui case A_int_disc: 1239 1.1 tsutsui /* disconnected */ 1240 1.1 tsutsui sc->sc_curcb = NULL; 1241 1.1 tsutsui break; 1242 1.1 tsutsui 1243 1.1 tsutsui case A_int_err: 1244 1.1 tsutsui /* generic error */ 1245 1.1 tsutsui dsp = oosiop_read_4(sc, OOSIOP_DSP); 1246 1.12 tsutsui printf("%s: script error at 0x%08x\n", 1247 1.12 tsutsui device_xname(sc->sc_dev), dsp - 8); 1248 1.1 tsutsui sc->sc_curcb = NULL; 1249 1.1 tsutsui break; 1250 1.1 tsutsui 1251 1.1 tsutsui case DATAIN_TRAP: 1252 1.12 tsutsui printf("%s: unexpected datain\n", device_xname(sc->sc_dev)); 1253 1.1 tsutsui /* XXX: need to reset? */ 1254 1.1 tsutsui break; 1255 1.1 tsutsui 1256 1.1 tsutsui case DATAOUT_TRAP: 1257 1.12 tsutsui printf("%s: unexpected dataout\n", device_xname(sc->sc_dev)); 1258 1.1 tsutsui /* XXX: need to reset? */ 1259 1.1 tsutsui break; 1260 1.1 tsutsui 1261 1.1 tsutsui default: 1262 1.12 tsutsui printf("%s: unknown intr code %08x\n", 1263 1.12 tsutsui device_xname(sc->sc_dev), icode); 1264 1.1 tsutsui break; 1265 1.1 tsutsui } 1266 1.1 tsutsui } 1267 1.1 tsutsui 1268 1.1 tsutsui static void 1269 1.1 tsutsui oosiop_msgin(struct oosiop_softc *sc, struct oosiop_cb *cb) 1270 1.1 tsutsui { 1271 1.1 tsutsui struct oosiop_xfer *xfer; 1272 1.1 tsutsui int msgout; 1273 1.1 tsutsui 1274 1.1 tsutsui xfer = cb->xfer; 1275 1.1 tsutsui sc->sc_nextdsp = Ent_ack_msgin; 1276 1.1 tsutsui msgout = 0; 1277 1.1 tsutsui 1278 1.1 tsutsui OOSIOP_XFERMSG_SYNC(sc, cb, 1279 1.1 tsutsui BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 1280 1.1 tsutsui 1281 1.1 tsutsui switch (xfer->msgin[0]) { 1282 1.1 tsutsui case MSG_EXTENDED: 1283 1.1 tsutsui switch (xfer->msgin[2]) { 1284 1.1 tsutsui case MSG_EXT_SDTR: 1285 1.1 tsutsui if (sc->sc_tgt[cb->id].flags & TGTF_WAITSDTR) { 1286 1.1 tsutsui /* Host initiated SDTR */ 1287 1.1 tsutsui sc->sc_tgt[cb->id].flags &= ~TGTF_WAITSDTR; 1288 1.1 tsutsui } else { 1289 1.1 tsutsui /* Target initiated SDTR */ 1290 1.1 tsutsui if (xfer->msgin[3] < sc->sc_minperiod) 1291 1.1 tsutsui xfer->msgin[3] = sc->sc_minperiod; 1292 1.1 tsutsui if (xfer->msgin[4] > OOSIOP_MAX_OFFSET) 1293 1.1 tsutsui xfer->msgin[4] = OOSIOP_MAX_OFFSET; 1294 1.1 tsutsui xfer->msgout[0] = MSG_EXTENDED; 1295 1.1 tsutsui xfer->msgout[1] = MSG_EXT_SDTR_LEN; 1296 1.1 tsutsui xfer->msgout[2] = MSG_EXT_SDTR; 1297 1.1 tsutsui xfer->msgout[3] = xfer->msgin[3]; 1298 1.1 tsutsui xfer->msgout[4] = xfer->msgin[4]; 1299 1.1 tsutsui cb->msgoutlen = 5; 1300 1.1 tsutsui msgout = 1; 1301 1.1 tsutsui } 1302 1.1 tsutsui oosiop_set_syncparam(sc, cb->id, (int)xfer->msgin[3], 1303 1.1 tsutsui (int)xfer->msgin[4]); 1304 1.1 tsutsui oosiop_setup_syncxfer(sc); 1305 1.1 tsutsui break; 1306 1.1 tsutsui 1307 1.1 tsutsui default: 1308 1.1 tsutsui /* Reject message */ 1309 1.1 tsutsui xfer->msgout[0] = MSG_MESSAGE_REJECT; 1310 1.1 tsutsui cb->msgoutlen = 1; 1311 1.1 tsutsui msgout = 1; 1312 1.1 tsutsui break; 1313 1.1 tsutsui } 1314 1.1 tsutsui break; 1315 1.1 tsutsui 1316 1.1 tsutsui case MSG_SAVEDATAPOINTER: 1317 1.1 tsutsui cb->savedp = cb->curdp; 1318 1.1 tsutsui break; 1319 1.1 tsutsui 1320 1.1 tsutsui case MSG_RESTOREPOINTERS: 1321 1.1 tsutsui if (cb->curdp != cb->savedp) { 1322 1.1 tsutsui cb->curdp = cb->savedp; 1323 1.1 tsutsui oosiop_setup_sgdma(sc, cb); 1324 1.1 tsutsui } 1325 1.1 tsutsui break; 1326 1.1 tsutsui 1327 1.1 tsutsui case MSG_MESSAGE_REJECT: 1328 1.1 tsutsui if (sc->sc_tgt[cb->id].flags & TGTF_WAITSDTR) { 1329 1.1 tsutsui /* SDTR rejected */ 1330 1.1 tsutsui sc->sc_tgt[cb->id].flags &= ~TGTF_WAITSDTR; 1331 1.1 tsutsui oosiop_set_syncparam(sc, cb->id, 0, 0); 1332 1.1 tsutsui oosiop_setup_syncxfer(sc); 1333 1.1 tsutsui } 1334 1.1 tsutsui break; 1335 1.1 tsutsui 1336 1.1 tsutsui default: 1337 1.1 tsutsui /* Reject message */ 1338 1.1 tsutsui xfer->msgout[0] = MSG_MESSAGE_REJECT; 1339 1.1 tsutsui cb->msgoutlen = 1; 1340 1.1 tsutsui msgout = 1; 1341 1.1 tsutsui } 1342 1.1 tsutsui 1343 1.1 tsutsui OOSIOP_XFERMSG_SYNC(sc, cb, 1344 1.1 tsutsui BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1345 1.1 tsutsui 1346 1.1 tsutsui if (msgout) { 1347 1.1 tsutsui OOSIOP_SCRIPT_SYNC(sc, BUS_DMASYNC_POSTWRITE); 1348 1.1 tsutsui oosiop_fixup_move(sc, Ent_p_msgout_move, cb->msgoutlen, 1349 1.1 tsutsui cb->xferdma->dm_segs[0].ds_addr + 1350 1.1 tsutsui offsetof(struct oosiop_xfer, msgout[0])); 1351 1.1 tsutsui OOSIOP_SCRIPT_SYNC(sc, BUS_DMASYNC_PREWRITE); 1352 1.1 tsutsui sc->sc_nextdsp = Ent_sendmsg; 1353 1.1 tsutsui } 1354 1.1 tsutsui } 1355