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