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