1 1.22 thorpej /* $NetBSD: spifi.c,v 1.22 2021/08/07 16:19:01 thorpej Exp $ */ 2 1.1 tsubai 3 1.1 tsubai /*- 4 1.1 tsubai * Copyright (c) 2000 Tsubai Masanari. All rights reserved. 5 1.1 tsubai * 6 1.1 tsubai * Redistribution and use in source and binary forms, with or without 7 1.1 tsubai * modification, are permitted provided that the following conditions 8 1.1 tsubai * are met: 9 1.1 tsubai * 1. Redistributions of source code must retain the above copyright 10 1.1 tsubai * notice, this list of conditions and the following disclaimer. 11 1.1 tsubai * 2. Redistributions in binary form must reproduce the above copyright 12 1.1 tsubai * notice, this list of conditions and the following disclaimer in the 13 1.1 tsubai * documentation and/or other materials provided with the distribution. 14 1.1 tsubai * 3. The name of the author may not be used to endorse or promote products 15 1.1 tsubai * derived from this software without specific prior written permission. 16 1.1 tsubai * 17 1.1 tsubai * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 1.1 tsubai * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 1.1 tsubai * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 1.1 tsubai * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 1.1 tsubai * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 1.1 tsubai * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 1.1 tsubai * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 1.1 tsubai * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 1.1 tsubai * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 1.1 tsubai * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 1.1 tsubai */ 28 1.11 lukem 29 1.11 lukem #include <sys/cdefs.h> 30 1.22 thorpej __KERNEL_RCSID(0, "$NetBSD: spifi.c,v 1.22 2021/08/07 16:19:01 thorpej Exp $"); 31 1.1 tsubai 32 1.1 tsubai #include <sys/param.h> 33 1.1 tsubai #include <sys/buf.h> 34 1.1 tsubai #include <sys/device.h> 35 1.1 tsubai #include <sys/errno.h> 36 1.1 tsubai #include <sys/kernel.h> 37 1.1 tsubai #include <sys/queue.h> 38 1.1 tsubai #include <sys/systm.h> 39 1.1 tsubai 40 1.1 tsubai #include <uvm/uvm_extern.h> 41 1.1 tsubai 42 1.1 tsubai #include <dev/scsipi/scsi_all.h> 43 1.1 tsubai #include <dev/scsipi/scsi_message.h> 44 1.1 tsubai #include <dev/scsipi/scsipi_all.h> 45 1.1 tsubai #include <dev/scsipi/scsiconf.h> 46 1.1 tsubai 47 1.1 tsubai #include <newsmips/apbus/apbusvar.h> 48 1.1 tsubai #include <newsmips/apbus/spifireg.h> 49 1.1 tsubai #include <newsmips/apbus/dmac3reg.h> 50 1.16 tsutsui #include <newsmips/apbus/dmac3var.h> 51 1.1 tsubai 52 1.1 tsubai #include <machine/adrsmap.h> 53 1.1 tsubai 54 1.1 tsubai /* #define SPIFI_DEBUG */ 55 1.1 tsubai 56 1.1 tsubai #ifdef SPIFI_DEBUG 57 1.1 tsubai # define DPRINTF printf 58 1.1 tsubai #else 59 1.1 tsubai # define DPRINTF while (0) printf 60 1.1 tsubai #endif 61 1.1 tsubai 62 1.1 tsubai struct spifi_scb { 63 1.1 tsubai TAILQ_ENTRY(spifi_scb) chain; 64 1.1 tsubai int flags; 65 1.1 tsubai struct scsipi_xfer *xs; 66 1.12 thorpej struct scsipi_generic cmd; 67 1.1 tsubai int cmdlen; 68 1.1 tsubai int resid; 69 1.1 tsubai vaddr_t daddr; 70 1.16 tsutsui uint8_t target; 71 1.16 tsutsui uint8_t lun; 72 1.16 tsutsui uint8_t lun_targ; 73 1.16 tsutsui uint8_t status; 74 1.1 tsubai }; 75 1.1 tsubai /* scb flags */ 76 1.1 tsubai #define SPIFI_READ 0x80 77 1.1 tsubai #define SPIFI_DMA 0x01 78 1.1 tsubai 79 1.1 tsubai struct spifi_softc { 80 1.16 tsutsui device_t sc_dev; 81 1.2 bouyer struct scsipi_channel sc_channel; 82 1.2 bouyer struct scsipi_adapter sc_adapter; 83 1.1 tsubai 84 1.1 tsubai struct spifi_reg *sc_reg; 85 1.1 tsubai struct spifi_scb *sc_nexus; 86 1.1 tsubai void *sc_dma; /* attached DMA softc */ 87 1.1 tsubai int sc_id; /* my SCSI ID */ 88 1.1 tsubai int sc_msgout; 89 1.16 tsutsui uint8_t sc_omsg[16]; 90 1.1 tsubai struct spifi_scb sc_scb[16]; 91 1.1 tsubai TAILQ_HEAD(, spifi_scb) free_scb; 92 1.1 tsubai TAILQ_HEAD(, spifi_scb) ready_scb; 93 1.1 tsubai }; 94 1.1 tsubai 95 1.1 tsubai #define SPIFI_SYNC_OFFSET_MAX 7 96 1.1 tsubai 97 1.1 tsubai #define SEND_REJECT 1 98 1.1 tsubai #define SEND_IDENTIFY 2 99 1.1 tsubai #define SEND_SDTR 4 100 1.1 tsubai 101 1.1 tsubai #define SPIFI_DATAOUT 0 102 1.1 tsubai #define SPIFI_DATAIN PRS_IO 103 1.1 tsubai #define SPIFI_COMMAND PRS_CD 104 1.1 tsubai #define SPIFI_STATUS (PRS_CD | PRS_IO) 105 1.1 tsubai #define SPIFI_MSGOUT (PRS_MSG | PRS_CD) 106 1.1 tsubai #define SPIFI_MSGIN (PRS_MSG | PRS_CD | PRS_IO) 107 1.1 tsubai 108 1.16 tsutsui int spifi_match(device_t, cfdata_t, void *); 109 1.16 tsutsui void spifi_attach(device_t, device_t, void *); 110 1.1 tsubai 111 1.13 tsutsui void spifi_scsipi_request(struct scsipi_channel *, scsipi_adapter_req_t, 112 1.13 tsutsui void *); 113 1.1 tsubai struct spifi_scb *spifi_get_scb(struct spifi_softc *); 114 1.1 tsubai void spifi_free_scb(struct spifi_softc *, struct spifi_scb *); 115 1.1 tsubai int spifi_poll(struct spifi_softc *); 116 1.1 tsubai void spifi_minphys(struct buf *); 117 1.1 tsubai 118 1.1 tsubai void spifi_sched(struct spifi_softc *); 119 1.1 tsubai int spifi_intr(void *); 120 1.1 tsubai void spifi_pmatch(struct spifi_softc *); 121 1.1 tsubai 122 1.1 tsubai void spifi_select(struct spifi_softc *); 123 1.1 tsubai void spifi_sendmsg(struct spifi_softc *, int); 124 1.1 tsubai void spifi_command(struct spifi_softc *); 125 1.1 tsubai void spifi_data_io(struct spifi_softc *); 126 1.1 tsubai void spifi_status(struct spifi_softc *); 127 1.1 tsubai int spifi_done(struct spifi_softc *); 128 1.1 tsubai void spifi_fifo_drain(struct spifi_softc *); 129 1.1 tsubai void spifi_reset(struct spifi_softc *); 130 1.1 tsubai void spifi_bus_reset(struct spifi_softc *); 131 1.1 tsubai 132 1.1 tsubai static int spifi_read_count(struct spifi_reg *); 133 1.1 tsubai static void spifi_write_count(struct spifi_reg *, int); 134 1.1 tsubai 135 1.1 tsubai #define DMAC3_FASTACCESS(sc) dmac3_misc((sc)->sc_dma, DMAC3_CONF_FASTACCESS) 136 1.1 tsubai #define DMAC3_SLOWACCESS(sc) dmac3_misc((sc)->sc_dma, DMAC3_CONF_SLOWACCESS) 137 1.1 tsubai 138 1.16 tsutsui CFATTACH_DECL_NEW(spifi, sizeof(struct spifi_softc), 139 1.9 thorpej spifi_match, spifi_attach, NULL, NULL); 140 1.1 tsubai 141 1.1 tsubai int 142 1.16 tsutsui spifi_match(device_t parent, cfdata_t cf, void *aux) 143 1.1 tsubai { 144 1.1 tsubai struct apbus_attach_args *apa = aux; 145 1.1 tsubai 146 1.1 tsubai if (strcmp(apa->apa_name, "spifi") == 0) 147 1.1 tsubai return 1; 148 1.1 tsubai 149 1.1 tsubai return 0; 150 1.1 tsubai } 151 1.1 tsubai 152 1.1 tsubai void 153 1.16 tsutsui spifi_attach(device_t parent, device_t self, void *aux) 154 1.1 tsubai { 155 1.16 tsutsui struct spifi_softc *sc = device_private(self); 156 1.1 tsubai struct apbus_attach_args *apa = aux; 157 1.16 tsutsui struct dmac3_softc *dma; 158 1.1 tsubai int intr, i; 159 1.1 tsubai 160 1.16 tsutsui sc->sc_dev = self; 161 1.16 tsutsui 162 1.1 tsubai /* Initialize scbs. */ 163 1.1 tsubai TAILQ_INIT(&sc->free_scb); 164 1.1 tsubai TAILQ_INIT(&sc->ready_scb); 165 1.16 tsutsui for (i = 0; i < __arraycount(sc->sc_scb); i++) 166 1.1 tsubai TAILQ_INSERT_TAIL(&sc->free_scb, &sc->sc_scb[i], chain); 167 1.1 tsubai 168 1.1 tsubai sc->sc_reg = (struct spifi_reg *)apa->apa_hwbase; 169 1.1 tsubai sc->sc_id = 7; /* XXX */ 170 1.1 tsubai 171 1.1 tsubai /* Find my dmac3. */ 172 1.1 tsubai dma = dmac3_link(apa->apa_ctlnum); 173 1.1 tsubai if (dma == NULL) { 174 1.16 tsutsui aprint_error(": cannot find slave dmac\n"); 175 1.1 tsubai return; 176 1.1 tsubai } 177 1.1 tsubai sc->sc_dma = dma; 178 1.1 tsubai 179 1.16 tsutsui aprint_normal(" slot%d addr 0x%lx", apa->apa_slotno, apa->apa_hwbase); 180 1.16 tsutsui aprint_normal(": SCSI ID = %d, using %s\n", 181 1.16 tsutsui sc->sc_id, device_xname(dma->sc_dev)); 182 1.1 tsubai 183 1.1 tsubai dmac3_reset(sc->sc_dma); 184 1.1 tsubai 185 1.1 tsubai DMAC3_SLOWACCESS(sc); 186 1.1 tsubai spifi_reset(sc); 187 1.1 tsubai DMAC3_FASTACCESS(sc); 188 1.1 tsubai 189 1.16 tsutsui sc->sc_adapter.adapt_dev = self; 190 1.2 bouyer sc->sc_adapter.adapt_nchannels = 1; 191 1.2 bouyer sc->sc_adapter.adapt_openings = 7; 192 1.2 bouyer sc->sc_adapter.adapt_max_periph = 1; 193 1.2 bouyer sc->sc_adapter.adapt_ioctl = NULL; 194 1.2 bouyer sc->sc_adapter.adapt_minphys = minphys; 195 1.2 bouyer sc->sc_adapter.adapt_request = spifi_scsipi_request; 196 1.2 bouyer 197 1.2 bouyer memset(&sc->sc_channel, 0, sizeof(sc->sc_channel)); 198 1.2 bouyer sc->sc_channel.chan_adapter = &sc->sc_adapter; 199 1.2 bouyer sc->sc_channel.chan_bustype = &scsi_bustype; 200 1.2 bouyer sc->sc_channel.chan_channel = 0; 201 1.2 bouyer sc->sc_channel.chan_ntargets = 8; 202 1.2 bouyer sc->sc_channel.chan_nluns = 8; 203 1.2 bouyer sc->sc_channel.chan_id = sc->sc_id; 204 1.1 tsubai 205 1.1 tsubai if (apa->apa_slotno == 0) 206 1.20 tsutsui intr = NEWS5000_INT0_DMAC; /* XXX news4000 */ 207 1.1 tsubai else 208 1.1 tsubai intr = SLOTTOMASK(apa->apa_slotno); 209 1.19 tsutsui apbus_intr_establish(0, intr, 0, spifi_intr, sc, device_xname(self), 210 1.1 tsubai apa->apa_ctlnum); 211 1.1 tsubai 212 1.22 thorpej config_found(self, &sc->sc_channel, scsiprint, CFARGS_NONE); 213 1.1 tsubai } 214 1.1 tsubai 215 1.2 bouyer void 216 1.13 tsutsui spifi_scsipi_request(struct scsipi_channel *chan, scsipi_adapter_req_t req, 217 1.13 tsutsui void *arg) 218 1.2 bouyer { 219 1.1 tsubai struct scsipi_xfer *xs; 220 1.2 bouyer struct scsipi_periph *periph; 221 1.16 tsutsui struct spifi_softc *sc = device_private(chan->chan_adapter->adapt_dev); 222 1.1 tsubai struct spifi_scb *scb; 223 1.1 tsubai u_int flags; 224 1.1 tsubai int s; 225 1.1 tsubai 226 1.2 bouyer switch (req) { 227 1.2 bouyer case ADAPTER_REQ_RUN_XFER: 228 1.2 bouyer xs = arg; 229 1.2 bouyer periph = xs->xs_periph; 230 1.2 bouyer 231 1.2 bouyer DPRINTF("spifi_scsi_cmd\n"); 232 1.2 bouyer 233 1.2 bouyer flags = xs->xs_control; 234 1.2 bouyer 235 1.2 bouyer scb = spifi_get_scb(sc); 236 1.2 bouyer if (scb == NULL) { 237 1.7 provos panic("spifi_scsipi_request: no scb"); 238 1.2 bouyer } 239 1.1 tsubai 240 1.2 bouyer scb->xs = xs; 241 1.2 bouyer scb->flags = 0; 242 1.2 bouyer scb->status = 0; 243 1.2 bouyer scb->daddr = (vaddr_t)xs->data; 244 1.2 bouyer scb->resid = xs->datalen; 245 1.13 tsutsui memcpy(&scb->cmd, xs->cmd, xs->cmdlen); 246 1.2 bouyer scb->cmdlen = xs->cmdlen; 247 1.2 bouyer 248 1.2 bouyer scb->target = periph->periph_target; 249 1.2 bouyer scb->lun = periph->periph_lun; 250 1.2 bouyer scb->lun_targ = scb->target | (scb->lun << 3); 251 1.2 bouyer 252 1.2 bouyer if (flags & XS_CTL_DATA_IN) 253 1.2 bouyer scb->flags |= SPIFI_READ; 254 1.2 bouyer 255 1.2 bouyer s = splbio(); 256 1.2 bouyer 257 1.2 bouyer TAILQ_INSERT_TAIL(&sc->ready_scb, scb, chain); 258 1.2 bouyer 259 1.2 bouyer if (sc->sc_nexus == NULL) /* IDLE */ 260 1.2 bouyer spifi_sched(sc); 261 1.2 bouyer 262 1.2 bouyer splx(s); 263 1.2 bouyer 264 1.2 bouyer if (flags & XS_CTL_POLL) { 265 1.2 bouyer if (spifi_poll(sc)) { 266 1.2 bouyer printf("spifi: timeout\n"); 267 1.2 bouyer if (spifi_poll(sc)) 268 1.2 bouyer printf("spifi: timeout again\n"); 269 1.2 bouyer } 270 1.2 bouyer } 271 1.2 bouyer return; 272 1.2 bouyer case ADAPTER_REQ_GROW_RESOURCES: 273 1.2 bouyer /* XXX Not supported. */ 274 1.2 bouyer return; 275 1.2 bouyer case ADAPTER_REQ_SET_XFER_MODE: 276 1.2 bouyer /* XXX Not supported. */ 277 1.2 bouyer return; 278 1.1 tsubai } 279 1.1 tsubai } 280 1.1 tsubai 281 1.1 tsubai struct spifi_scb * 282 1.13 tsutsui spifi_get_scb(struct spifi_softc *sc) 283 1.1 tsubai { 284 1.1 tsubai struct spifi_scb *scb; 285 1.1 tsubai int s; 286 1.1 tsubai 287 1.1 tsubai s = splbio(); 288 1.16 tsutsui scb = TAILQ_FIRST(&sc->free_scb); 289 1.1 tsubai if (scb) 290 1.1 tsubai TAILQ_REMOVE(&sc->free_scb, scb, chain); 291 1.1 tsubai splx(s); 292 1.1 tsubai 293 1.1 tsubai return scb; 294 1.1 tsubai } 295 1.1 tsubai 296 1.1 tsubai void 297 1.13 tsutsui spifi_free_scb(struct spifi_softc *sc, struct spifi_scb *scb) 298 1.1 tsubai { 299 1.1 tsubai int s; 300 1.1 tsubai 301 1.1 tsubai s = splbio(); 302 1.1 tsubai TAILQ_INSERT_HEAD(&sc->free_scb, scb, chain); 303 1.1 tsubai splx(s); 304 1.1 tsubai } 305 1.1 tsubai 306 1.1 tsubai int 307 1.13 tsutsui spifi_poll(struct spifi_softc *sc) 308 1.1 tsubai { 309 1.1 tsubai struct spifi_scb *scb = sc->sc_nexus; 310 1.1 tsubai struct scsipi_xfer *xs; 311 1.1 tsubai int count; 312 1.1 tsubai 313 1.16 tsutsui printf("%s: not implemented yet\n", __func__); 314 1.1 tsubai delay(10000); 315 1.4 tsubai scb->status = SCSI_OK; 316 1.4 tsubai scb->resid = 0; 317 1.4 tsubai spifi_done(sc); 318 1.1 tsubai return 0; 319 1.1 tsubai 320 1.1 tsubai if (xs == NULL) 321 1.1 tsubai return 0; 322 1.1 tsubai 323 1.1 tsubai xs = scb->xs; 324 1.1 tsubai count = xs->timeout; 325 1.1 tsubai 326 1.1 tsubai while (count > 0) { 327 1.1 tsubai if (dmac3_intr(sc->sc_dma) != 0) 328 1.1 tsubai spifi_intr(sc); 329 1.1 tsubai 330 1.1 tsubai if (xs->xs_status & XS_STS_DONE) 331 1.1 tsubai return 0; 332 1.1 tsubai DELAY(1000); 333 1.1 tsubai count--; 334 1.1 tsubai }; 335 1.1 tsubai return 1; 336 1.1 tsubai } 337 1.1 tsubai 338 1.1 tsubai void 339 1.13 tsutsui spifi_minphys(struct buf *bp) 340 1.1 tsubai { 341 1.13 tsutsui 342 1.13 tsutsui if (bp->b_bcount > 64 * 1024) 343 1.13 tsutsui bp->b_bcount = 64 * 1024; 344 1.1 tsubai 345 1.1 tsubai minphys(bp); 346 1.1 tsubai } 347 1.1 tsubai 348 1.1 tsubai void 349 1.13 tsutsui spifi_sched(struct spifi_softc *sc) 350 1.1 tsubai { 351 1.1 tsubai struct spifi_scb *scb; 352 1.1 tsubai 353 1.16 tsutsui scb = TAILQ_FIRST(&sc->ready_scb); 354 1.1 tsubai start: 355 1.1 tsubai if (scb == NULL || sc->sc_nexus != NULL) 356 1.1 tsubai return; 357 1.13 tsutsui #if 0 358 1.1 tsubai if (sc->sc_targets[scb->target] & (1 << scb->lun)) 359 1.1 tsubai goto next; 360 1.13 tsutsui #endif 361 1.1 tsubai TAILQ_REMOVE(&sc->ready_scb, scb, chain); 362 1.1 tsubai 363 1.1 tsubai #ifdef SPIFI_DEBUG 364 1.1 tsubai { 365 1.1 tsubai int i; 366 1.1 tsubai 367 1.1 tsubai printf("spifi_sched: ID:LUN = %d:%d, ", scb->target, scb->lun); 368 1.1 tsubai printf("cmd = 0x%x", scb->cmd.opcode); 369 1.1 tsubai for (i = 0; i < 5; i++) 370 1.1 tsubai printf(" 0x%x", scb->cmd.bytes[i]); 371 1.1 tsubai printf("\n"); 372 1.1 tsubai } 373 1.1 tsubai #endif 374 1.1 tsubai 375 1.1 tsubai DMAC3_SLOWACCESS(sc); 376 1.1 tsubai sc->sc_nexus = scb; 377 1.1 tsubai spifi_select(sc); 378 1.1 tsubai DMAC3_FASTACCESS(sc); 379 1.1 tsubai 380 1.1 tsubai scb = scb->chain.tqe_next; 381 1.1 tsubai goto start; 382 1.1 tsubai } 383 1.1 tsubai 384 1.1 tsubai static inline int 385 1.13 tsutsui spifi_read_count(struct spifi_reg *reg) 386 1.1 tsubai { 387 1.1 tsubai int count; 388 1.1 tsubai 389 1.6 tsutsui count = (reg->count_hi & 0xff) << 16 | 390 1.6 tsutsui (reg->count_mid & 0xff) << 8 | 391 1.1 tsubai (reg->count_low & 0xff); 392 1.1 tsubai return count; 393 1.1 tsubai } 394 1.1 tsubai 395 1.1 tsubai static inline void 396 1.13 tsutsui spifi_write_count(struct spifi_reg *reg, int count) 397 1.1 tsubai { 398 1.13 tsutsui 399 1.1 tsubai reg->count_hi = count >> 16; 400 1.1 tsubai reg->count_mid = count >> 8; 401 1.1 tsubai reg->count_low = count; 402 1.1 tsubai } 403 1.1 tsubai 404 1.1 tsubai 405 1.1 tsubai #ifdef SPIFI_DEBUG 406 1.16 tsutsui static const char scsi_phase_name[][8] = { 407 1.1 tsubai "DATAOUT", "DATAIN", "COMMAND", "STATUS", 408 1.1 tsubai "", "", "MSGOUT", "MSGIN" 409 1.1 tsubai }; 410 1.1 tsubai #endif 411 1.1 tsubai 412 1.1 tsubai int 413 1.13 tsutsui spifi_intr(void *v) 414 1.1 tsubai { 415 1.1 tsubai struct spifi_softc *sc = v; 416 1.1 tsubai struct spifi_reg *reg = sc->sc_reg; 417 1.1 tsubai int intr, state, icond; 418 1.1 tsubai struct spifi_scb *scb; 419 1.1 tsubai struct scsipi_xfer *xs; 420 1.1 tsubai #ifdef SPIFI_DEBUG 421 1.1 tsubai char bitmask[64]; 422 1.1 tsubai #endif 423 1.1 tsubai 424 1.1 tsubai switch (dmac3_intr(sc->sc_dma)) { 425 1.1 tsubai case 0: 426 1.10 wiz DPRINTF("spurious DMA intr\n"); 427 1.1 tsubai return 0; 428 1.1 tsubai case -1: 429 1.1 tsubai printf("DMAC parity error, data PAD\n"); 430 1.1 tsubai 431 1.1 tsubai DMAC3_SLOWACCESS(sc); 432 1.1 tsubai reg->prcmd = PRC_TRPAD; 433 1.1 tsubai DMAC3_FASTACCESS(sc); 434 1.1 tsubai return 1; 435 1.1 tsubai 436 1.1 tsubai default: 437 1.1 tsubai break; 438 1.1 tsubai } 439 1.1 tsubai DMAC3_SLOWACCESS(sc); 440 1.1 tsubai 441 1.1 tsubai intr = reg->intr & 0xff; 442 1.1 tsubai if (intr == 0) { 443 1.1 tsubai DMAC3_FASTACCESS(sc); 444 1.5 wiz DPRINTF("spurious intr (not me)\n"); 445 1.1 tsubai return 0; 446 1.1 tsubai } 447 1.1 tsubai 448 1.1 tsubai scb = sc->sc_nexus; 449 1.1 tsubai xs = scb->xs; 450 1.1 tsubai state = reg->spstat; 451 1.1 tsubai icond = reg->icond; 452 1.1 tsubai 453 1.1 tsubai /* clear interrupt */ 454 1.1 tsubai reg->intr = ~intr; 455 1.1 tsubai 456 1.1 tsubai #ifdef SPIFI_DEBUG 457 1.17 christos snprintb(bitmask, sizeof bitmask, INTR_BITMASK, intr); 458 1.18 msaitoh printf("spifi_intr intr = %s (%s), ", bitmask, 459 1.1 tsubai scsi_phase_name[(reg->prstat >> 3) & 7]); 460 1.1 tsubai printf("state = 0x%x, icond = 0x%x\n", state, icond); 461 1.1 tsubai #endif 462 1.1 tsubai 463 1.1 tsubai if (intr & INTR_FCOMP) { 464 1.1 tsubai spifi_fifo_drain(sc); 465 1.1 tsubai scb->status = reg->cmbuf[scb->target].status; 466 1.1 tsubai scb->resid = spifi_read_count(reg); 467 1.1 tsubai 468 1.1 tsubai DPRINTF("datalen = %d, resid = %d, status = 0x%x\n", 469 1.1 tsubai xs->datalen, scb->resid, scb->status); 470 1.1 tsubai DPRINTF("msg = 0x%x\n", reg->cmbuf[sc->sc_id].cdb[0]); 471 1.1 tsubai 472 1.1 tsubai DMAC3_FASTACCESS(sc); 473 1.1 tsubai spifi_done(sc); 474 1.1 tsubai return 1; 475 1.1 tsubai } 476 1.1 tsubai if (intr & INTR_DISCON) 477 1.16 tsutsui panic("%s: disconnect", __func__); 478 1.1 tsubai 479 1.1 tsubai if (intr & INTR_TIMEO) { 480 1.1 tsubai xs->error = XS_SELTIMEOUT; 481 1.1 tsubai DMAC3_FASTACCESS(sc); 482 1.1 tsubai spifi_done(sc); 483 1.1 tsubai return 1; 484 1.1 tsubai } 485 1.1 tsubai if (intr & INTR_BSRQ) { 486 1.1 tsubai if (scb == NULL) 487 1.16 tsutsui panic("%s: reconnect?", __func__); 488 1.1 tsubai 489 1.1 tsubai if (intr & INTR_PERR) { 490 1.16 tsutsui printf("%s: %d:%d parity error\n", 491 1.16 tsutsui device_xname(sc->sc_dev), 492 1.16 tsutsui scb->target, scb->lun); 493 1.1 tsubai 494 1.1 tsubai /* XXX reset */ 495 1.1 tsubai xs->error = XS_DRIVER_STUFFUP; 496 1.1 tsubai spifi_done(sc); 497 1.1 tsubai return 1; 498 1.1 tsubai } 499 1.1 tsubai 500 1.1 tsubai if (state >> 4 == SPS_MSGIN && icond == ICOND_NXTREQ) 501 1.16 tsutsui panic("%s: NXTREQ", __func__); 502 1.1 tsubai if (reg->fifoctrl & FIFOC_RQOVRN) 503 1.16 tsutsui panic("%s: RQOVRN", __func__); 504 1.1 tsubai if (icond == ICOND_UXPHASEZ) 505 1.1 tsubai panic("ICOND_UXPHASEZ"); 506 1.1 tsubai 507 1.1 tsubai if ((icond & 0x0f) == ICOND_ADATAOFF) { 508 1.1 tsubai spifi_data_io(sc); 509 1.1 tsubai goto done; 510 1.1 tsubai } 511 1.1 tsubai if ((icond & 0xf0) == ICOND_UBF) { 512 1.1 tsubai reg->exstat = reg->exstat & ~EXS_UBF; 513 1.1 tsubai spifi_pmatch(sc); 514 1.1 tsubai goto done; 515 1.1 tsubai } 516 1.1 tsubai 517 1.1 tsubai /* 518 1.1 tsubai * XXX Work around the SPIFI bug that interrupts during 519 1.1 tsubai * XXX dataout phase. 520 1.1 tsubai */ 521 1.1 tsubai if (state == ((SPS_DATAOUT << 4) | SPS_INTR) && 522 1.1 tsubai (reg->prstat & PRS_PHASE) == SPIFI_DATAOUT) { 523 1.1 tsubai reg->prcmd = PRC_DATAOUT; 524 1.1 tsubai goto done; 525 1.1 tsubai } 526 1.1 tsubai if ((reg->prstat & PRS_Z) == 0) { 527 1.1 tsubai spifi_pmatch(sc); 528 1.1 tsubai goto done; 529 1.1 tsubai } 530 1.1 tsubai 531 1.16 tsutsui panic("%s: unknown intr state", __func__); 532 1.1 tsubai } 533 1.1 tsubai 534 1.1 tsubai done: 535 1.1 tsubai DMAC3_FASTACCESS(sc); 536 1.1 tsubai return 1; 537 1.1 tsubai } 538 1.1 tsubai 539 1.1 tsubai void 540 1.13 tsutsui spifi_pmatch(struct spifi_softc *sc) 541 1.1 tsubai { 542 1.1 tsubai struct spifi_reg *reg = sc->sc_reg; 543 1.1 tsubai int phase; 544 1.1 tsubai 545 1.1 tsubai phase = (reg->prstat & PRS_PHASE); 546 1.1 tsubai 547 1.1 tsubai #ifdef SPIFI_DEBUG 548 1.16 tsutsui printf("%s (%s)\n", __func__, scsi_phase_name[phase >> 3]); 549 1.1 tsubai #endif 550 1.1 tsubai 551 1.1 tsubai switch (phase) { 552 1.1 tsubai 553 1.1 tsubai case SPIFI_COMMAND: 554 1.1 tsubai spifi_command(sc); 555 1.1 tsubai break; 556 1.1 tsubai case SPIFI_DATAIN: 557 1.1 tsubai case SPIFI_DATAOUT: 558 1.1 tsubai spifi_data_io(sc); 559 1.1 tsubai break; 560 1.1 tsubai case SPIFI_STATUS: 561 1.1 tsubai spifi_status(sc); 562 1.1 tsubai break; 563 1.1 tsubai 564 1.1 tsubai case SPIFI_MSGIN: /* XXX */ 565 1.1 tsubai case SPIFI_MSGOUT: /* XXX */ 566 1.1 tsubai default: 567 1.1 tsubai printf("spifi: unknown phase %d\n", phase); 568 1.1 tsubai } 569 1.1 tsubai } 570 1.1 tsubai 571 1.1 tsubai void 572 1.13 tsutsui spifi_select(struct spifi_softc *sc) 573 1.1 tsubai { 574 1.1 tsubai struct spifi_reg *reg = sc->sc_reg; 575 1.1 tsubai struct spifi_scb *scb = sc->sc_nexus; 576 1.1 tsubai int sel; 577 1.1 tsubai 578 1.1 tsubai #if 0 579 1.1 tsubai if (reg->loopdata || reg->intr) 580 1.1 tsubai return; 581 1.1 tsubai #endif 582 1.1 tsubai 583 1.1 tsubai if (scb == NULL) { 584 1.16 tsutsui printf("%s: spifi_select: NULL nexus\n", 585 1.16 tsutsui device_xname(sc->sc_dev)); 586 1.1 tsubai return; 587 1.1 tsubai } 588 1.1 tsubai 589 1.1 tsubai reg->exctrl = EXC_IPLOCK; 590 1.1 tsubai 591 1.1 tsubai dmac3_reset(sc->sc_dma); 592 1.1 tsubai sel = scb->target << 4 | SEL_ISTART | SEL_IRESELEN | SEL_WATN; 593 1.1 tsubai spifi_sendmsg(sc, SEND_IDENTIFY); 594 1.1 tsubai reg->select = sel; 595 1.1 tsubai } 596 1.1 tsubai 597 1.1 tsubai void 598 1.13 tsutsui spifi_sendmsg(struct spifi_softc *sc, int msg) 599 1.1 tsubai { 600 1.1 tsubai struct spifi_scb *scb = sc->sc_nexus; 601 1.1 tsubai /* struct mesh_tinfo *ti; */ 602 1.1 tsubai int lun, len, i; 603 1.1 tsubai 604 1.1 tsubai int id = sc->sc_id; 605 1.1 tsubai struct spifi_reg *reg = sc->sc_reg; 606 1.1 tsubai 607 1.16 tsutsui DPRINTF("%s: sending", __func__); 608 1.1 tsubai sc->sc_msgout = msg; 609 1.1 tsubai len = 0; 610 1.1 tsubai 611 1.1 tsubai if (msg & SEND_REJECT) { 612 1.1 tsubai DPRINTF(" REJECT"); 613 1.1 tsubai sc->sc_omsg[len++] = MSG_MESSAGE_REJECT; 614 1.1 tsubai } 615 1.1 tsubai if (msg & SEND_IDENTIFY) { 616 1.1 tsubai DPRINTF(" IDENTIFY"); 617 1.2 bouyer lun = scb->xs->xs_periph->periph_lun; 618 1.1 tsubai sc->sc_omsg[len++] = MSG_IDENTIFY(lun, 0); 619 1.1 tsubai } 620 1.1 tsubai if (msg & SEND_SDTR) { 621 1.1 tsubai DPRINTF(" SDTR"); 622 1.1 tsubai #if 0 623 1.1 tsubai ti = &sc->sc_tinfo[scb->target]; 624 1.1 tsubai sc->sc_omsg[len++] = MSG_EXTENDED; 625 1.1 tsubai sc->sc_omsg[len++] = 3; 626 1.1 tsubai sc->sc_omsg[len++] = MSG_EXT_SDTR; 627 1.1 tsubai sc->sc_omsg[len++] = ti->period; 628 1.1 tsubai sc->sc_omsg[len++] = ti->offset; 629 1.1 tsubai #endif 630 1.1 tsubai } 631 1.1 tsubai DPRINTF("\n"); 632 1.1 tsubai 633 1.1 tsubai reg->cmlen = CML_AMSG_EN | len; 634 1.1 tsubai for (i = 0; i < len; i++) 635 1.1 tsubai reg->cmbuf[id].cdb[i] = sc->sc_omsg[i]; 636 1.1 tsubai } 637 1.13 tsutsui 638 1.1 tsubai void 639 1.1 tsubai spifi_command(struct spifi_softc *sc) 640 1.1 tsubai { 641 1.1 tsubai struct spifi_scb *scb = sc->sc_nexus; 642 1.1 tsubai struct spifi_reg *reg = sc->sc_reg; 643 1.1 tsubai int len = scb->cmdlen; 644 1.16 tsutsui uint8_t *cmdp = (uint8_t *)&scb->cmd; 645 1.1 tsubai int i; 646 1.1 tsubai 647 1.16 tsutsui DPRINTF("%s\n", __func__); 648 1.1 tsubai 649 1.1 tsubai reg->cmdpage = scb->lun_targ; 650 1.1 tsubai 651 1.1 tsubai if (reg->init_status & IST_ACK) { 652 1.1 tsubai /* Negate ACK. */ 653 1.1 tsubai reg->prcmd = PRC_NJMP | PRC_CLRACK | PRC_COMMAND; 654 1.1 tsubai reg->prcmd = PRC_NJMP | PRC_COMMAND; 655 1.1 tsubai } 656 1.1 tsubai 657 1.1 tsubai reg->cmlen = CML_AMSG_EN | len; 658 1.1 tsubai 659 1.1 tsubai for (i = 0; i < len; i++) 660 1.1 tsubai reg->cmbuf[sc->sc_id].cdb[i] = *cmdp++; 661 1.1 tsubai 662 1.1 tsubai reg->prcmd = PRC_COMMAND; 663 1.1 tsubai } 664 1.1 tsubai 665 1.1 tsubai void 666 1.1 tsubai spifi_data_io(struct spifi_softc *sc) 667 1.1 tsubai { 668 1.1 tsubai struct spifi_scb *scb = sc->sc_nexus; 669 1.1 tsubai struct spifi_reg *reg = sc->sc_reg; 670 1.1 tsubai int phase; 671 1.1 tsubai 672 1.16 tsutsui DPRINTF("%s\n", __func__); 673 1.1 tsubai 674 1.1 tsubai phase = reg->prstat & PRS_PHASE; 675 1.1 tsubai dmac3_reset(sc->sc_dma); 676 1.1 tsubai 677 1.1 tsubai spifi_write_count(reg, scb->resid); 678 1.1 tsubai reg->cmlen = CML_AMSG_EN | 1; 679 1.1 tsubai reg->data_xfer = 0; 680 1.1 tsubai 681 1.1 tsubai scb->flags |= SPIFI_DMA; 682 1.1 tsubai if (phase == SPIFI_DATAIN) { 683 1.1 tsubai if (reg->fifoctrl & FIFOC_SSTKACT) { 684 1.1 tsubai /* 685 1.1 tsubai * Clear FIFO and load the contents of synchronous 686 1.1 tsubai * stack into the FIFO. 687 1.1 tsubai */ 688 1.1 tsubai reg->fifoctrl = FIFOC_CLREVEN; 689 1.1 tsubai reg->fifoctrl = FIFOC_LOAD; 690 1.1 tsubai } 691 1.1 tsubai reg->autodata = ADATA_IN | scb->lun_targ; 692 1.1 tsubai dmac3_start(sc->sc_dma, scb->daddr, scb->resid, DMAC3_CSR_RECV); 693 1.1 tsubai reg->prcmd = PRC_DATAIN; 694 1.1 tsubai } else { 695 1.1 tsubai reg->fifoctrl = FIFOC_CLREVEN; 696 1.1 tsubai reg->autodata = scb->lun_targ; 697 1.1 tsubai dmac3_start(sc->sc_dma, scb->daddr, scb->resid, DMAC3_CSR_SEND); 698 1.1 tsubai reg->prcmd = PRC_DATAOUT; 699 1.1 tsubai } 700 1.1 tsubai } 701 1.1 tsubai 702 1.1 tsubai void 703 1.1 tsubai spifi_status(struct spifi_softc *sc) 704 1.1 tsubai { 705 1.1 tsubai struct spifi_reg *reg = sc->sc_reg; 706 1.1 tsubai 707 1.16 tsutsui DPRINTF("%s\n", __func__); 708 1.1 tsubai spifi_fifo_drain(sc); 709 1.1 tsubai reg->cmlen = CML_AMSG_EN | 1; 710 1.1 tsubai reg->prcmd = PRC_STATUS; 711 1.1 tsubai } 712 1.1 tsubai 713 1.1 tsubai int 714 1.13 tsutsui spifi_done(struct spifi_softc *sc) 715 1.1 tsubai { 716 1.1 tsubai struct spifi_scb *scb = sc->sc_nexus; 717 1.1 tsubai struct scsipi_xfer *xs = scb->xs; 718 1.1 tsubai 719 1.16 tsutsui DPRINTF("%s\n", __func__); 720 1.1 tsubai 721 1.2 bouyer xs->status = scb->status; 722 1.2 bouyer if (xs->status == SCSI_CHECK) { 723 1.16 tsutsui DPRINTF("%s: CHECK CONDITION\n", __func__); 724 1.2 bouyer if (xs->error == XS_NOERROR) 725 1.2 bouyer xs->error = XS_BUSY; 726 1.2 bouyer } 727 1.1 tsubai 728 1.1 tsubai xs->resid = scb->resid; 729 1.1 tsubai 730 1.1 tsubai scsipi_done(xs); 731 1.1 tsubai spifi_free_scb(sc, scb); 732 1.1 tsubai 733 1.1 tsubai sc->sc_nexus = NULL; 734 1.1 tsubai spifi_sched(sc); 735 1.1 tsubai 736 1.15 thorpej return false; 737 1.1 tsubai } 738 1.1 tsubai 739 1.1 tsubai void 740 1.13 tsutsui spifi_fifo_drain(struct spifi_softc *sc) 741 1.1 tsubai { 742 1.1 tsubai struct spifi_scb *scb = sc->sc_nexus; 743 1.1 tsubai struct spifi_reg *reg = sc->sc_reg; 744 1.1 tsubai int fifoctrl, fifo_count; 745 1.1 tsubai 746 1.16 tsutsui DPRINTF("%s\n", __func__); 747 1.1 tsubai 748 1.1 tsubai if ((scb->flags & SPIFI_READ) == 0) 749 1.1 tsubai return; 750 1.1 tsubai 751 1.1 tsubai fifoctrl = reg->fifoctrl; 752 1.1 tsubai if (fifoctrl & FIFOC_SSTKACT) 753 1.1 tsubai return; 754 1.1 tsubai 755 1.1 tsubai fifo_count = 8 - (fifoctrl & FIFOC_FSLOT); 756 1.1 tsubai if (fifo_count > 0 && (scb->flags & SPIFI_DMA)) { 757 1.1 tsubai /* Flush data still in FIFO. */ 758 1.1 tsubai reg->fifoctrl = FIFOC_FLUSH; 759 1.1 tsubai return; 760 1.1 tsubai } 761 1.1 tsubai 762 1.1 tsubai reg->fifoctrl = FIFOC_CLREVEN; 763 1.1 tsubai } 764 1.1 tsubai 765 1.1 tsubai void 766 1.13 tsutsui spifi_reset(struct spifi_softc *sc) 767 1.1 tsubai { 768 1.1 tsubai struct spifi_reg *reg = sc->sc_reg; 769 1.1 tsubai int id = sc->sc_id; 770 1.1 tsubai 771 1.16 tsutsui DPRINTF("%s\n", __func__); 772 1.1 tsubai 773 1.1 tsubai reg->auxctrl = AUXCTRL_SRST; 774 1.1 tsubai reg->auxctrl = AUXCTRL_CRST; 775 1.1 tsubai 776 1.1 tsubai dmac3_reset(sc->sc_dma); 777 1.1 tsubai 778 1.1 tsubai reg->auxctrl = AUXCTRL_SRST; 779 1.1 tsubai reg->auxctrl = AUXCTRL_CRST; 780 1.1 tsubai reg->auxctrl = AUXCTRL_DMAEDGE; 781 1.1 tsubai 782 1.1 tsubai /* Mask (only) target mode interrupts. */ 783 1.1 tsubai reg->imask = INTR_TGSEL | INTR_COMRECV; 784 1.1 tsubai 785 1.1 tsubai reg->config = CONFIG_DMABURST | CONFIG_PCHKEN | CONFIG_PGENEN | id; 786 1.1 tsubai reg->fastwide = FAST_FASTEN; 787 1.1 tsubai reg->prctrl = 0; 788 1.1 tsubai reg->loopctrl = 0; 789 1.1 tsubai 790 1.1 tsubai /* Enable automatic status input except the initiator. */ 791 1.1 tsubai reg->autostat = ~(1 << id); 792 1.1 tsubai 793 1.1 tsubai reg->fifoctrl = FIFOC_CLREVEN; 794 1.1 tsubai spifi_write_count(reg, 0); 795 1.1 tsubai 796 1.1 tsubai /* Flush write buffer. */ 797 1.1 tsubai (void)reg->spstat; 798 1.1 tsubai } 799 1.1 tsubai 800 1.1 tsubai void 801 1.13 tsutsui spifi_bus_reset(struct spifi_softc *sc) 802 1.1 tsubai { 803 1.1 tsubai struct spifi_reg *reg = sc->sc_reg; 804 1.1 tsubai 805 1.16 tsutsui printf("%s: bus reset\n", device_xname(sc->sc_dev)); 806 1.1 tsubai 807 1.1 tsubai sc->sc_nexus = NULL; 808 1.1 tsubai 809 1.1 tsubai reg->auxctrl = AUXCTRL_SETRST; 810 1.1 tsubai delay(100); 811 1.1 tsubai reg->auxctrl = 0; 812 1.1 tsubai } 813 1.1 tsubai 814 1.1 tsubai #if 0 815 1.16 tsutsui static uint8_t spifi_sync_period[] = { 816 1.1 tsubai /* 0 1 2 3 4 5 6 7 8 9 10 11 */ 817 1.1 tsubai 137, 125, 112, 100, 87, 75, 62, 50, 43, 37, 31, 25 818 1.1 tsubai }; 819 1.1 tsubai 820 1.1 tsubai void 821 1.13 tsutsui spifi_setsync(struct spifi_softc *sc, struct spifi_tinfo *ti) 822 1.1 tsubai { 823 1.13 tsutsui 824 1.1 tsubai if ((ti->flags & T_SYNCMODE) == 0) 825 1.1 tsubai reg->data_xfer = 0; 826 1.1 tsubai else { 827 1.16 tsutsui uint8_t period = ti->period; 828 1.16 tsutsui uint8_t offset = ti->offset; 829 1.1 tsubai int v; 830 1.1 tsubai 831 1.1 tsubai for (v = sizeof(spifi_sync_period) - 1; v >= 0; v--) 832 1.1 tsubai if (spifi_sync_period[v] >= period) 833 1.1 tsubai break; 834 1.1 tsubai if (v == -1) 835 1.1 tsubai reg->data_xfer = 0; /* XXX */ 836 1.1 tsubai else 837 1.1 tsubai reg->data_xfer = v << 4 | offset; 838 1.1 tsubai } 839 1.1 tsubai } 840 1.1 tsubai #endif 841