1 1.44 thorpej /* $NetBSD: mesh.c,v 1.44 2023/12/20 15:29:04 thorpej Exp $ */ 2 1.1 tsubai 3 1.1 tsubai /*- 4 1.6 tsubai * Copyright (c) 2000 Tsubai Masanari. 5 1.6 tsubai * Copyright (c) 1999 Internet Research Institute, Inc. 6 1.1 tsubai * All rights reserved. 7 1.1 tsubai * 8 1.1 tsubai * Redistribution and use in source and binary forms, with or without 9 1.1 tsubai * modification, are permitted provided that the following conditions 10 1.1 tsubai * are met: 11 1.1 tsubai * 1. Redistributions of source code must retain the above copyright 12 1.1 tsubai * notice, this list of conditions and the following disclaimer. 13 1.1 tsubai * 2. Redistributions in binary form must reproduce the above copyright 14 1.1 tsubai * notice, this list of conditions and the following disclaimer in the 15 1.1 tsubai * documentation and/or other materials provided with the distribution. 16 1.1 tsubai * 3. All advertising materials mentioning features or use of this software 17 1.1 tsubai * must display the following acknowledgement: 18 1.1 tsubai * This product includes software developed by 19 1.1 tsubai * Internet Research Institute, Inc. 20 1.1 tsubai * 4. The name of the author may not be used to endorse or promote products 21 1.1 tsubai * derived from this software without specific prior written permission. 22 1.1 tsubai * 23 1.1 tsubai * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 24 1.1 tsubai * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 25 1.1 tsubai * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 26 1.1 tsubai * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 27 1.1 tsubai * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 28 1.1 tsubai * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29 1.1 tsubai * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 30 1.1 tsubai * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 31 1.1 tsubai * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 32 1.1 tsubai * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 1.1 tsubai */ 34 1.19 lukem 35 1.19 lukem #include <sys/cdefs.h> 36 1.44 thorpej __KERNEL_RCSID(0, "$NetBSD: mesh.c,v 1.44 2023/12/20 15:29:04 thorpej Exp $"); 37 1.1 tsubai 38 1.1 tsubai #include <sys/param.h> 39 1.1 tsubai #include <sys/buf.h> 40 1.1 tsubai #include <sys/device.h> 41 1.1 tsubai #include <sys/errno.h> 42 1.1 tsubai #include <sys/kernel.h> 43 1.1 tsubai #include <sys/queue.h> 44 1.1 tsubai #include <sys/systm.h> 45 1.1 tsubai 46 1.5 mrg #include <uvm/uvm_extern.h> 47 1.1 tsubai 48 1.1 tsubai #include <dev/scsipi/scsi_all.h> 49 1.1 tsubai #include <dev/scsipi/scsipi_all.h> 50 1.1 tsubai #include <dev/scsipi/scsiconf.h> 51 1.1 tsubai #include <dev/scsipi/scsi_message.h> 52 1.1 tsubai 53 1.1 tsubai #include <dev/ofw/openfirm.h> 54 1.1 tsubai 55 1.1 tsubai #include <machine/autoconf.h> 56 1.1 tsubai #include <machine/cpu.h> 57 1.1 tsubai #include <machine/pio.h> 58 1.1 tsubai 59 1.1 tsubai #include <macppc/dev/dbdma.h> 60 1.1 tsubai #include <macppc/dev/meshreg.h> 61 1.1 tsubai 62 1.6 tsubai #ifdef MESH_DEBUG 63 1.6 tsubai # define DPRINTF printf 64 1.6 tsubai #else 65 1.6 tsubai # define DPRINTF while (0) printf 66 1.6 tsubai #endif 67 1.6 tsubai 68 1.1 tsubai #define T_SYNCMODE 0x01 /* target uses sync mode */ 69 1.1 tsubai #define T_SYNCNEGO 0x02 /* sync negotiation done */ 70 1.1 tsubai 71 1.1 tsubai struct mesh_tinfo { 72 1.1 tsubai int flags; 73 1.1 tsubai int period; 74 1.1 tsubai int offset; 75 1.1 tsubai }; 76 1.1 tsubai 77 1.1 tsubai /* scb flags */ 78 1.1 tsubai #define MESH_POLL 0x01 79 1.1 tsubai #define MESH_CHECK 0x02 80 1.1 tsubai #define MESH_READ 0x80 81 1.1 tsubai 82 1.1 tsubai struct mesh_scb { 83 1.1 tsubai TAILQ_ENTRY(mesh_scb) chain; 84 1.1 tsubai int flags; 85 1.1 tsubai struct scsipi_xfer *xs; 86 1.20 thorpej struct scsipi_generic cmd; 87 1.1 tsubai int cmdlen; 88 1.1 tsubai int target; /* target SCSI ID */ 89 1.1 tsubai int resid; 90 1.1 tsubai vaddr_t daddr; 91 1.1 tsubai vsize_t dlen; 92 1.1 tsubai int status; 93 1.1 tsubai }; 94 1.1 tsubai 95 1.1 tsubai /* sc_flags value */ 96 1.1 tsubai #define MESH_DMA_ACTIVE 0x01 97 1.1 tsubai 98 1.1 tsubai struct mesh_softc { 99 1.31 tsutsui device_t sc_dev; /* us as a device */ 100 1.9 bouyer struct scsipi_channel sc_channel; 101 1.1 tsubai struct scsipi_adapter sc_adapter; 102 1.1 tsubai 103 1.1 tsubai u_char *sc_reg; /* MESH base address */ 104 1.1 tsubai dbdma_regmap_t *sc_dmareg; /* DMA register address */ 105 1.1 tsubai dbdma_command_t *sc_dmacmd; /* DMA command area */ 106 1.1 tsubai 107 1.1 tsubai int sc_flags; 108 1.1 tsubai int sc_cfflags; /* copy of config flags */ 109 1.1 tsubai int sc_meshid; /* MESH version */ 110 1.1 tsubai int sc_minsync; /* minimum sync period */ 111 1.1 tsubai int sc_irq; 112 1.1 tsubai int sc_freq; /* SCSI bus frequency in MHz */ 113 1.1 tsubai int sc_id; /* our SCSI ID */ 114 1.1 tsubai struct mesh_tinfo sc_tinfo[8]; /* target information */ 115 1.1 tsubai 116 1.1 tsubai int sc_nextstate; 117 1.1 tsubai int sc_prevphase; 118 1.1 tsubai struct mesh_scb *sc_nexus; /* current command */ 119 1.1 tsubai 120 1.1 tsubai int sc_msgout; 121 1.1 tsubai int sc_imsglen; 122 1.1 tsubai u_char sc_imsg[16]; 123 1.1 tsubai u_char sc_omsg[16]; 124 1.1 tsubai 125 1.1 tsubai TAILQ_HEAD(, mesh_scb) free_scb; 126 1.1 tsubai TAILQ_HEAD(, mesh_scb) ready_scb; 127 1.1 tsubai struct mesh_scb sc_scb[16]; 128 1.1 tsubai }; 129 1.1 tsubai 130 1.1 tsubai /* mesh_msgout() values */ 131 1.1 tsubai #define SEND_REJECT 1 132 1.1 tsubai #define SEND_IDENTIFY 2 133 1.1 tsubai #define SEND_SDTR 4 134 1.1 tsubai 135 1.28 dsl static inline int mesh_read_reg(struct mesh_softc *, int); 136 1.28 dsl static inline void mesh_set_reg(struct mesh_softc *, int, int); 137 1.1 tsubai 138 1.34 tsutsui static int mesh_match(device_t, cfdata_t, void *); 139 1.34 tsutsui static void mesh_attach(device_t, device_t, void *); 140 1.34 tsutsui static bool mesh_shutdown(device_t, int); 141 1.34 tsutsui static int mesh_intr(void *); 142 1.34 tsutsui static void mesh_error(struct mesh_softc *, struct mesh_scb *, int, int); 143 1.34 tsutsui static void mesh_select(struct mesh_softc *, struct mesh_scb *); 144 1.34 tsutsui static void mesh_identify(struct mesh_softc *, struct mesh_scb *); 145 1.34 tsutsui static void mesh_command(struct mesh_softc *, struct mesh_scb *); 146 1.34 tsutsui static void mesh_dma_setup(struct mesh_softc *, struct mesh_scb *); 147 1.34 tsutsui static void mesh_dataio(struct mesh_softc *, struct mesh_scb *); 148 1.34 tsutsui static void mesh_status(struct mesh_softc *, struct mesh_scb *); 149 1.34 tsutsui static void mesh_msgin(struct mesh_softc *, struct mesh_scb *); 150 1.34 tsutsui static void mesh_msgout(struct mesh_softc *, int); 151 1.34 tsutsui static void mesh_bus_reset(struct mesh_softc *); 152 1.34 tsutsui static void mesh_reset(struct mesh_softc *); 153 1.34 tsutsui static int mesh_stp(struct mesh_softc *, int); 154 1.34 tsutsui static void mesh_setsync(struct mesh_softc *, struct mesh_tinfo *); 155 1.34 tsutsui static struct mesh_scb *mesh_get_scb(struct mesh_softc *); 156 1.34 tsutsui static void mesh_free_scb(struct mesh_softc *, struct mesh_scb *); 157 1.34 tsutsui static void mesh_scsi_request(struct scsipi_channel *, 158 1.28 dsl scsipi_adapter_req_t, void *); 159 1.34 tsutsui static void mesh_sched(struct mesh_softc *); 160 1.34 tsutsui static int mesh_poll(struct mesh_softc *, struct scsipi_xfer *); 161 1.34 tsutsui static void mesh_done(struct mesh_softc *, struct mesh_scb *); 162 1.34 tsutsui static void mesh_timeout(void *); 163 1.34 tsutsui static void mesh_minphys(struct buf *); 164 1.1 tsubai 165 1.1 tsubai 166 1.1 tsubai #define MESH_DATAOUT 0 167 1.1 tsubai #define MESH_DATAIN MESH_STATUS0_IO 168 1.1 tsubai #define MESH_COMMAND MESH_STATUS0_CD 169 1.1 tsubai #define MESH_STATUS (MESH_STATUS0_CD | MESH_STATUS0_IO) 170 1.1 tsubai #define MESH_MSGOUT (MESH_STATUS0_MSG | MESH_STATUS0_CD) 171 1.1 tsubai #define MESH_MSGIN (MESH_STATUS0_MSG | MESH_STATUS0_CD | MESH_STATUS0_IO) 172 1.1 tsubai 173 1.1 tsubai #define MESH_SELECTING 8 174 1.1 tsubai #define MESH_IDENTIFY 9 175 1.1 tsubai #define MESH_COMPLETE 10 176 1.1 tsubai #define MESH_BUSFREE 11 177 1.1 tsubai #define MESH_UNKNOWN -1 178 1.1 tsubai 179 1.1 tsubai #define MESH_PHASE_MASK (MESH_STATUS0_MSG | MESH_STATUS0_CD | MESH_STATUS0_IO) 180 1.1 tsubai 181 1.31 tsutsui CFATTACH_DECL_NEW(mesh, sizeof(struct mesh_softc), 182 1.16 thorpej mesh_match, mesh_attach, NULL, NULL); 183 1.1 tsubai 184 1.1 tsubai int 185 1.31 tsutsui mesh_match(device_t parent, cfdata_t cf, void *aux) 186 1.1 tsubai { 187 1.1 tsubai struct confargs *ca = aux; 188 1.7 tsubai char compat[32]; 189 1.1 tsubai 190 1.7 tsubai if (strcmp(ca->ca_name, "mesh") == 0) 191 1.7 tsubai return 1; 192 1.1 tsubai 193 1.12 wiz memset(compat, 0, sizeof(compat)); 194 1.7 tsubai OF_getprop(ca->ca_node, "compatible", compat, sizeof(compat)); 195 1.7 tsubai if (strcmp(compat, "chrp,mesh0") == 0) 196 1.7 tsubai return 1; 197 1.7 tsubai 198 1.7 tsubai return 0; 199 1.1 tsubai } 200 1.1 tsubai 201 1.1 tsubai void 202 1.31 tsutsui mesh_attach(device_t parent, device_t self, void *aux) 203 1.1 tsubai { 204 1.31 tsutsui struct mesh_softc *sc = device_private(self); 205 1.1 tsubai struct confargs *ca = aux; 206 1.1 tsubai int i; 207 1.1 tsubai u_int *reg; 208 1.1 tsubai 209 1.32 tsutsui sc->sc_dev = self; 210 1.1 tsubai reg = ca->ca_reg; 211 1.1 tsubai reg[0] += ca->ca_baseaddr; 212 1.1 tsubai reg[2] += ca->ca_baseaddr; 213 1.35 matt sc->sc_reg = mapiodev(reg[0], reg[1], false); 214 1.1 tsubai sc->sc_irq = ca->ca_intr[0]; 215 1.35 matt sc->sc_dmareg = mapiodev(reg[2], reg[3], false); 216 1.1 tsubai 217 1.25 thorpej sc->sc_cfflags = device_cfdata(self)->cf_flags; 218 1.1 tsubai sc->sc_meshid = mesh_read_reg(sc, MESH_MESH_ID) & 0x1f; 219 1.1 tsubai #if 0 220 1.1 tsubai if (sc->sc_meshid != (MESH_SIGNATURE & 0x1f) { 221 1.31 tsutsui aprint_error(": unknown MESH ID (0x%x)\n", sc->sc_meshid); 222 1.1 tsubai return; 223 1.1 tsubai } 224 1.1 tsubai #endif 225 1.1 tsubai if (OF_getprop(ca->ca_node, "clock-frequency", &sc->sc_freq, 4) != 4) { 226 1.31 tsutsui aprint_error(": cannot get clock-frequency\n"); 227 1.1 tsubai return; 228 1.1 tsubai } 229 1.1 tsubai sc->sc_freq /= 1000000; /* in MHz */ 230 1.1 tsubai sc->sc_minsync = 25; /* maximum sync rate = 10MB/sec */ 231 1.1 tsubai sc->sc_id = 7; 232 1.1 tsubai 233 1.1 tsubai TAILQ_INIT(&sc->free_scb); 234 1.1 tsubai TAILQ_INIT(&sc->ready_scb); 235 1.1 tsubai for (i = 0; i < sizeof(sc->sc_scb)/sizeof(sc->sc_scb[0]); i++) 236 1.1 tsubai TAILQ_INSERT_TAIL(&sc->free_scb, &sc->sc_scb[i], chain); 237 1.1 tsubai 238 1.37 macallan sc->sc_dmacmd = dbdma_alloc(sizeof(dbdma_command_t) * 20, NULL); 239 1.1 tsubai 240 1.1 tsubai mesh_reset(sc); 241 1.1 tsubai mesh_bus_reset(sc); 242 1.1 tsubai 243 1.31 tsutsui aprint_normal(" irq %d: %dMHz, SCSI ID %d\n", 244 1.1 tsubai sc->sc_irq, sc->sc_freq, sc->sc_id); 245 1.1 tsubai 246 1.31 tsutsui sc->sc_adapter.adapt_dev = self; 247 1.9 bouyer sc->sc_adapter.adapt_nchannels = 1; 248 1.9 bouyer sc->sc_adapter.adapt_openings = 7; 249 1.9 bouyer sc->sc_adapter.adapt_max_periph = 1; 250 1.9 bouyer sc->sc_adapter.adapt_ioctl = NULL; 251 1.9 bouyer sc->sc_adapter.adapt_minphys = mesh_minphys; 252 1.9 bouyer sc->sc_adapter.adapt_request = mesh_scsi_request; 253 1.9 bouyer 254 1.9 bouyer sc->sc_channel.chan_adapter = &sc->sc_adapter; 255 1.9 bouyer sc->sc_channel.chan_bustype = &scsi_bustype; 256 1.9 bouyer sc->sc_channel.chan_channel = 0; 257 1.9 bouyer sc->sc_channel.chan_ntargets = 8; 258 1.9 bouyer sc->sc_channel.chan_nluns = 8; 259 1.9 bouyer sc->sc_channel.chan_id = sc->sc_id; 260 1.1 tsubai 261 1.42 thorpej config_found(self, &sc->sc_channel, scsiprint, CFARGS_NONE); 262 1.1 tsubai 263 1.40 rin intr_establish_xname(sc->sc_irq, IST_EDGE, IPL_BIO, mesh_intr, sc, 264 1.40 rin device_xname(self)); 265 1.1 tsubai 266 1.1 tsubai /* Reset SCSI bus when halt. */ 267 1.38 tsutsui if (!pmf_device_register1(self, NULL, NULL, mesh_shutdown)) 268 1.33 tsutsui aprint_error_dev(self, "couldn't establish power handler\n"); 269 1.1 tsubai } 270 1.1 tsubai 271 1.1 tsubai #define MESH_SET_XFER(sc, count) do { \ 272 1.1 tsubai mesh_set_reg(sc, MESH_XFER_COUNT0, count); \ 273 1.1 tsubai mesh_set_reg(sc, MESH_XFER_COUNT1, count >> 8); \ 274 1.1 tsubai } while (0) 275 1.1 tsubai 276 1.1 tsubai #define MESH_GET_XFER(sc) ((mesh_read_reg(sc, MESH_XFER_COUNT1) << 8) | \ 277 1.1 tsubai mesh_read_reg(sc, MESH_XFER_COUNT0)) 278 1.1 tsubai 279 1.1 tsubai int 280 1.29 dsl mesh_read_reg(struct mesh_softc *sc, int reg) 281 1.1 tsubai { 282 1.1 tsubai return in8(sc->sc_reg + reg); 283 1.1 tsubai } 284 1.1 tsubai 285 1.1 tsubai void 286 1.30 dsl mesh_set_reg(struct mesh_softc *sc, int reg, int val) 287 1.1 tsubai { 288 1.1 tsubai out8(sc->sc_reg + reg, val); 289 1.1 tsubai } 290 1.1 tsubai 291 1.33 tsutsui bool 292 1.33 tsutsui mesh_shutdown(device_t self, int howto) 293 1.1 tsubai { 294 1.33 tsutsui struct mesh_softc *sc; 295 1.33 tsutsui 296 1.33 tsutsui sc = device_private(self); 297 1.1 tsubai 298 1.1 tsubai /* Set to async mode. */ 299 1.1 tsubai mesh_set_reg(sc, MESH_SYNC_PARAM, 2); 300 1.21 briggs mesh_bus_reset(sc); 301 1.33 tsutsui 302 1.33 tsutsui return true; 303 1.1 tsubai } 304 1.1 tsubai 305 1.6 tsubai #ifdef MESH_DEBUG 306 1.6 tsubai static char scsi_phase[][8] = { 307 1.6 tsubai "DATAOUT", 308 1.6 tsubai "DATAIN", 309 1.6 tsubai "COMMAND", 310 1.6 tsubai "STATUS", 311 1.6 tsubai "", 312 1.6 tsubai "", 313 1.6 tsubai "MSGOUT", 314 1.6 tsubai "MSGIN" 315 1.6 tsubai }; 316 1.6 tsubai #endif 317 1.6 tsubai 318 1.1 tsubai int 319 1.29 dsl mesh_intr(void *arg) 320 1.1 tsubai { 321 1.1 tsubai struct mesh_softc *sc = arg; 322 1.1 tsubai struct mesh_scb *scb; 323 1.3 tsubai int fifocnt; 324 1.36 mrg u_char intr, exception, error, status0; 325 1.1 tsubai 326 1.1 tsubai intr = mesh_read_reg(sc, MESH_INTERRUPT); 327 1.1 tsubai if (intr == 0) { 328 1.31 tsutsui DPRINTF("%s: stray interrupt\n", device_xname(sc->sc_dev)); 329 1.1 tsubai return 0; 330 1.1 tsubai } 331 1.1 tsubai 332 1.1 tsubai exception = mesh_read_reg(sc, MESH_EXCEPTION); 333 1.1 tsubai error = mesh_read_reg(sc, MESH_ERROR); 334 1.1 tsubai status0 = mesh_read_reg(sc, MESH_BUS_STATUS0); 335 1.36 mrg (void)mesh_read_reg(sc, MESH_BUS_STATUS1); 336 1.1 tsubai 337 1.1 tsubai /* clear interrupt */ 338 1.1 tsubai mesh_set_reg(sc, MESH_INTERRUPT, intr); 339 1.1 tsubai 340 1.6 tsubai #ifdef MESH_DEBUG 341 1.6 tsubai { 342 1.6 tsubai char buf1[64], buf2[64]; 343 1.6 tsubai 344 1.27 christos snprintb(buf1, sizeof buf1, MESH_STATUS0_BITMASK, status0); 345 1.27 christos snprintb(buf2, sizeof buf2, MESH_EXC_BITMASK, exception); 346 1.39 msaitoh printf("mesh_intr status0 = %s (%s), exc = %s\n", 347 1.6 tsubai buf1, scsi_phase[status0 & 7], buf2); 348 1.6 tsubai } 349 1.6 tsubai #endif 350 1.6 tsubai 351 1.1 tsubai scb = sc->sc_nexus; 352 1.1 tsubai if (scb == NULL) { 353 1.31 tsutsui DPRINTF("%s: NULL nexus\n", device_xname(sc->sc_dev)); 354 1.1 tsubai return 1; 355 1.1 tsubai } 356 1.1 tsubai 357 1.21 briggs if (intr & MESH_INTR_CMDDONE) { 358 1.21 briggs if (sc->sc_flags & MESH_DMA_ACTIVE) { 359 1.21 briggs dbdma_stop(sc->sc_dmareg); 360 1.21 briggs 361 1.21 briggs sc->sc_flags &= ~MESH_DMA_ACTIVE; 362 1.21 briggs scb->resid = MESH_GET_XFER(sc); 363 1.21 briggs 364 1.21 briggs fifocnt = mesh_read_reg(sc, MESH_FIFO_COUNT); 365 1.21 briggs if (fifocnt != 0) { 366 1.21 briggs if (scb->flags & MESH_READ) { 367 1.21 briggs char *cp; 368 1.21 briggs 369 1.21 briggs cp = (char *)scb->daddr + scb->dlen 370 1.21 briggs - fifocnt; 371 1.21 briggs DPRINTF("fifocnt = %d, resid = %d\n", 372 1.21 briggs fifocnt, scb->resid); 373 1.21 briggs while (fifocnt > 0) { 374 1.21 briggs *cp++ = mesh_read_reg(sc, 375 1.21 briggs MESH_FIFO); 376 1.21 briggs fifocnt--; 377 1.21 briggs } 378 1.21 briggs } else { 379 1.21 briggs mesh_set_reg(sc, MESH_SEQUENCE, 380 1.21 briggs MESH_CMD_FLUSH_FIFO); 381 1.21 briggs } 382 1.21 briggs } else { 383 1.21 briggs /* Clear all interrupts */ 384 1.21 briggs mesh_set_reg(sc, MESH_INTERRUPT, 7); 385 1.3 tsubai } 386 1.21 briggs } 387 1.1 tsubai } 388 1.1 tsubai 389 1.1 tsubai if (intr & MESH_INTR_ERROR) { 390 1.21 briggs printf("%s: error %02x %02x\n", 391 1.31 tsutsui device_xname(sc->sc_dev), error, exception); 392 1.1 tsubai mesh_error(sc, scb, error, 0); 393 1.1 tsubai return 1; 394 1.1 tsubai } 395 1.1 tsubai 396 1.1 tsubai if (intr & MESH_INTR_EXCEPTION) { 397 1.1 tsubai /* selection timeout */ 398 1.1 tsubai if (exception & MESH_EXC_SELTO) { 399 1.1 tsubai mesh_error(sc, scb, 0, exception); 400 1.1 tsubai return 1; 401 1.1 tsubai } 402 1.1 tsubai 403 1.1 tsubai /* phase mismatch */ 404 1.1 tsubai if (exception & MESH_EXC_PHASEMM) { 405 1.6 tsubai DPRINTF("%s: PHASE MISMATCH; nextstate = %d -> ", 406 1.31 tsutsui device_xname(sc->sc_dev), sc->sc_nextstate); 407 1.1 tsubai sc->sc_nextstate = status0 & MESH_PHASE_MASK; 408 1.6 tsubai 409 1.6 tsubai DPRINTF("%d, resid = %d\n", 410 1.6 tsubai sc->sc_nextstate, scb->resid); 411 1.1 tsubai } 412 1.1 tsubai } 413 1.1 tsubai 414 1.1 tsubai if (sc->sc_nextstate == MESH_UNKNOWN) 415 1.1 tsubai sc->sc_nextstate = status0 & MESH_PHASE_MASK; 416 1.1 tsubai 417 1.1 tsubai switch (sc->sc_nextstate) { 418 1.1 tsubai 419 1.1 tsubai case MESH_IDENTIFY: 420 1.1 tsubai mesh_identify(sc, scb); 421 1.1 tsubai break; 422 1.1 tsubai case MESH_COMMAND: 423 1.1 tsubai mesh_command(sc, scb); 424 1.1 tsubai break; 425 1.1 tsubai case MESH_DATAIN: 426 1.1 tsubai case MESH_DATAOUT: 427 1.1 tsubai mesh_dataio(sc, scb); 428 1.1 tsubai break; 429 1.1 tsubai case MESH_STATUS: 430 1.1 tsubai mesh_status(sc, scb); 431 1.1 tsubai break; 432 1.1 tsubai case MESH_MSGIN: 433 1.1 tsubai mesh_msgin(sc, scb); 434 1.1 tsubai break; 435 1.1 tsubai case MESH_COMPLETE: 436 1.1 tsubai mesh_done(sc, scb); 437 1.1 tsubai break; 438 1.1 tsubai 439 1.1 tsubai default: 440 1.31 tsutsui printf("%s: unknown state (%d)\n", device_xname(sc->sc_dev), 441 1.6 tsubai sc->sc_nextstate); 442 1.6 tsubai scb->xs->error = XS_DRIVER_STUFFUP; 443 1.6 tsubai mesh_done(sc, scb); 444 1.1 tsubai } 445 1.1 tsubai 446 1.1 tsubai return 1; 447 1.1 tsubai } 448 1.1 tsubai 449 1.1 tsubai void 450 1.30 dsl mesh_error(struct mesh_softc *sc, struct mesh_scb *scb, int error, int exception) 451 1.1 tsubai { 452 1.1 tsubai if (error & MESH_ERR_SCSI_RESET) { 453 1.31 tsutsui printf("%s: SCSI RESET\n", device_xname(sc->sc_dev)); 454 1.1 tsubai 455 1.1 tsubai /* Wait until the RST signal is deasserted. */ 456 1.1 tsubai while (mesh_read_reg(sc, MESH_BUS_STATUS1) & MESH_STATUS1_RST); 457 1.1 tsubai mesh_reset(sc); 458 1.1 tsubai return; 459 1.1 tsubai } 460 1.1 tsubai 461 1.1 tsubai if (error & MESH_ERR_PARITY_ERR0) { 462 1.31 tsutsui printf("%s: parity error\n", device_xname(sc->sc_dev)); 463 1.1 tsubai scb->xs->error = XS_DRIVER_STUFFUP; 464 1.1 tsubai } 465 1.1 tsubai 466 1.1 tsubai if (error & MESH_ERR_DISCONNECT) { 467 1.31 tsutsui printf("%s: unexpected disconnect\n", device_xname(sc->sc_dev)); 468 1.1 tsubai if (sc->sc_nextstate != MESH_COMPLETE) 469 1.1 tsubai scb->xs->error = XS_DRIVER_STUFFUP; 470 1.1 tsubai } 471 1.1 tsubai 472 1.1 tsubai if (exception & MESH_EXC_SELTO) { 473 1.1 tsubai /* XXX should reset bus here? */ 474 1.6 tsubai scb->xs->error = XS_SELTIMEOUT; 475 1.1 tsubai } 476 1.1 tsubai 477 1.1 tsubai mesh_done(sc, scb); 478 1.1 tsubai } 479 1.1 tsubai 480 1.1 tsubai void 481 1.29 dsl mesh_select(struct mesh_softc *sc, struct mesh_scb *scb) 482 1.1 tsubai { 483 1.1 tsubai struct mesh_tinfo *ti = &sc->sc_tinfo[scb->target]; 484 1.8 wiz int timeout; 485 1.1 tsubai 486 1.6 tsubai DPRINTF("mesh_select\n"); 487 1.6 tsubai 488 1.1 tsubai mesh_setsync(sc, ti); 489 1.1 tsubai MESH_SET_XFER(sc, 0); 490 1.1 tsubai 491 1.1 tsubai /* arbitration */ 492 1.1 tsubai 493 1.1 tsubai /* 494 1.1 tsubai * MESH mistakenly asserts TARGET ID bit along with its own ID bit 495 1.1 tsubai * in arbitration phase (like selection). So we should load 496 1.1 tsubai * initiator ID to DestID register temporarily. 497 1.1 tsubai */ 498 1.1 tsubai mesh_set_reg(sc, MESH_DEST_ID, sc->sc_id); 499 1.1 tsubai mesh_set_reg(sc, MESH_INTR_MASK, 0); /* disable intr. */ 500 1.1 tsubai mesh_set_reg(sc, MESH_SEQUENCE, MESH_CMD_ARBITRATE); 501 1.1 tsubai 502 1.1 tsubai while (mesh_read_reg(sc, MESH_INTERRUPT) == 0); 503 1.1 tsubai mesh_set_reg(sc, MESH_INTERRUPT, 1); 504 1.1 tsubai mesh_set_reg(sc, MESH_INTR_MASK, 7); 505 1.1 tsubai 506 1.1 tsubai /* selection */ 507 1.1 tsubai mesh_set_reg(sc, MESH_DEST_ID, scb->target); 508 1.1 tsubai mesh_set_reg(sc, MESH_SEQUENCE, MESH_CMD_SELECT | MESH_SEQ_ATN); 509 1.1 tsubai 510 1.1 tsubai sc->sc_prevphase = MESH_SELECTING; 511 1.1 tsubai sc->sc_nextstate = MESH_IDENTIFY; 512 1.1 tsubai 513 1.14 bouyer timeout = mstohz(scb->xs->timeout); 514 1.8 wiz if (timeout == 0) 515 1.8 wiz timeout = 1; 516 1.8 wiz 517 1.8 wiz callout_reset(&scb->xs->xs_callout, timeout, mesh_timeout, scb); 518 1.1 tsubai } 519 1.1 tsubai 520 1.1 tsubai void 521 1.29 dsl mesh_identify(struct mesh_softc *sc, struct mesh_scb *scb) 522 1.1 tsubai { 523 1.6 tsubai struct mesh_tinfo *ti = &sc->sc_tinfo[scb->target]; 524 1.6 tsubai 525 1.6 tsubai DPRINTF("mesh_identify\n"); 526 1.1 tsubai mesh_set_reg(sc, MESH_SEQUENCE, MESH_CMD_FLUSH_FIFO); 527 1.1 tsubai 528 1.6 tsubai if ((ti->flags & T_SYNCNEGO) == 0) { 529 1.6 tsubai ti->period = sc->sc_minsync; 530 1.6 tsubai ti->offset = 15; 531 1.6 tsubai mesh_msgout(sc, SEND_IDENTIFY | SEND_SDTR); 532 1.6 tsubai sc->sc_nextstate = MESH_MSGIN; 533 1.6 tsubai } else { 534 1.6 tsubai mesh_msgout(sc, SEND_IDENTIFY); 535 1.6 tsubai sc->sc_nextstate = MESH_COMMAND; 536 1.6 tsubai } 537 1.1 tsubai } 538 1.1 tsubai 539 1.1 tsubai void 540 1.29 dsl mesh_command(struct mesh_softc *sc, struct mesh_scb *scb) 541 1.1 tsubai { 542 1.1 tsubai int i; 543 1.1 tsubai char *cmdp; 544 1.1 tsubai 545 1.6 tsubai #ifdef MESH_DEBUG 546 1.6 tsubai printf("mesh_command cdb = %02x", scb->cmd.opcode); 547 1.6 tsubai for (i = 0; i < 5; i++) 548 1.6 tsubai printf(" %02x", scb->cmd.bytes[i]); 549 1.6 tsubai printf("\n"); 550 1.6 tsubai #endif 551 1.1 tsubai 552 1.1 tsubai mesh_set_reg(sc, MESH_SEQUENCE, MESH_CMD_FLUSH_FIFO); 553 1.1 tsubai 554 1.1 tsubai MESH_SET_XFER(sc, scb->cmdlen); 555 1.1 tsubai mesh_set_reg(sc, MESH_SEQUENCE, MESH_CMD_COMMAND); 556 1.1 tsubai 557 1.1 tsubai cmdp = (char *)&scb->cmd; 558 1.1 tsubai for (i = 0; i < scb->cmdlen; i++) 559 1.1 tsubai mesh_set_reg(sc, MESH_FIFO, *cmdp++); 560 1.1 tsubai 561 1.1 tsubai if (scb->resid == 0) 562 1.1 tsubai sc->sc_nextstate = MESH_STATUS; /* no data xfer */ 563 1.1 tsubai else 564 1.1 tsubai sc->sc_nextstate = MESH_DATAIN; 565 1.1 tsubai } 566 1.1 tsubai 567 1.1 tsubai void 568 1.29 dsl mesh_dma_setup(struct mesh_softc *sc, struct mesh_scb *scb) 569 1.1 tsubai { 570 1.1 tsubai int datain = scb->flags & MESH_READ; 571 1.1 tsubai dbdma_command_t *cmdp; 572 1.1 tsubai u_int cmd; 573 1.1 tsubai vaddr_t va; 574 1.1 tsubai int count, offset; 575 1.1 tsubai 576 1.1 tsubai cmdp = sc->sc_dmacmd; 577 1.1 tsubai cmd = datain ? DBDMA_CMD_IN_MORE : DBDMA_CMD_OUT_MORE; 578 1.1 tsubai 579 1.1 tsubai count = scb->dlen; 580 1.1 tsubai 581 1.17 thorpej if (count / PAGE_SIZE > 32) 582 1.1 tsubai panic("mesh: transfer size >= 128k"); 583 1.1 tsubai 584 1.1 tsubai va = scb->daddr; 585 1.1 tsubai offset = va & PGOFSET; 586 1.1 tsubai 587 1.1 tsubai /* if va is not page-aligned, setup the first page */ 588 1.1 tsubai if (offset != 0) { 589 1.17 thorpej int rest = PAGE_SIZE - offset; /* the rest in the page */ 590 1.1 tsubai 591 1.1 tsubai if (count > rest) { /* if continues to next page */ 592 1.1 tsubai DBDMA_BUILD(cmdp, cmd, 0, rest, vtophys(va), 593 1.1 tsubai DBDMA_INT_NEVER, DBDMA_WAIT_NEVER, 594 1.1 tsubai DBDMA_BRANCH_NEVER); 595 1.1 tsubai count -= rest; 596 1.1 tsubai va += rest; 597 1.1 tsubai cmdp++; 598 1.1 tsubai } 599 1.1 tsubai } 600 1.1 tsubai 601 1.1 tsubai /* now va is page-aligned */ 602 1.17 thorpej while (count > PAGE_SIZE) { 603 1.17 thorpej DBDMA_BUILD(cmdp, cmd, 0, PAGE_SIZE, vtophys(va), 604 1.1 tsubai DBDMA_INT_NEVER, DBDMA_WAIT_NEVER, DBDMA_BRANCH_NEVER); 605 1.17 thorpej count -= PAGE_SIZE; 606 1.17 thorpej va += PAGE_SIZE; 607 1.1 tsubai cmdp++; 608 1.1 tsubai } 609 1.1 tsubai 610 1.17 thorpej /* the last page (count <= PAGE_SIZE here) */ 611 1.1 tsubai cmd = datain ? DBDMA_CMD_IN_LAST : DBDMA_CMD_OUT_LAST; 612 1.1 tsubai DBDMA_BUILD(cmdp, cmd , 0, count, vtophys(va), 613 1.1 tsubai DBDMA_INT_NEVER, DBDMA_WAIT_NEVER, DBDMA_BRANCH_NEVER); 614 1.1 tsubai cmdp++; 615 1.1 tsubai 616 1.1 tsubai DBDMA_BUILD(cmdp, DBDMA_CMD_STOP, 0, 0, 0, 617 1.1 tsubai DBDMA_INT_NEVER, DBDMA_WAIT_NEVER, DBDMA_BRANCH_NEVER); 618 1.1 tsubai } 619 1.1 tsubai 620 1.1 tsubai void 621 1.29 dsl mesh_dataio(struct mesh_softc *sc, struct mesh_scb *scb) 622 1.1 tsubai { 623 1.6 tsubai DPRINTF("mesh_dataio len = %ld (%s)\n", scb->dlen, 624 1.6 tsubai scb->flags & MESH_READ ? "read" : "write"); 625 1.6 tsubai 626 1.1 tsubai mesh_dma_setup(sc, scb); 627 1.1 tsubai 628 1.1 tsubai if (scb->dlen == 65536) 629 1.1 tsubai MESH_SET_XFER(sc, 0); /* TC = 0 means 64KB transfer */ 630 1.1 tsubai else 631 1.1 tsubai MESH_SET_XFER(sc, scb->dlen); 632 1.1 tsubai 633 1.1 tsubai if (scb->flags & MESH_READ) 634 1.1 tsubai mesh_set_reg(sc, MESH_SEQUENCE, MESH_CMD_DATAIN | MESH_SEQ_DMA); 635 1.1 tsubai else 636 1.1 tsubai mesh_set_reg(sc, MESH_SEQUENCE, MESH_CMD_DATAOUT | MESH_SEQ_DMA); 637 1.1 tsubai dbdma_start(sc->sc_dmareg, sc->sc_dmacmd); 638 1.1 tsubai sc->sc_flags |= MESH_DMA_ACTIVE; 639 1.1 tsubai sc->sc_nextstate = MESH_STATUS; 640 1.1 tsubai } 641 1.1 tsubai 642 1.1 tsubai void 643 1.29 dsl mesh_status(struct mesh_softc *sc, struct mesh_scb *scb) 644 1.1 tsubai { 645 1.1 tsubai if (mesh_read_reg(sc, MESH_FIFO_COUNT) == 0) { /* XXX cheat */ 646 1.6 tsubai DPRINTF("mesh_status(0)\n"); 647 1.1 tsubai MESH_SET_XFER(sc, 1); 648 1.1 tsubai mesh_set_reg(sc, MESH_SEQUENCE, MESH_CMD_STATUS); 649 1.1 tsubai sc->sc_nextstate = MESH_STATUS; 650 1.1 tsubai return; 651 1.1 tsubai } 652 1.1 tsubai 653 1.1 tsubai scb->status = mesh_read_reg(sc, MESH_FIFO); 654 1.6 tsubai DPRINTF("mesh_status(1): status = 0x%x\n", scb->status); 655 1.6 tsubai if (mesh_read_reg(sc, MESH_FIFO_COUNT) != 0) 656 1.6 tsubai DPRINTF("FIFO_COUNT=%d\n", mesh_read_reg(sc, MESH_FIFO_COUNT)); 657 1.1 tsubai 658 1.1 tsubai mesh_set_reg(sc, MESH_SEQUENCE, MESH_CMD_FLUSH_FIFO); 659 1.1 tsubai MESH_SET_XFER(sc, 1); 660 1.1 tsubai mesh_set_reg(sc, MESH_SEQUENCE, MESH_CMD_MSGIN); 661 1.1 tsubai 662 1.1 tsubai sc->sc_nextstate = MESH_MSGIN; 663 1.1 tsubai } 664 1.1 tsubai 665 1.1 tsubai void 666 1.29 dsl mesh_msgin(struct mesh_softc *sc, struct mesh_scb *scb) 667 1.1 tsubai { 668 1.6 tsubai DPRINTF("mesh_msgin\n"); 669 1.6 tsubai 670 1.1 tsubai if (mesh_read_reg(sc, MESH_FIFO_COUNT) == 0) { /* XXX cheat */ 671 1.1 tsubai MESH_SET_XFER(sc, 1); 672 1.1 tsubai mesh_set_reg(sc, MESH_SEQUENCE, MESH_CMD_MSGIN); 673 1.1 tsubai sc->sc_imsglen = 0; 674 1.1 tsubai sc->sc_nextstate = MESH_MSGIN; 675 1.1 tsubai return; 676 1.1 tsubai } 677 1.1 tsubai 678 1.1 tsubai sc->sc_imsg[sc->sc_imsglen++] = mesh_read_reg(sc, MESH_FIFO); 679 1.1 tsubai 680 1.13 tsutsui if (sc->sc_imsglen == 1 && MSG_IS1BYTE(sc->sc_imsg[0])) 681 1.1 tsubai goto gotit; 682 1.13 tsutsui if (sc->sc_imsglen == 2 && MSG_IS2BYTE(sc->sc_imsg[0])) 683 1.1 tsubai goto gotit; 684 1.13 tsutsui if (sc->sc_imsglen >= 3 && MSG_ISEXTENDED(sc->sc_imsg[0]) && 685 1.1 tsubai sc->sc_imsglen == sc->sc_imsg[1] + 2) 686 1.1 tsubai goto gotit; 687 1.1 tsubai 688 1.1 tsubai sc->sc_nextstate = MESH_MSGIN; 689 1.1 tsubai MESH_SET_XFER(sc, 1); 690 1.1 tsubai mesh_set_reg(sc, MESH_SEQUENCE, MESH_CMD_MSGIN); 691 1.1 tsubai return; 692 1.1 tsubai 693 1.1 tsubai gotit: 694 1.6 tsubai #ifdef MESH_DEBUG 695 1.1 tsubai printf("msgin:"); 696 1.43 andvar for (int i = 0; i < sc->sc_imsglen; i++) 697 1.1 tsubai printf(" 0x%02x", sc->sc_imsg[i]); 698 1.1 tsubai printf("\n"); 699 1.1 tsubai #endif 700 1.1 tsubai 701 1.1 tsubai switch (sc->sc_imsg[0]) { 702 1.1 tsubai case MSG_CMDCOMPLETE: 703 1.1 tsubai mesh_set_reg(sc, MESH_SEQUENCE, MESH_CMD_BUSFREE); 704 1.1 tsubai sc->sc_nextstate = MESH_COMPLETE; 705 1.1 tsubai sc->sc_imsglen = 0; 706 1.1 tsubai return; 707 1.1 tsubai 708 1.1 tsubai case MSG_MESSAGE_REJECT: 709 1.6 tsubai if (sc->sc_msgout & SEND_SDTR) { 710 1.1 tsubai printf("SDTR rejected\n"); 711 1.1 tsubai printf("using async mode\n"); 712 1.1 tsubai sc->sc_tinfo[scb->target].period = 0; 713 1.1 tsubai sc->sc_tinfo[scb->target].offset = 0; 714 1.1 tsubai mesh_setsync(sc, &sc->sc_tinfo[scb->target]); 715 1.1 tsubai break; 716 1.1 tsubai } 717 1.1 tsubai break; 718 1.1 tsubai 719 1.1 tsubai case MSG_NOOP: 720 1.1 tsubai break; 721 1.1 tsubai 722 1.1 tsubai case MSG_EXTENDED: 723 1.1 tsubai goto extended_msg; 724 1.1 tsubai 725 1.1 tsubai default: 726 1.9 bouyer scsipi_printaddr(scb->xs->xs_periph); 727 1.1 tsubai printf("unrecognized MESSAGE(0x%02x); sending REJECT\n", 728 1.1 tsubai sc->sc_imsg[0]); 729 1.1 tsubai 730 1.1 tsubai reject: 731 1.1 tsubai mesh_msgout(sc, SEND_REJECT); 732 1.1 tsubai return; 733 1.1 tsubai } 734 1.1 tsubai goto done; 735 1.1 tsubai 736 1.1 tsubai extended_msg: 737 1.1 tsubai /* process an extended message */ 738 1.1 tsubai switch (sc->sc_imsg[2]) { 739 1.1 tsubai case MSG_EXT_SDTR: 740 1.1 tsubai { 741 1.1 tsubai struct mesh_tinfo *ti = &sc->sc_tinfo[scb->target]; 742 1.1 tsubai int period = sc->sc_imsg[3]; 743 1.1 tsubai int offset = sc->sc_imsg[4]; 744 1.1 tsubai int r = 250 / period; 745 1.1 tsubai int s = (100*250) / period - 100 * r; 746 1.1 tsubai 747 1.1 tsubai if (period < sc->sc_minsync) { 748 1.1 tsubai ti->period = sc->sc_minsync; 749 1.1 tsubai ti->offset = 15; 750 1.1 tsubai mesh_msgout(sc, SEND_SDTR); 751 1.1 tsubai return; 752 1.1 tsubai } 753 1.9 bouyer scsipi_printaddr(scb->xs->xs_periph); 754 1.1 tsubai /* XXX if (offset != 0) ... */ 755 1.1 tsubai printf("max sync rate %d.%02dMb/s\n", r, s); 756 1.1 tsubai ti->period = period; 757 1.1 tsubai ti->offset = offset; 758 1.1 tsubai ti->flags |= T_SYNCNEGO; 759 1.1 tsubai ti->flags |= T_SYNCMODE; 760 1.1 tsubai mesh_setsync(sc, ti); 761 1.1 tsubai goto done; 762 1.1 tsubai } 763 1.1 tsubai default: 764 1.1 tsubai printf("%s target %d: rejecting extended message 0x%x\n", 765 1.31 tsutsui device_xname(sc->sc_dev), scb->target, sc->sc_imsg[0]); 766 1.1 tsubai goto reject; 767 1.1 tsubai } 768 1.1 tsubai 769 1.1 tsubai done: 770 1.1 tsubai sc->sc_imsglen = 0; 771 1.1 tsubai sc->sc_nextstate = MESH_UNKNOWN; 772 1.1 tsubai 773 1.1 tsubai mesh_set_reg(sc, MESH_SEQUENCE, MESH_CMD_BUSFREE); /* XXX really? */ 774 1.1 tsubai } 775 1.1 tsubai 776 1.1 tsubai void 777 1.29 dsl mesh_msgout(struct mesh_softc *sc, int msg) 778 1.1 tsubai { 779 1.1 tsubai struct mesh_scb *scb = sc->sc_nexus; 780 1.1 tsubai struct mesh_tinfo *ti; 781 1.6 tsubai int lun, len, i; 782 1.6 tsubai 783 1.6 tsubai DPRINTF("mesh_msgout: sending"); 784 1.6 tsubai 785 1.6 tsubai sc->sc_msgout = msg; 786 1.6 tsubai len = 0; 787 1.1 tsubai 788 1.6 tsubai if (msg & SEND_REJECT) { 789 1.6 tsubai DPRINTF(" REJECT"); 790 1.6 tsubai sc->sc_omsg[len++] = MSG_MESSAGE_REJECT; 791 1.6 tsubai } 792 1.6 tsubai if (msg & SEND_IDENTIFY) { 793 1.6 tsubai DPRINTF(" IDENTIFY"); 794 1.9 bouyer lun = scb->xs->xs_periph->periph_lun; 795 1.6 tsubai sc->sc_omsg[len++] = MSG_IDENTIFY(lun, 0); 796 1.6 tsubai } 797 1.6 tsubai if (msg & SEND_SDTR) { 798 1.6 tsubai DPRINTF(" SDTR"); 799 1.1 tsubai ti = &sc->sc_tinfo[scb->target]; 800 1.6 tsubai sc->sc_omsg[len++] = MSG_EXTENDED; 801 1.6 tsubai sc->sc_omsg[len++] = 3; 802 1.6 tsubai sc->sc_omsg[len++] = MSG_EXT_SDTR; 803 1.6 tsubai sc->sc_omsg[len++] = ti->period; 804 1.6 tsubai sc->sc_omsg[len++] = ti->offset; 805 1.6 tsubai } 806 1.6 tsubai DPRINTF("\n"); 807 1.6 tsubai 808 1.6 tsubai MESH_SET_XFER(sc, len); 809 1.6 tsubai if (len == 1) { 810 1.6 tsubai mesh_set_reg(sc, MESH_SEQUENCE, MESH_CMD_MSGOUT); 811 1.6 tsubai mesh_set_reg(sc, MESH_FIFO, sc->sc_omsg[0]); 812 1.6 tsubai } else { 813 1.6 tsubai mesh_set_reg(sc, MESH_SEQUENCE, MESH_CMD_MSGOUT | MESH_SEQ_ATN); 814 1.6 tsubai 815 1.6 tsubai for (i = 0; i < len - 1; i++) 816 1.6 tsubai mesh_set_reg(sc, MESH_FIFO, sc->sc_omsg[i]); 817 1.1 tsubai 818 1.6 tsubai /* Wait for the FIFO empty... */ 819 1.6 tsubai while (mesh_read_reg(sc, MESH_FIFO_COUNT) > 0); 820 1.1 tsubai 821 1.6 tsubai /* ...then write the last byte. */ 822 1.1 tsubai mesh_set_reg(sc, MESH_FIFO, sc->sc_omsg[i]); 823 1.6 tsubai } 824 1.1 tsubai sc->sc_nextstate = MESH_UNKNOWN; 825 1.1 tsubai } 826 1.1 tsubai 827 1.1 tsubai void 828 1.29 dsl mesh_bus_reset(struct mesh_softc *sc) 829 1.1 tsubai { 830 1.6 tsubai DPRINTF("mesh_bus_reset\n"); 831 1.6 tsubai 832 1.1 tsubai /* Disable interrupts. */ 833 1.1 tsubai mesh_set_reg(sc, MESH_INTR_MASK, 0); 834 1.1 tsubai 835 1.1 tsubai /* Assert RST line. */ 836 1.1 tsubai mesh_set_reg(sc, MESH_BUS_STATUS1, MESH_STATUS1_RST); 837 1.1 tsubai delay(50); 838 1.1 tsubai mesh_set_reg(sc, MESH_BUS_STATUS1, 0); 839 1.1 tsubai 840 1.1 tsubai mesh_reset(sc); 841 1.1 tsubai } 842 1.1 tsubai 843 1.1 tsubai void 844 1.29 dsl mesh_reset(struct mesh_softc *sc) 845 1.1 tsubai { 846 1.1 tsubai int i; 847 1.1 tsubai 848 1.6 tsubai DPRINTF("mesh_reset\n"); 849 1.6 tsubai 850 1.1 tsubai /* Reset DMA first. */ 851 1.1 tsubai dbdma_reset(sc->sc_dmareg); 852 1.1 tsubai 853 1.1 tsubai /* Disable interrupts. */ 854 1.1 tsubai mesh_set_reg(sc, MESH_INTR_MASK, 0); 855 1.1 tsubai 856 1.1 tsubai mesh_set_reg(sc, MESH_SEQUENCE, MESH_CMD_RESET_MESH); 857 1.1 tsubai delay(1); 858 1.1 tsubai 859 1.1 tsubai /* Wait for reset done. */ 860 1.1 tsubai while (mesh_read_reg(sc, MESH_INTERRUPT) == 0); 861 1.1 tsubai 862 1.1 tsubai /* Clear interrupts */ 863 1.1 tsubai mesh_set_reg(sc, MESH_INTERRUPT, 0x7); 864 1.1 tsubai 865 1.1 tsubai /* Set SCSI ID */ 866 1.1 tsubai mesh_set_reg(sc, MESH_SOURCE_ID, sc->sc_id); 867 1.1 tsubai 868 1.1 tsubai /* Set to async mode by default. */ 869 1.1 tsubai mesh_set_reg(sc, MESH_SYNC_PARAM, 2); 870 1.1 tsubai 871 1.1 tsubai /* Set selection timeout to 250ms. */ 872 1.1 tsubai mesh_set_reg(sc, MESH_SEL_TIMEOUT, 250 * sc->sc_freq / 500); 873 1.1 tsubai 874 1.1 tsubai /* Enable parity check. */ 875 1.1 tsubai mesh_set_reg(sc, MESH_SEQUENCE, MESH_CMD_ENABLE_PARITY); 876 1.1 tsubai 877 1.1 tsubai /* Enable all interrupts. */ 878 1.1 tsubai mesh_set_reg(sc, MESH_INTR_MASK, 0x7); 879 1.1 tsubai 880 1.1 tsubai for (i = 0; i < 7; i++) { 881 1.1 tsubai struct mesh_tinfo *ti = &sc->sc_tinfo[i]; 882 1.1 tsubai 883 1.1 tsubai ti->flags = 0; 884 1.1 tsubai ti->period = ti->offset = 0; 885 1.6 tsubai if (sc->sc_cfflags & (0x100 << i)) 886 1.1 tsubai ti->flags |= T_SYNCNEGO; 887 1.1 tsubai } 888 1.1 tsubai sc->sc_nexus = NULL; 889 1.1 tsubai } 890 1.1 tsubai 891 1.1 tsubai int 892 1.29 dsl mesh_stp(struct mesh_softc *sc, int v) 893 1.1 tsubai { 894 1.1 tsubai /* 895 1.1 tsubai * stp(v) = 5 * clock_period (v == 0) 896 1.1 tsubai * = (v + 2) * 2 clock_period (v > 0) 897 1.1 tsubai */ 898 1.1 tsubai 899 1.1 tsubai if (v == 0) 900 1.1 tsubai return 5 * 250 / sc->sc_freq; 901 1.1 tsubai else 902 1.1 tsubai return (v + 2) * 2 * 250 / sc->sc_freq; 903 1.1 tsubai } 904 1.1 tsubai 905 1.1 tsubai void 906 1.29 dsl mesh_setsync(struct mesh_softc *sc, struct mesh_tinfo *ti) 907 1.1 tsubai { 908 1.1 tsubai int period = ti->period; 909 1.1 tsubai int offset = ti->offset; 910 1.1 tsubai int v; 911 1.1 tsubai 912 1.1 tsubai if ((ti->flags & T_SYNCMODE) == 0) 913 1.1 tsubai offset = 0; 914 1.1 tsubai 915 1.1 tsubai if (offset == 0) { /* async mode */ 916 1.1 tsubai mesh_set_reg(sc, MESH_SYNC_PARAM, 2); 917 1.1 tsubai return; 918 1.1 tsubai } 919 1.1 tsubai 920 1.1 tsubai v = period * sc->sc_freq / 250 / 2 - 2; 921 1.1 tsubai if (v < 0) 922 1.1 tsubai v = 0; 923 1.1 tsubai if (mesh_stp(sc, v) < period) 924 1.1 tsubai v++; 925 1.1 tsubai if (v > 15) 926 1.1 tsubai v = 15; 927 1.1 tsubai mesh_set_reg(sc, MESH_SYNC_PARAM, (offset << 4) | v); 928 1.1 tsubai } 929 1.1 tsubai 930 1.1 tsubai struct mesh_scb * 931 1.29 dsl mesh_get_scb(struct mesh_softc *sc) 932 1.1 tsubai { 933 1.1 tsubai struct mesh_scb *scb; 934 1.1 tsubai int s; 935 1.1 tsubai 936 1.1 tsubai s = splbio(); 937 1.6 tsubai if ((scb = sc->free_scb.tqh_first) != NULL) 938 1.6 tsubai TAILQ_REMOVE(&sc->free_scb, scb, chain); 939 1.1 tsubai splx(s); 940 1.1 tsubai 941 1.1 tsubai return scb; 942 1.1 tsubai } 943 1.1 tsubai 944 1.1 tsubai void 945 1.29 dsl mesh_free_scb(struct mesh_softc *sc, struct mesh_scb *scb) 946 1.1 tsubai { 947 1.1 tsubai int s; 948 1.1 tsubai 949 1.1 tsubai s = splbio(); 950 1.1 tsubai TAILQ_INSERT_HEAD(&sc->free_scb, scb, chain); 951 1.1 tsubai splx(s); 952 1.1 tsubai } 953 1.1 tsubai 954 1.9 bouyer void 955 1.29 dsl mesh_scsi_request(struct scsipi_channel *chan, scsipi_adapter_req_t req, void *arg) 956 1.9 bouyer { 957 1.1 tsubai struct scsipi_xfer *xs; 958 1.9 bouyer struct scsipi_periph *periph; 959 1.31 tsutsui struct mesh_softc *sc = device_private(chan->chan_adapter->adapt_dev); 960 1.1 tsubai struct mesh_scb *scb; 961 1.9 bouyer u_int flags; 962 1.1 tsubai int s; 963 1.1 tsubai 964 1.9 bouyer switch (req) { 965 1.9 bouyer case ADAPTER_REQ_RUN_XFER: 966 1.9 bouyer xs = arg; 967 1.9 bouyer periph = xs->xs_periph; 968 1.9 bouyer flags = xs->xs_control; 969 1.9 bouyer 970 1.9 bouyer 971 1.9 bouyer if ((scb = mesh_get_scb(sc)) == NULL) { 972 1.9 bouyer xs->error = XS_RESOURCE_SHORTAGE; 973 1.9 bouyer scsipi_done(xs); 974 1.9 bouyer return; 975 1.9 bouyer } 976 1.9 bouyer scb->xs = xs; 977 1.9 bouyer scb->flags = 0; 978 1.9 bouyer scb->status = 0; 979 1.9 bouyer scb->daddr = (vaddr_t)xs->data; 980 1.9 bouyer scb->dlen = xs->datalen; 981 1.9 bouyer scb->resid = xs->datalen; 982 1.12 wiz memcpy(&scb->cmd, xs->cmd, xs->cmdlen); 983 1.9 bouyer scb->cmdlen = xs->cmdlen; 984 1.9 bouyer scb->target = periph->periph_target; 985 1.9 bouyer sc->sc_imsglen = 0; /* XXX ? */ 986 1.1 tsubai 987 1.6 tsubai #ifdef MESH_DEBUG 988 1.6 tsubai { 989 1.9 bouyer int i; 990 1.9 bouyer printf("mesh_scsi_cmd: target = %d, cdb = %02x", 991 1.9 bouyer scb->target, scb->cmd.opcode); 992 1.9 bouyer for (i = 0; i < 5; i++) 993 1.9 bouyer printf(" %02x", scb->cmd.bytes[i]); 994 1.9 bouyer printf("\n"); 995 1.6 tsubai } 996 1.6 tsubai #endif 997 1.6 tsubai 998 1.9 bouyer if (flags & XS_CTL_POLL) 999 1.9 bouyer scb->flags |= MESH_POLL; 1000 1.1 tsubai #if 0 1001 1.9 bouyer if (flags & XS_CTL_DATA_OUT) 1002 1.9 bouyer scb->flags &= ~MESH_READ; 1003 1.1 tsubai #endif 1004 1.9 bouyer if (flags & XS_CTL_DATA_IN) 1005 1.9 bouyer scb->flags |= MESH_READ; 1006 1.1 tsubai 1007 1.9 bouyer s = splbio(); 1008 1.9 bouyer 1009 1.9 bouyer TAILQ_INSERT_TAIL(&sc->ready_scb, scb, chain); 1010 1.9 bouyer 1011 1.9 bouyer if (sc->sc_nexus == NULL) /* IDLE */ 1012 1.9 bouyer mesh_sched(sc); 1013 1.1 tsubai 1014 1.9 bouyer splx(s); 1015 1.1 tsubai 1016 1.9 bouyer if ((flags & XS_CTL_POLL) == 0) 1017 1.9 bouyer return; 1018 1.1 tsubai 1019 1.9 bouyer if (mesh_poll(sc, xs)) { 1020 1.31 tsutsui printf("%s: timeout\n", device_xname(sc->sc_dev)); 1021 1.9 bouyer if (mesh_poll(sc, xs)) 1022 1.31 tsutsui printf("%s: timeout again\n", 1023 1.31 tsutsui device_xname(sc->sc_dev)); 1024 1.9 bouyer } 1025 1.9 bouyer return; 1026 1.1 tsubai 1027 1.9 bouyer case ADAPTER_REQ_GROW_RESOURCES: 1028 1.9 bouyer /* XXX Not supported. */ 1029 1.9 bouyer return; 1030 1.1 tsubai 1031 1.9 bouyer case ADAPTER_REQ_SET_XFER_MODE: 1032 1.9 bouyer /* XXX Not supported. */ 1033 1.9 bouyer return; 1034 1.1 tsubai } 1035 1.9 bouyer 1036 1.1 tsubai } 1037 1.1 tsubai 1038 1.1 tsubai void 1039 1.29 dsl mesh_sched(struct mesh_softc *sc) 1040 1.1 tsubai { 1041 1.1 tsubai struct mesh_scb *scb; 1042 1.1 tsubai 1043 1.1 tsubai scb = sc->ready_scb.tqh_first; 1044 1.1 tsubai start: 1045 1.1 tsubai if (scb == NULL) 1046 1.1 tsubai return; 1047 1.1 tsubai 1048 1.1 tsubai if (sc->sc_nexus == NULL) { 1049 1.1 tsubai TAILQ_REMOVE(&sc->ready_scb, scb, chain); 1050 1.1 tsubai sc->sc_nexus = scb; 1051 1.1 tsubai mesh_select(sc, scb); 1052 1.1 tsubai return; 1053 1.1 tsubai } 1054 1.1 tsubai 1055 1.1 tsubai scb = scb->chain.tqe_next; 1056 1.1 tsubai goto start; 1057 1.1 tsubai } 1058 1.1 tsubai 1059 1.1 tsubai int 1060 1.29 dsl mesh_poll(struct mesh_softc *sc, struct scsipi_xfer *xs) 1061 1.1 tsubai { 1062 1.1 tsubai int count = xs->timeout; 1063 1.1 tsubai 1064 1.1 tsubai while (count) { 1065 1.1 tsubai if (mesh_read_reg(sc, MESH_INTERRUPT)) 1066 1.1 tsubai mesh_intr(sc); 1067 1.1 tsubai 1068 1.2 thorpej if (xs->xs_status & XS_STS_DONE) 1069 1.1 tsubai return 0; 1070 1.6 tsubai delay(1000); 1071 1.1 tsubai count--; 1072 1.1 tsubai }; 1073 1.1 tsubai return 1; 1074 1.1 tsubai } 1075 1.1 tsubai 1076 1.1 tsubai void 1077 1.29 dsl mesh_done(struct mesh_softc *sc, struct mesh_scb *scb) 1078 1.1 tsubai { 1079 1.1 tsubai struct scsipi_xfer *xs = scb->xs; 1080 1.1 tsubai 1081 1.6 tsubai DPRINTF("mesh_done\n"); 1082 1.1 tsubai 1083 1.1 tsubai sc->sc_nextstate = MESH_BUSFREE; 1084 1.1 tsubai sc->sc_nexus = NULL; 1085 1.1 tsubai 1086 1.4 thorpej callout_stop(&scb->xs->xs_callout); 1087 1.1 tsubai 1088 1.1 tsubai if (scb->status == SCSI_BUSY) { 1089 1.1 tsubai xs->error = XS_BUSY; 1090 1.1 tsubai printf("Target busy\n"); 1091 1.1 tsubai } 1092 1.1 tsubai 1093 1.23 macallan xs->status = scb->status; 1094 1.9 bouyer xs->resid = scb->resid; 1095 1.1 tsubai if (scb->status == SCSI_CHECK) { 1096 1.9 bouyer xs->error = XS_BUSY; 1097 1.1 tsubai } 1098 1.1 tsubai 1099 1.1 tsubai mesh_set_reg(sc, MESH_SYNC_PARAM, 2); 1100 1.1 tsubai 1101 1.2 thorpej if ((xs->xs_control & XS_CTL_POLL) == 0) 1102 1.1 tsubai mesh_sched(sc); 1103 1.1 tsubai 1104 1.1 tsubai scsipi_done(xs); 1105 1.1 tsubai mesh_free_scb(sc, scb); 1106 1.1 tsubai } 1107 1.1 tsubai 1108 1.1 tsubai void 1109 1.29 dsl mesh_timeout(void *arg) 1110 1.1 tsubai { 1111 1.1 tsubai struct mesh_scb *scb = arg; 1112 1.9 bouyer struct mesh_softc *sc = 1113 1.31 tsutsui device_private(scb->xs->xs_periph->periph_channel->chan_adapter->adapt_dev); 1114 1.1 tsubai int s; 1115 1.1 tsubai int status0, status1; 1116 1.21 briggs int intr, error, exception, imsk; 1117 1.1 tsubai 1118 1.31 tsutsui printf("%s: timeout state %d\n", device_xname(sc->sc_dev), 1119 1.31 tsutsui sc->sc_nextstate); 1120 1.1 tsubai 1121 1.1 tsubai intr = mesh_read_reg(sc, MESH_INTERRUPT); 1122 1.21 briggs imsk = mesh_read_reg(sc, MESH_INTR_MASK); 1123 1.1 tsubai exception = mesh_read_reg(sc, MESH_EXCEPTION); 1124 1.1 tsubai error = mesh_read_reg(sc, MESH_ERROR); 1125 1.1 tsubai status0 = mesh_read_reg(sc, MESH_BUS_STATUS0); 1126 1.1 tsubai status1 = mesh_read_reg(sc, MESH_BUS_STATUS1); 1127 1.1 tsubai 1128 1.21 briggs printf("%s: intr/msk %02x/%02x, exc %02x, err %02x, st0/1 %02x/%02x\n", 1129 1.31 tsutsui device_xname(sc->sc_dev), 1130 1.21 briggs intr, imsk, exception, error, status0, status1); 1131 1.21 briggs 1132 1.1 tsubai s = splbio(); 1133 1.1 tsubai if (sc->sc_flags & MESH_DMA_ACTIVE) { 1134 1.18 wiz printf("mesh: resetting DMA\n"); 1135 1.1 tsubai dbdma_reset(sc->sc_dmareg); 1136 1.1 tsubai } 1137 1.1 tsubai scb->xs->error = XS_TIMEOUT; 1138 1.1 tsubai 1139 1.1 tsubai mesh_set_reg(sc, MESH_SEQUENCE, MESH_CMD_BUSFREE); 1140 1.1 tsubai sc->sc_nextstate = MESH_COMPLETE; 1141 1.1 tsubai 1142 1.1 tsubai splx(s); 1143 1.1 tsubai } 1144 1.1 tsubai 1145 1.1 tsubai void 1146 1.29 dsl mesh_minphys(struct buf *bp) 1147 1.1 tsubai { 1148 1.1 tsubai if (bp->b_bcount > 64*1024) 1149 1.1 tsubai bp->b_bcount = 64*1024; 1150 1.1 tsubai 1151 1.1 tsubai minphys(bp); 1152 1.1 tsubai } 1153