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