siop.c revision 1.5 1 1.5 bouyer /* $NetBSD: siop.c,v 1.5 2000/04/27 14:06:57 bouyer Exp $ */
2 1.1 bouyer
3 1.1 bouyer /*
4 1.1 bouyer * Copyright (c) 2000 Manuel Bouyer.
5 1.1 bouyer *
6 1.1 bouyer * Redistribution and use in source and binary forms, with or without
7 1.1 bouyer * modification, are permitted provided that the following conditions
8 1.1 bouyer * are met:
9 1.1 bouyer * 1. Redistributions of source code must retain the above copyright
10 1.1 bouyer * notice, this list of conditions and the following disclaimer.
11 1.1 bouyer * 2. Redistributions in binary form must reproduce the above copyright
12 1.1 bouyer * notice, this list of conditions and the following disclaimer in the
13 1.1 bouyer * documentation and/or other materials provided with the distribution.
14 1.1 bouyer * 3. All advertising materials mentioning features or use of this software
15 1.1 bouyer * must display the following acknowledgement:
16 1.5 bouyer * This product includes software developed by Manuel Bouyer
17 1.5 bouyer * 4. The name of the author may not be used to endorse or promote products
18 1.5 bouyer * derived from this software without specific prior written permission.
19 1.1 bouyer *
20 1.5 bouyer * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
21 1.5 bouyer * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
22 1.5 bouyer * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23 1.5 bouyer * AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
24 1.5 bouyer * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 1.5 bouyer * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 1.5 bouyer * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 1.5 bouyer * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 1.5 bouyer * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 1.5 bouyer * POSSIBILITY OF SUCH DAMAGE.
30 1.1 bouyer *
31 1.1 bouyer */
32 1.1 bouyer
33 1.1 bouyer /* SYM53c7/8xx PCI-SCSI I/O Processors driver */
34 1.1 bouyer
35 1.1 bouyer #include <sys/param.h>
36 1.1 bouyer #include <sys/systm.h>
37 1.1 bouyer #include <sys/device.h>
38 1.1 bouyer #include <sys/malloc.h>
39 1.1 bouyer #include <sys/buf.h>
40 1.1 bouyer #include <sys/kernel.h>
41 1.2 bouyer #include <sys/scsiio.h>
42 1.1 bouyer
43 1.1 bouyer #include <machine/endian.h>
44 1.1 bouyer #include <machine/bus.h>
45 1.1 bouyer
46 1.1 bouyer #include <vm/vm.h>
47 1.1 bouyer #include <vm/vm_param.h>
48 1.1 bouyer #include <vm/vm_kern.h>
49 1.1 bouyer
50 1.1 bouyer #include <dev/microcode/siop/siop.out>
51 1.1 bouyer
52 1.1 bouyer #include <dev/scsipi/scsi_all.h>
53 1.1 bouyer #include <dev/scsipi/scsi_message.h>
54 1.1 bouyer #include <dev/scsipi/scsipi_all.h>
55 1.1 bouyer
56 1.1 bouyer #include <dev/scsipi/scsiconf.h>
57 1.1 bouyer
58 1.1 bouyer #include <dev/ic/siopreg.h>
59 1.1 bouyer #include <dev/ic/siopvar.h>
60 1.1 bouyer
61 1.2 bouyer #undef DEBUG
62 1.2 bouyer #undef DEBUG_INTR
63 1.2 bouyer #undef DEBUG_SHED
64 1.2 bouyer #undef DUMP_SCRIPT
65 1.2 bouyer
66 1.2 bouyer #define SIOP_STATS
67 1.2 bouyer
68 1.1 bouyer #ifndef SIOP_DEFAULT_TARGET
69 1.1 bouyer #define SIOP_DEFAULT_TARGET 7
70 1.1 bouyer #endif
71 1.1 bouyer
72 1.1 bouyer #define MEM_SIZE 8192
73 1.2 bouyer #define CMD_OFF 4096
74 1.1 bouyer
75 1.1 bouyer /* tables used by SCRIPT */
76 1.1 bouyer typedef struct scr_table {
77 1.1 bouyer u_int32_t count;
78 1.1 bouyer u_int32_t addr;
79 1.1 bouyer } scr_table_t ;
80 1.1 bouyer
81 1.1 bouyer /* Number of scatter/gather entries */
82 1.1 bouyer #define SIOP_NSG (MAXPHYS/NBPG + 1)
83 1.1 bouyer
84 1.1 bouyer /*
85 1.1 bouyer * This structure interfaces the SCRIPT with the driver; it describes a full
86 1.1 bouyer * transfert. It lives in the same chunk of DMA-safe memory as the script.
87 1.1 bouyer */
88 1.1 bouyer struct siop_xfer {
89 1.2 bouyer u_int8_t msg_out[8]; /* 0 */
90 1.2 bouyer u_int8_t msg_in[8]; /* 8 */
91 1.2 bouyer int status; /* 16 */
92 1.2 bouyer u_int32_t id; /* 20 */
93 1.2 bouyer u_int32_t pad1; /* 24 */
94 1.2 bouyer scr_table_t t_msgin; /* 28 */
95 1.2 bouyer scr_table_t t_extmsgin; /* 36 */
96 1.2 bouyer scr_table_t t_extmsgdata; /* 44 */
97 1.2 bouyer scr_table_t t_extmsgtag; /* 52 */
98 1.2 bouyer scr_table_t t_msgout; /* 60 */
99 1.2 bouyer scr_table_t cmd; /* 68 */
100 1.2 bouyer scr_table_t t_status; /* 76 */
101 1.2 bouyer scr_table_t data[SIOP_NSG]; /* 84 */
102 1.1 bouyer };
103 1.1 bouyer
104 1.1 bouyer /*
105 1.1 bouyer * This decribes a command handled by the SCSI controller
106 1.1 bouyer * These are chained in either a free list or a active list
107 1.1 bouyer * We have one queue per target + (one at the adapter's target for probe)
108 1.1 bouyer */
109 1.1 bouyer struct siop_cmd {
110 1.1 bouyer TAILQ_ENTRY (siop_cmd) next;
111 1.1 bouyer struct siop_softc *siop_sc; /* pointer to adapter */
112 1.1 bouyer struct scsipi_xfer *xs; /* xfer from the upper level */
113 1.1 bouyer struct siop_xfer *siop_table; /* tables dealing with this xfer */
114 1.2 bouyer bus_addr_t dsa; /* DSA value to load */
115 1.1 bouyer bus_dmamap_t dmamap_cmd;
116 1.1 bouyer bus_dmamap_t dmamap_data;
117 1.1 bouyer struct scsipi_sense rs_cmd; /* request sense command buffer */
118 1.2 bouyer int status;
119 1.2 bouyer int flags;
120 1.1 bouyer };
121 1.1 bouyer
122 1.1 bouyer /* status defs */
123 1.2 bouyer #define CMDST_FREE 0 /* cmd slot is free */
124 1.2 bouyer #define CMDST_READY 1 /* cmd slot is waiting for processing */
125 1.2 bouyer #define CMDST_ACTIVE 2 /* cmd slot is being processed */
126 1.2 bouyer #define CMDST_SENSE 3 /* cmd slot is being requesting sense */
127 1.2 bouyer #define CMDST_SENSE_ACTIVE 4 /* request sense active */
128 1.2 bouyer #define CMDST_SENSE_DONE 5 /* request sense done */
129 1.2 bouyer #define CMDST_DONE 6 /* cmd slot has been processed */
130 1.1 bouyer /* flags defs */
131 1.1 bouyer #define CMDFL_TIMEOUT 0x0001 /* cmd timed out */
132 1.1 bouyer
133 1.1 bouyer /* initial number of cmd descriptors */
134 1.1 bouyer #define SIOP_NCMD 10
135 1.1 bouyer
136 1.1 bouyer void siop_reset __P((struct siop_softc *));
137 1.2 bouyer void siop_handle_reset __P((struct siop_softc *));
138 1.2 bouyer void siop_scsicmd_end __P((struct siop_cmd *));
139 1.1 bouyer void siop_start __P((struct siop_softc *));
140 1.1 bouyer void siop_timeout __P((void *));
141 1.1 bouyer void siop_minphys __P((struct buf *));
142 1.2 bouyer int siop_ioctl __P((struct scsipi_link *, u_long,
143 1.2 bouyer caddr_t, int, struct proc *));
144 1.1 bouyer int siop_scsicmd __P((struct scsipi_xfer *));
145 1.1 bouyer void siop_sdp __P((struct siop_cmd *));
146 1.1 bouyer void siop_ssg __P((struct siop_cmd *));
147 1.2 bouyer void siop_dump_script __P((struct siop_softc *));
148 1.1 bouyer
149 1.1 bouyer struct scsipi_adapter siop_adapter = {
150 1.1 bouyer 0,
151 1.1 bouyer siop_scsicmd,
152 1.1 bouyer siop_minphys,
153 1.2 bouyer siop_ioctl,
154 1.1 bouyer NULL,
155 1.1 bouyer };
156 1.1 bouyer
157 1.1 bouyer struct scsipi_device siop_dev = {
158 1.1 bouyer NULL,
159 1.1 bouyer NULL,
160 1.1 bouyer NULL,
161 1.1 bouyer NULL,
162 1.1 bouyer };
163 1.1 bouyer
164 1.2 bouyer #ifdef SIOP_STATS
165 1.2 bouyer static int siop_stat_intr = 0;
166 1.2 bouyer static int siop_stat_intr_shortxfer = 0;
167 1.2 bouyer static int siop_stat_intr_sdp = 0;
168 1.2 bouyer static int siop_stat_intr_done = 0;
169 1.2 bouyer static int siop_stat_intr_reselect = 0;
170 1.2 bouyer static int siop_stat_intr_xferdisc = 0;
171 1.2 bouyer void siop_printstats __P((void));
172 1.2 bouyer #define INCSTAT(x) x++
173 1.2 bouyer #else
174 1.2 bouyer #define INCSTAT(x)
175 1.2 bouyer #endif
176 1.2 bouyer
177 1.2 bouyer static __inline__ void siop_table_sync __P((struct siop_cmd *, int));
178 1.2 bouyer static __inline__ void
179 1.2 bouyer siop_table_sync(siop_cmd, ops)
180 1.2 bouyer struct siop_cmd *siop_cmd;
181 1.2 bouyer int ops;
182 1.2 bouyer {
183 1.2 bouyer struct siop_softc *sc = siop_cmd->siop_sc;
184 1.2 bouyer bus_addr_t offset;
185 1.2 bouyer
186 1.2 bouyer offset = sc->sc_scriptdma->dm_segs[0].ds_addr - siop_cmd->dsa;
187 1.2 bouyer bus_dmamap_sync(sc->sc_dmat, sc->sc_scriptdma, offset,
188 1.2 bouyer sizeof(struct siop_xfer), ops);
189 1.2 bouyer }
190 1.2 bouyer
191 1.2 bouyer static __inline__ void siop_script_sync __P((struct siop_softc *, int));
192 1.2 bouyer static __inline__ void
193 1.2 bouyer siop_script_sync(sc, ops)
194 1.2 bouyer struct siop_softc *sc;
195 1.2 bouyer int ops;
196 1.2 bouyer {
197 1.2 bouyer bus_dmamap_sync(sc->sc_dmat, sc->sc_scriptdma, 0, CMD_OFF, ops);
198 1.2 bouyer }
199 1.2 bouyer
200 1.1 bouyer void
201 1.1 bouyer siop_attach(sc)
202 1.1 bouyer struct siop_softc *sc;
203 1.1 bouyer {
204 1.1 bouyer int error, i;
205 1.1 bouyer bus_dma_segment_t seg;
206 1.1 bouyer int rseg;
207 1.1 bouyer
208 1.1 bouyer /*
209 1.1 bouyer * Allocate DMA-safe memory for the script itself and internal
210 1.1 bouyer * variables and map it.
211 1.1 bouyer */
212 1.1 bouyer error = bus_dmamem_alloc(sc->sc_dmat, MEM_SIZE,
213 1.1 bouyer NBPG, 0, &seg, 1, &rseg, BUS_DMA_NOWAIT);
214 1.1 bouyer if (error) {
215 1.1 bouyer printf("%s: unable to allocate script DMA memory, error = %d\n",
216 1.1 bouyer sc->sc_dev.dv_xname, error);
217 1.1 bouyer return;
218 1.1 bouyer }
219 1.1 bouyer error = bus_dmamem_map(sc->sc_dmat, &seg, rseg, MEM_SIZE,
220 1.1 bouyer (caddr_t *)&sc->sc_script, BUS_DMA_NOWAIT|BUS_DMA_COHERENT);
221 1.1 bouyer if (error) {
222 1.1 bouyer printf("%s: unable to map script DMA memory, error = %d\n",
223 1.1 bouyer sc->sc_dev.dv_xname, error);
224 1.1 bouyer return;
225 1.1 bouyer }
226 1.1 bouyer error = bus_dmamap_create(sc->sc_dmat, MEM_SIZE, 1,
227 1.1 bouyer MEM_SIZE, 0, BUS_DMA_NOWAIT, &sc->sc_scriptdma);
228 1.1 bouyer if (error) {
229 1.1 bouyer printf("%s: unable to create script DMA map, error = %d\n",
230 1.1 bouyer sc->sc_dev.dv_xname, error);
231 1.1 bouyer return;
232 1.1 bouyer }
233 1.1 bouyer error = bus_dmamap_load(sc->sc_dmat, sc->sc_scriptdma, sc->sc_script,
234 1.1 bouyer MEM_SIZE, NULL, BUS_DMA_NOWAIT);
235 1.1 bouyer if (error) {
236 1.1 bouyer printf("%s: unable to load script DMA map, error = %d\n",
237 1.1 bouyer sc->sc_dev.dv_xname, error);
238 1.1 bouyer return;
239 1.1 bouyer }
240 1.1 bouyer TAILQ_INIT(&sc->free_list);
241 1.1 bouyer for (i = 0; i < 16; i++)
242 1.1 bouyer TAILQ_INIT(&sc->active_list[i]);
243 1.1 bouyer /* allocate cmd list */
244 1.2 bouyer sc->cmds =
245 1.2 bouyer malloc(sizeof(struct siop_cmd) * SIOP_NCMD, M_DEVBUF, M_NOWAIT);
246 1.2 bouyer if (sc->cmds == NULL) {
247 1.1 bouyer printf("%s: can't allocate memory for command descriptors\n",
248 1.1 bouyer sc->sc_dev.dv_xname);
249 1.1 bouyer return;
250 1.1 bouyer }
251 1.1 bouyer for (i = 0; i < SIOP_NCMD; i++) {
252 1.1 bouyer error = bus_dmamap_create(sc->sc_dmat, MAXPHYS, SIOP_NSG,
253 1.1 bouyer MAXPHYS, 0, BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW,
254 1.2 bouyer &sc->cmds[i].dmamap_data);
255 1.1 bouyer if (error) {
256 1.1 bouyer printf("%s: unable to create data DMA map for cbd %d\n",
257 1.1 bouyer sc->sc_dev.dv_xname, error);
258 1.1 bouyer return;
259 1.1 bouyer }
260 1.1 bouyer error = bus_dmamap_create(sc->sc_dmat,
261 1.1 bouyer sizeof(struct scsipi_generic), 1,
262 1.1 bouyer sizeof(struct scsipi_generic), 0,
263 1.1 bouyer BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW,
264 1.2 bouyer &sc->cmds[i].dmamap_cmd);
265 1.1 bouyer if (error) {
266 1.1 bouyer printf("%s: unable to create cmd DMA map for cbd %d\n",
267 1.1 bouyer sc->sc_dev.dv_xname, error);
268 1.1 bouyer return;
269 1.1 bouyer }
270 1.2 bouyer sc->cmds[i].siop_sc = sc;
271 1.2 bouyer sc->cmds[i].siop_table =
272 1.2 bouyer &((struct siop_xfer *)(&sc->sc_script[CMD_OFF/4]))[i];
273 1.2 bouyer sc->cmds[i].dsa = sc->sc_scriptdma->dm_segs[0].ds_addr +
274 1.2 bouyer CMD_OFF + i * sizeof(struct siop_xfer);
275 1.2 bouyer sc->cmds[i].status = CMDST_FREE;
276 1.2 bouyer sc->cmds[i].siop_table->t_msgout.count= htole32(1);
277 1.2 bouyer sc->cmds[i].siop_table->t_msgout.addr =
278 1.2 bouyer htole32(sc->cmds[i].dsa);
279 1.2 bouyer sc->cmds[i].siop_table->t_msgin.count= htole32(1);
280 1.2 bouyer sc->cmds[i].siop_table->t_msgin.addr =
281 1.2 bouyer htole32(sc->cmds[i].dsa + 8);
282 1.2 bouyer sc->cmds[i].siop_table->t_extmsgin.count= htole32(2);
283 1.2 bouyer sc->cmds[i].siop_table->t_extmsgin.addr =
284 1.4 bouyer htole32(le32toh(sc->cmds[i].siop_table->t_msgin.addr) + 1);
285 1.2 bouyer sc->cmds[i].siop_table->t_status.count= htole32(1);
286 1.2 bouyer sc->cmds[i].siop_table->t_status.addr =
287 1.4 bouyer htole32(le32toh(sc->cmds[i].siop_table->t_msgin.addr) + 8);
288 1.2 bouyer TAILQ_INSERT_TAIL(&sc->free_list, &sc->cmds[i], next);
289 1.2 bouyer #ifdef DEBUG
290 1.1 bouyer printf("tables[%d]: out=0x%x in=0x%x status=0x%x\n", i,
291 1.4 bouyer le32toh(sc->cmds[i].siop_table->t_msgin.addr),
292 1.4 bouyer le32toh(sc->cmds[i].siop_table->t_msgout.addr),
293 1.4 bouyer le32toh(sc->cmds[i].siop_table->t_status.addr));
294 1.2 bouyer #endif
295 1.1 bouyer }
296 1.2 bouyer /* compute number of sheduler slots */
297 1.2 bouyer sc->sc_nshedslots = (
298 1.2 bouyer CMD_OFF /* memory size allocated for scripts */
299 1.2 bouyer - sizeof(siop_script) /* memory for main script */
300 1.2 bouyer + 8 /* extra NOP at end of main script */
301 1.2 bouyer - sizeof(endslot_script) /* memory needed at end of sheduler */
302 1.2 bouyer ) / (sizeof(slot_script) - 8);
303 1.1 bouyer #ifdef DEBUG
304 1.2 bouyer printf("%s: script size = %d, PHY addr=0x%x, VIRT=%p nslots %d\n",
305 1.2 bouyer sc->sc_dev.dv_xname, (int)sizeof(siop_script),
306 1.2 bouyer (u_int)sc->sc_scriptdma->dm_segs[0].ds_addr, sc->sc_script,
307 1.2 bouyer sc->sc_nshedslots);
308 1.1 bouyer #endif
309 1.1 bouyer
310 1.1 bouyer sc->sc_link.adapter_softc = sc;
311 1.1 bouyer sc->sc_link.openings = 1;
312 1.1 bouyer sc->sc_link.scsipi_scsi.channel = SCSI_CHANNEL_ONLY_ONE;
313 1.1 bouyer sc->sc_link.scsipi_scsi.max_target =
314 1.1 bouyer (sc->features & SF_BUS_WIDE) ? 15 : 7;
315 1.1 bouyer sc->sc_link.scsipi_scsi.max_lun = 7;
316 1.1 bouyer sc->sc_link.scsipi_scsi.adapter_target = bus_space_read_1(sc->sc_rt,
317 1.1 bouyer sc->sc_rh, SIOP_SCID);
318 1.2 bouyer if (sc->sc_link.scsipi_scsi.adapter_target == 0 ||
319 1.2 bouyer sc->sc_link.scsipi_scsi.adapter_target >
320 1.1 bouyer sc->sc_link.scsipi_scsi.max_target)
321 1.1 bouyer sc->sc_link.scsipi_scsi.adapter_target = SIOP_DEFAULT_TARGET;
322 1.1 bouyer sc->sc_link.type = BUS_SCSI;
323 1.1 bouyer sc->sc_link.adapter = &siop_adapter;
324 1.1 bouyer sc->sc_link.device = &siop_dev;
325 1.1 bouyer sc->sc_link.flags = 0;
326 1.1 bouyer
327 1.1 bouyer siop_reset(sc);
328 1.2 bouyer #ifdef DUMP_SCRIPT
329 1.2 bouyer siop_dump_script(sc);
330 1.2 bouyer #endif
331 1.1 bouyer
332 1.1 bouyer config_found((struct device*)sc, &sc->sc_link, scsiprint);
333 1.1 bouyer }
334 1.1 bouyer
335 1.1 bouyer void
336 1.1 bouyer siop_reset(sc)
337 1.1 bouyer struct siop_softc *sc;
338 1.1 bouyer {
339 1.4 bouyer int i, j;
340 1.2 bouyer u_int32_t *scr;
341 1.2 bouyer bus_addr_t physaddr;
342 1.4 bouyer
343 1.1 bouyer /* reset the chip */
344 1.1 bouyer bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_ISTAT, ISTAT_SRST);
345 1.1 bouyer delay(1000);
346 1.1 bouyer bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_ISTAT, 0);
347 1.1 bouyer
348 1.1 bouyer /* copy and patch the script */
349 1.4 bouyer for (j = 0; j < (sizeof(siop_script) / sizeof(siop_script[0])); j++) {
350 1.4 bouyer sc->sc_script[j] = htole32(siop_script[j]);
351 1.4 bouyer }
352 1.2 bouyer /* copy the sheduler slots script */
353 1.2 bouyer for (i = 0; i < sc->sc_nshedslots; i++) {
354 1.2 bouyer scr = &sc->sc_script[Ent_sheduler / 4 + (Ent_nextslot / 4) * i];
355 1.2 bouyer physaddr = sc->sc_scriptdma->dm_segs[0].ds_addr + Ent_sheduler
356 1.2 bouyer + Ent_nextslot * i;
357 1.4 bouyer for (j = 0; j < (sizeof(slot_script) / sizeof(slot_script[0]));
358 1.4 bouyer j++) {
359 1.4 bouyer scr[j] = htole32(slot_script[j]);
360 1.4 bouyer }
361 1.2 bouyer /*
362 1.2 bouyer * save current jump offset and patch MOVE MEMORY operands
363 1.2 bouyer * to restore it.
364 1.2 bouyer */
365 1.2 bouyer scr[Ent_slotdata/4 + 1] = scr[Ent_slot/4 + 1];
366 1.2 bouyer scr[E_slot_nextp_Used[0]] = htole32(physaddr + Ent_slot + 4);
367 1.2 bouyer scr[E_slot_shed_addrsrc_Used[0]] = htole32(physaddr +
368 1.2 bouyer Ent_slotdata + 4);
369 1.2 bouyer /* JUMP selected, in main script */
370 1.2 bouyer scr[E_slot_abs_selected_Used[0]] =
371 1.2 bouyer htole32(sc->sc_scriptdma->dm_segs[0].ds_addr + Ent_selected);
372 1.2 bouyer /* JUMP addr if SELECT fail */
373 1.2 bouyer scr[E_slot_abs_reselect_Used[0]] =
374 1.2 bouyer htole32(sc->sc_scriptdma->dm_segs[0].ds_addr + Ent_reselect);
375 1.2 bouyer }
376 1.2 bouyer /* Now the final JUMP */
377 1.2 bouyer scr = &sc->sc_script[Ent_sheduler / 4 +
378 1.2 bouyer (Ent_nextslot / 4) * sc->sc_nshedslots];
379 1.4 bouyer for (j = 0; j < (sizeof(endslot_script) / sizeof(endslot_script[0]));
380 1.4 bouyer j++) {
381 1.4 bouyer scr[j] = htole32(endslot_script[j]);
382 1.4 bouyer }
383 1.2 bouyer scr[E_endslot_abs_reselect_Used[0]] =
384 1.2 bouyer htole32(sc->sc_scriptdma->dm_segs[0].ds_addr + Ent_reselect);
385 1.1 bouyer
386 1.1 bouyer /* init registers */
387 1.1 bouyer bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL0,
388 1.1 bouyer SCNTL0_ARB_MASK | SCNTL0_EPC | SCNTL0_AAP);
389 1.1 bouyer bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1, 0);
390 1.1 bouyer bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL3, 0x3);
391 1.1 bouyer bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_DIEN, 0xff);
392 1.1 bouyer bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SIEN0,
393 1.1 bouyer 0xff & ~(SIEN0_CMP | SIEN0_SEL | SIEN0_RSL));
394 1.1 bouyer bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SIEN1,
395 1.1 bouyer 0xff & ~(SIEN1_HTH | SIEN1_GEN));
396 1.1 bouyer bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST2, STEST2_EXT);
397 1.1 bouyer bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST3, STEST3_TE);
398 1.1 bouyer bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STIME0,
399 1.1 bouyer (0xb << STIME0_SEL_SHIFT));
400 1.1 bouyer bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCID,
401 1.1 bouyer sc->sc_link.scsipi_scsi.adapter_target | SCID_RRE);
402 1.1 bouyer bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_RESPID0,
403 1.1 bouyer 1 << sc->sc_link.scsipi_scsi.adapter_target);
404 1.2 bouyer bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_DCNTL, 0);
405 1.2 bouyer
406 1.2 bouyer /* start script */
407 1.2 bouyer siop_script_sync(sc, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
408 1.2 bouyer bus_space_write_4(sc->sc_rt, sc->sc_rh, SIOP_DSP,
409 1.4 bouyer sc->sc_scriptdma->dm_segs[0].ds_addr + Ent_reselect);
410 1.1 bouyer }
411 1.1 bouyer
412 1.1 bouyer #if 0
413 1.1 bouyer #define CALL_SCRIPT(ent) do {\
414 1.1 bouyer printf ("start script DSA 0x%lx DSP 0x%lx\n", \
415 1.4 bouyer siop_cmd->dsa, \
416 1.4 bouyer sc->sc_scriptdma->dm_segs[0].ds_addr + ent); \
417 1.4 bouyer bus_space_write_4(sc->sc_rt, sc->sc_rh, SIOP_DSP, sc->sc_scriptdma->dm_segs[0].ds_addr + ent); \
418 1.1 bouyer } while (0)
419 1.1 bouyer #else
420 1.1 bouyer #define CALL_SCRIPT(ent) do {\
421 1.4 bouyer bus_space_write_4(sc->sc_rt, sc->sc_rh, SIOP_DSP, sc->sc_scriptdma->dm_segs[0].ds_addr + ent); \
422 1.1 bouyer } while (0)
423 1.1 bouyer #endif
424 1.1 bouyer
425 1.1 bouyer int
426 1.1 bouyer siop_intr(v)
427 1.1 bouyer void *v;
428 1.1 bouyer {
429 1.1 bouyer struct siop_softc *sc = v;
430 1.1 bouyer struct siop_cmd *siop_cmd;
431 1.1 bouyer struct scsipi_xfer *xs;
432 1.1 bouyer u_int8_t istat, sist0, sist1, sstat1, dstat, scntl1;
433 1.1 bouyer u_int32_t irqcode;
434 1.1 bouyer int need_reset = 0;
435 1.2 bouyer int offset, target;
436 1.2 bouyer bus_addr_t dsa;
437 1.1 bouyer
438 1.1 bouyer istat = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_ISTAT);
439 1.2 bouyer if ((istat & (ISTAT_INTF | ISTAT_DIP | ISTAT_SIP)) == 0)
440 1.2 bouyer return 0;
441 1.2 bouyer INCSTAT(siop_stat_intr);
442 1.1 bouyer if (istat & ISTAT_INTF) {
443 1.1 bouyer printf("INTRF\n");
444 1.1 bouyer bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_ISTAT, ISTAT_INTF);
445 1.1 bouyer }
446 1.2 bouyer /* use DSA to find the current siop_cmd */
447 1.2 bouyer dsa = bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSA);
448 1.2 bouyer if (dsa >= sc->sc_scriptdma->dm_segs[0].ds_addr + CMD_OFF &&
449 1.2 bouyer dsa < sc->sc_scriptdma->dm_segs[0].ds_addr + CMD_OFF +
450 1.2 bouyer SIOP_NCMD * sizeof(struct siop_xfer)) {
451 1.2 bouyer dsa -= sc->sc_scriptdma->dm_segs[0].ds_addr + CMD_OFF;
452 1.2 bouyer siop_cmd = &sc->cmds[dsa / sizeof(struct siop_xfer)];
453 1.2 bouyer siop_table_sync(siop_cmd,
454 1.2 bouyer BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
455 1.2 bouyer } else {
456 1.2 bouyer printf("%s: current DSA invalid\n",
457 1.2 bouyer sc->sc_dev.dv_xname);
458 1.2 bouyer siop_cmd = NULL;
459 1.2 bouyer }
460 1.1 bouyer if (istat & ISTAT_DIP) {
461 1.1 bouyer u_int32_t *p;
462 1.1 bouyer dstat = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_DSTAT);
463 1.2 bouyer if (dstat & DSTAT_SSI) {
464 1.2 bouyer printf("single step dsp 0x%08x dsa 0x08%x\n",
465 1.2 bouyer bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSP),
466 1.2 bouyer bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSA));
467 1.2 bouyer if ((dstat & ~(DSTAT_DFE | DSTAT_SSI)) == 0 &&
468 1.2 bouyer (istat & ISTAT_SIP) == 0) {
469 1.2 bouyer bus_space_write_1(sc->sc_rt, sc->sc_rh,
470 1.2 bouyer SIOP_DCNTL, bus_space_read_1(sc->sc_rt,
471 1.2 bouyer sc->sc_rh, SIOP_DCNTL) | DCNTL_STD);
472 1.2 bouyer }
473 1.2 bouyer return 1;
474 1.2 bouyer }
475 1.2 bouyer if (dstat & ~(DSTAT_SIR | DSTAT_DFE | DSTAT_SSI)) {
476 1.1 bouyer printf("DMA IRQ:");
477 1.1 bouyer if (dstat & DSTAT_IID)
478 1.1 bouyer printf(" Illegal instruction");
479 1.1 bouyer if (dstat & DSTAT_ABRT)
480 1.1 bouyer printf(" abort");
481 1.1 bouyer if (dstat & DSTAT_BF)
482 1.1 bouyer printf(" bus fault");
483 1.1 bouyer if (dstat & DSTAT_MDPE)
484 1.1 bouyer printf(" parity");
485 1.1 bouyer if (dstat & DSTAT_DFE)
486 1.1 bouyer printf(" dma fifo empty");
487 1.1 bouyer printf(", DSP=0x%x DSA=0x%x: ",
488 1.1 bouyer bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSP),
489 1.1 bouyer bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSA));
490 1.2 bouyer p = sc->sc_script +
491 1.1 bouyer (bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSP) -
492 1.2 bouyer sc->sc_scriptdma->dm_segs[0].ds_addr - 8) / 4;
493 1.4 bouyer printf("0x%x 0x%x 0x%x 0x%x\n", le32toh(p[0]), le32toh(p[1]),
494 1.4 bouyer le32toh(p[2]), le32toh(p[3]));
495 1.2 bouyer if (siop_cmd)
496 1.1 bouyer printf("last msg_in=0x%x status=0x%x\n",
497 1.2 bouyer siop_cmd->siop_table->msg_in[0],
498 1.2 bouyer htole32(siop_cmd->siop_table->status));
499 1.1 bouyer need_reset = 1;
500 1.1 bouyer }
501 1.1 bouyer }
502 1.1 bouyer if (istat & ISTAT_SIP) {
503 1.2 bouyer /*
504 1.2 bouyer * SCSI interrupt. If current command is not active,
505 1.2 bouyer * we don't need siop_cmd
506 1.2 bouyer */
507 1.2 bouyer if (siop_cmd->status != CMDST_ACTIVE &&
508 1.2 bouyer siop_cmd->status != CMDST_SENSE_ACTIVE) {
509 1.2 bouyer siop_cmd = NULL;
510 1.2 bouyer }
511 1.1 bouyer if (istat & ISTAT_DIP)
512 1.1 bouyer delay(1);
513 1.1 bouyer sist0 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SIST0);
514 1.1 bouyer delay(1);
515 1.1 bouyer sist1 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SIST1);
516 1.1 bouyer sstat1 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SSTAT1);
517 1.1 bouyer #if 0
518 1.1 bouyer printf("scsi interrupt, sist0=0x%x sist1=0x%x sstat1=0x%x "
519 1.1 bouyer "DSA=0x%x DSP=0x%x\n", sist0, sist1,
520 1.1 bouyer bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SSTAT1),
521 1.1 bouyer bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSA),
522 1.1 bouyer bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSP));
523 1.1 bouyer #endif
524 1.1 bouyer if (siop_cmd)
525 1.1 bouyer xs = siop_cmd->xs;
526 1.1 bouyer if (sist0 & SIST0_RST) {
527 1.2 bouyer siop_handle_reset(sc);
528 1.1 bouyer siop_start(sc);
529 1.2 bouyer /* no table to flush here */
530 1.1 bouyer return 1;
531 1.1 bouyer }
532 1.1 bouyer if (sist0 & SIST0_SGE) {
533 1.1 bouyer if (siop_cmd)
534 1.1 bouyer scsi_print_addr(xs->sc_link);
535 1.1 bouyer else
536 1.1 bouyer printf("%s:", sc->sc_dev.dv_xname);
537 1.1 bouyer printf("scsi gross error\n");
538 1.1 bouyer goto reset;
539 1.1 bouyer }
540 1.1 bouyer if ((sist0 & SIST0_MA) && need_reset == 0) {
541 1.1 bouyer if (siop_cmd) {
542 1.3 bouyer /*
543 1.3 bouyer * first restore DSA, in case we were in a S/G
544 1.3 bouyer * operation.
545 1.3 bouyer */
546 1.3 bouyer bus_space_write_4(sc->sc_rt, sc->sc_rh,
547 1.4 bouyer SIOP_DSA, siop_cmd->dsa);
548 1.1 bouyer switch (sstat1 & SSTAT1_PHASE_MASK) {
549 1.1 bouyer case SSTAT1_PHASE_STATUS:
550 1.1 bouyer /*
551 1.1 bouyer * previous phase may be aborted for any reason
552 1.1 bouyer * ( for example, the target has less data to
553 1.1 bouyer * transfer than requested). Just go to status
554 1.1 bouyer * and the command should terminate.
555 1.1 bouyer */
556 1.2 bouyer INCSTAT(siop_stat_intr_shortxfer);
557 1.1 bouyer CALL_SCRIPT(Ent_status);
558 1.2 bouyer /* no table to flush here */
559 1.1 bouyer return 1;
560 1.1 bouyer case SSTAT1_PHASE_MSGIN:
561 1.1 bouyer /*
562 1.1 bouyer * target may be ready to disconnect
563 1.1 bouyer * Save data pointers just in case.
564 1.1 bouyer */
565 1.2 bouyer INCSTAT(siop_stat_intr_xferdisc);
566 1.1 bouyer siop_sdp(siop_cmd);
567 1.2 bouyer siop_table_sync(siop_cmd,
568 1.2 bouyer BUS_DMASYNC_PREREAD |
569 1.2 bouyer BUS_DMASYNC_PREWRITE);
570 1.1 bouyer CALL_SCRIPT(Ent_msgin);
571 1.1 bouyer return 1;
572 1.1 bouyer }
573 1.1 bouyer printf("%s: unexpected phase mismatch %d\n",
574 1.1 bouyer sc->sc_dev.dv_xname,
575 1.1 bouyer sstat1 & SSTAT1_PHASE_MASK);
576 1.1 bouyer } else {
577 1.1 bouyer printf("%s: phase mismatch without command\n",
578 1.1 bouyer sc->sc_dev.dv_xname);
579 1.1 bouyer }
580 1.1 bouyer need_reset = 1;
581 1.1 bouyer }
582 1.1 bouyer if (sist0 & SIST0_PAR) {
583 1.1 bouyer /* parity error, reset */
584 1.1 bouyer if (siop_cmd)
585 1.1 bouyer scsi_print_addr(xs->sc_link);
586 1.1 bouyer else
587 1.1 bouyer printf("%s:", sc->sc_dev.dv_xname);
588 1.1 bouyer printf("parity error\n");
589 1.1 bouyer need_reset = 1;
590 1.1 bouyer }
591 1.1 bouyer if ((sist1 & SIST1_STO) && need_reset == 0) {
592 1.1 bouyer /* selection time out, assume there's no device here */
593 1.1 bouyer if (siop_cmd) {
594 1.1 bouyer siop_cmd->status = CMDST_DONE;
595 1.1 bouyer xs->error = XS_SELTIMEOUT;
596 1.1 bouyer goto end;
597 1.1 bouyer } else {
598 1.1 bouyer printf("%s: selection timeout without "
599 1.1 bouyer "command\n", sc->sc_dev.dv_xname);
600 1.1 bouyer need_reset = 1;
601 1.1 bouyer }
602 1.1 bouyer }
603 1.1 bouyer if (sist0 & SIST0_UDC) {
604 1.1 bouyer /*
605 1.1 bouyer * unexpected disconnect. Usually the target signals
606 1.1 bouyer * a fatal condition this way. Attempt to get sense.
607 1.1 bouyer */
608 1.1 bouyer if (siop_cmd)
609 1.1 bouyer goto check_sense;
610 1.1 bouyer printf("%s: unexpected disconnect without "
611 1.1 bouyer "command\n", sc->sc_dev.dv_xname);
612 1.2 bouyer goto reset;
613 1.1 bouyer }
614 1.1 bouyer /* Else it's an unhandled exeption (for now). */
615 1.1 bouyer printf("%s: unhandled scsi interrupt, sist0=0x%x sist1=0x%x "
616 1.1 bouyer "sstat1=0x%x DSA=0x%x DSP=0x%x\n", sc->sc_dev.dv_xname,
617 1.1 bouyer sist0, sist1,
618 1.1 bouyer bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SSTAT1),
619 1.1 bouyer bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSA),
620 1.1 bouyer bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSP));
621 1.1 bouyer if (siop_cmd) {
622 1.1 bouyer siop_cmd->status = CMDST_DONE;
623 1.1 bouyer xs->error = XS_SELTIMEOUT;
624 1.1 bouyer goto end;
625 1.1 bouyer }
626 1.1 bouyer need_reset = 1;
627 1.1 bouyer }
628 1.1 bouyer if (need_reset) {
629 1.1 bouyer reset:
630 1.1 bouyer /* fatal error, reset the bus */
631 1.1 bouyer scntl1 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1);
632 1.1 bouyer bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1,
633 1.1 bouyer scntl1 | SCNTL1_RST);
634 1.1 bouyer /* minimum 25 us, more time won't hurt */
635 1.1 bouyer delay(100);
636 1.1 bouyer bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1, scntl1);
637 1.2 bouyer /* no table to flush here */
638 1.1 bouyer return 1;
639 1.1 bouyer }
640 1.1 bouyer
641 1.1 bouyer
642 1.1 bouyer if ((istat & ISTAT_DIP) && (dstat & DSTAT_SIR)) { /* script interrupt */
643 1.1 bouyer irqcode = bus_space_read_4(sc->sc_rt, sc->sc_rh,
644 1.1 bouyer SIOP_DSPS);
645 1.2 bouyer #ifdef DEBUG_INTR
646 1.2 bouyer printf("script interrupt 0x%x\n", irqcode);
647 1.2 bouyer #endif
648 1.2 bouyer /*
649 1.2 bouyer * an inactive command is only valid if it's a reselect
650 1.2 bouyer * interrupt: we'll change siop_cmd to point to the rigth one
651 1.2 bouyer * just here
652 1.2 bouyer */
653 1.2 bouyer if (irqcode != A_int_resel &&
654 1.2 bouyer siop_cmd->status != CMDST_ACTIVE &&
655 1.2 bouyer siop_cmd->status != CMDST_SENSE_ACTIVE) {
656 1.2 bouyer printf("%s: Aie, no command (IRQ code 0x%x current "
657 1.2 bouyer "status %d) !\n", sc->sc_dev.dv_xname,
658 1.2 bouyer irqcode, siop_cmd->status);
659 1.2 bouyer xs = NULL;
660 1.2 bouyer } else
661 1.2 bouyer xs = siop_cmd->xs;
662 1.1 bouyer switch(irqcode) {
663 1.1 bouyer case A_int_err:
664 1.2 bouyer printf("error, DSP=0x%x\n",
665 1.2 bouyer bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSP));
666 1.2 bouyer if (xs) {
667 1.2 bouyer xs->error = XS_SELTIMEOUT;
668 1.2 bouyer goto end;
669 1.2 bouyer } else {
670 1.2 bouyer goto reset;
671 1.2 bouyer }
672 1.1 bouyer case A_int_msgin:
673 1.2 bouyer if (xs)
674 1.2 bouyer scsi_print_addr(xs->sc_link);
675 1.2 bouyer else
676 1.2 bouyer printf("%s: ", sc->sc_dev.dv_xname);
677 1.2 bouyer if (siop_cmd->siop_table->msg_in[0] ==
678 1.2 bouyer MSG_MESSAGE_REJECT) {
679 1.2 bouyer printf("scsi message reject, message sent "
680 1.2 bouyer "was 0x%x\n",
681 1.2 bouyer siop_cmd->siop_table->msg_out[0]);
682 1.2 bouyer if (siop_cmd->siop_table->msg_out[0] ==
683 1.2 bouyer MSG_MESSAGE_REJECT) {
684 1.2 bouyer /* MSG_REJECT for a MSG_REJECT !*/
685 1.2 bouyer goto reset;
686 1.2 bouyer }
687 1.2 bouyer /* no table to flush here */
688 1.2 bouyer CALL_SCRIPT(Ent_msgin_ack);
689 1.2 bouyer return 1;
690 1.2 bouyer }
691 1.2 bouyer printf("unhandled message 0x%x\n",
692 1.2 bouyer siop_cmd->siop_table->msg_in[0]);
693 1.2 bouyer siop_cmd->siop_table->t_msgout.count= htole32(1);
694 1.2 bouyer siop_cmd->siop_table->t_msgout.addr =
695 1.2 bouyer htole32(siop_cmd->dsa);
696 1.2 bouyer siop_cmd->siop_table->msg_out[0] = MSG_MESSAGE_REJECT;
697 1.2 bouyer siop_table_sync(siop_cmd,
698 1.2 bouyer BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
699 1.2 bouyer CALL_SCRIPT(Ent_send_msgout);
700 1.2 bouyer return 1;
701 1.2 bouyer case A_int_extmsgin:
702 1.2 bouyer #ifdef DEBUG_INTR
703 1.2 bouyer printf("extended message: msg 0x%x len %d\n",
704 1.2 bouyer siop_cmd->siop_table->msg_in[2],
705 1.2 bouyer siop_cmd->siop_table->msg_in[1]);
706 1.2 bouyer #endif
707 1.2 bouyer siop_cmd->siop_table->t_extmsgdata.count =
708 1.2 bouyer htole32(siop_cmd->siop_table->msg_in[1] - 1);
709 1.2 bouyer siop_cmd->siop_table->t_extmsgdata.addr =
710 1.2 bouyer htole32(
711 1.4 bouyer le32toh(siop_cmd->siop_table->t_extmsgin.addr)
712 1.2 bouyer + 2);
713 1.2 bouyer siop_table_sync(siop_cmd,
714 1.2 bouyer BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
715 1.2 bouyer CALL_SCRIPT(Ent_get_extmsgdata);
716 1.2 bouyer return 1;
717 1.2 bouyer case A_int_extmsgdata:
718 1.2 bouyer #ifdef DEBUG_INTR
719 1.2 bouyer {
720 1.2 bouyer int i;
721 1.2 bouyer printf("extended message: 0x%x, data:",
722 1.2 bouyer siop_cmd->siop_table->msg_in[2]);
723 1.2 bouyer for (i = 3; i < 2 + siop_cmd->siop_table->msg_in[1];
724 1.2 bouyer i++)
725 1.2 bouyer printf(" 0x%x",
726 1.2 bouyer siop_cmd->siop_table->msg_in[i]);
727 1.2 bouyer printf("\n");
728 1.2 bouyer }
729 1.2 bouyer #endif
730 1.2 bouyer if (siop_cmd->siop_table->msg_in[2] == MSG_EXT_SDTR) {
731 1.2 bouyer /* anserw with async for now */
732 1.2 bouyer siop_cmd->siop_table->msg_out[0] = MSG_EXTENDED;
733 1.2 bouyer siop_cmd->siop_table->msg_out[1] =
734 1.2 bouyer MSG_EXT_SDTR_LEN;
735 1.2 bouyer siop_cmd->siop_table->msg_out[2] = MSG_EXT_SDTR;
736 1.2 bouyer siop_cmd->siop_table->msg_out[3] = 0;
737 1.2 bouyer siop_cmd->siop_table->msg_out[4] = 0;
738 1.2 bouyer siop_cmd->siop_table->t_msgout.count =
739 1.2 bouyer htole32(MSG_EXT_SDTR_LEN + 2);
740 1.2 bouyer siop_cmd->siop_table->t_msgout.addr =
741 1.2 bouyer htole32(siop_cmd->dsa);
742 1.2 bouyer } else {
743 1.2 bouyer /* send a message reject */
744 1.2 bouyer siop_cmd->siop_table->t_msgout.count =
745 1.2 bouyer htole32(1);
746 1.2 bouyer siop_cmd->siop_table->t_msgout.addr =
747 1.2 bouyer htole32(siop_cmd->dsa);
748 1.2 bouyer siop_cmd->siop_table->msg_out[0] =
749 1.2 bouyer MSG_MESSAGE_REJECT;
750 1.2 bouyer }
751 1.2 bouyer siop_table_sync(siop_cmd,
752 1.2 bouyer BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
753 1.2 bouyer CALL_SCRIPT(Ent_send_msgout);
754 1.2 bouyer return 1;
755 1.1 bouyer case A_int_resel: /* reselected */
756 1.2 bouyer INCSTAT(siop_stat_intr_reselect);
757 1.2 bouyer if ((siop_cmd->siop_table->msg_in[0] & 0x80) == 0) {
758 1.1 bouyer printf("%s: reselect without identify (%d)\n",
759 1.1 bouyer sc->sc_dev.dv_xname,
760 1.2 bouyer siop_cmd->siop_table->msg_in[0]);
761 1.1 bouyer goto reset;
762 1.1 bouyer }
763 1.2 bouyer target = bus_space_read_1(sc->sc_rt,
764 1.1 bouyer sc->sc_rh, SIOP_SCRATCHA);
765 1.2 bouyer if ((target & 0x80) == 0) {
766 1.2 bouyer printf("reselect without id (%d)\n", target);
767 1.1 bouyer goto reset;
768 1.1 bouyer }
769 1.2 bouyer target &= 0x0f;
770 1.1 bouyer #ifdef DEBUG_DR
771 1.1 bouyer printf("reselected by target %d lun %d\n",
772 1.2 bouyer target,
773 1.2 bouyer siop_cmd->siop_table->msg_in[0] & 0x07);
774 1.1 bouyer #endif
775 1.1 bouyer siop_cmd =
776 1.2 bouyer sc->active_list[target].tqh_first;
777 1.1 bouyer if (siop_cmd == NULL) {
778 1.1 bouyer printf("%s: reselected without cmd\n",
779 1.1 bouyer sc->sc_dev.dv_xname);
780 1.1 bouyer goto reset;
781 1.1 bouyer }
782 1.4 bouyer bus_space_write_4(sc->sc_rt, sc->sc_rh, SIOP_DSA,
783 1.4 bouyer siop_cmd->dsa);
784 1.2 bouyer /* no table to flush */
785 1.2 bouyer CALL_SCRIPT(Ent_selected);
786 1.1 bouyer return 1;
787 1.1 bouyer case A_int_disc:
788 1.2 bouyer INCSTAT(siop_stat_intr_sdp);
789 1.1 bouyer offset = bus_space_read_1(sc->sc_rt, sc->sc_rh,
790 1.1 bouyer SIOP_SCRATCHA + 1);
791 1.1 bouyer #ifdef DEBUG_DR
792 1.1 bouyer printf("disconnect offset %d\n", offset);
793 1.1 bouyer #endif
794 1.1 bouyer if (offset > SIOP_NSG) {
795 1.1 bouyer printf("%s: bad offset for disconnect (%d)\n",
796 1.1 bouyer sc->sc_dev.dv_xname, offset);
797 1.1 bouyer goto reset;
798 1.1 bouyer }
799 1.1 bouyer /*
800 1.1 bouyer * offset == SIOP_NSG may be a valid condition if
801 1.1 bouyer * we get a sdp when the xfer is done.
802 1.1 bouyer * Don't call memmove in this case.
803 1.1 bouyer */
804 1.1 bouyer if (offset < SIOP_NSG) {
805 1.1 bouyer memmove(&siop_cmd->siop_table->data[0],
806 1.1 bouyer &siop_cmd->siop_table->data[offset],
807 1.1 bouyer (SIOP_NSG - offset) * sizeof(scr_table_t));
808 1.2 bouyer siop_table_sync(siop_cmd,
809 1.2 bouyer BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
810 1.1 bouyer }
811 1.2 bouyer CALL_SCRIPT(Ent_sheduler);
812 1.1 bouyer return 1;
813 1.1 bouyer case A_int_resfail:
814 1.1 bouyer printf("reselect failed\n");
815 1.2 bouyer CALL_SCRIPT(Ent_sheduler);
816 1.1 bouyer return 1;
817 1.1 bouyer case A_int_done:
818 1.2 bouyer if (xs == NULL) {
819 1.2 bouyer printf("%s: done without command\n",
820 1.2 bouyer sc->sc_dev.dv_xname);
821 1.2 bouyer siop_cmd->status = 0;
822 1.2 bouyer CALL_SCRIPT(Ent_sheduler);
823 1.2 bouyer siop_start(sc);
824 1.2 bouyer return 1;
825 1.2 bouyer }
826 1.1 bouyer #if 0
827 1.1 bouyer printf("done, taget id 0x%x last msg in=0x%x "
828 1.1 bouyer "status=0x%x\n",
829 1.4 bouyer le32toh(siop_cmd->siop_table->id),
830 1.2 bouyer siop_cmd->siop_table->msg_in[0],
831 1.4 bouyer le32toh(siop_cmd->siop_table->status));
832 1.1 bouyer #endif
833 1.2 bouyer INCSTAT(siop_stat_intr_done);
834 1.2 bouyer if (siop_cmd->status == CMDST_SENSE_ACTIVE)
835 1.1 bouyer siop_cmd->status = CMDST_SENSE_DONE;
836 1.1 bouyer else
837 1.1 bouyer siop_cmd->status = CMDST_DONE;
838 1.4 bouyer switch(le32toh(siop_cmd->siop_table->status)) {
839 1.1 bouyer case SCSI_OK:
840 1.1 bouyer xs->error = (siop_cmd->status == CMDST_DONE) ?
841 1.1 bouyer XS_NOERROR : XS_SENSE;
842 1.1 bouyer break;
843 1.1 bouyer case SCSI_BUSY:
844 1.1 bouyer xs->error = XS_BUSY;
845 1.1 bouyer break;
846 1.1 bouyer case SCSI_CHECK:
847 1.1 bouyer check_sense:
848 1.1 bouyer if (siop_cmd->status == CMDST_SENSE_DONE) {
849 1.2 bouyer /* request sense on a request sense ? */
850 1.2 bouyer printf("request sense failed\n");
851 1.1 bouyer xs->error = XS_DRIVER_STUFFUP;
852 1.1 bouyer } else {
853 1.1 bouyer siop_cmd->status = CMDST_SENSE;
854 1.1 bouyer }
855 1.1 bouyer break;
856 1.1 bouyer case 0xff:
857 1.1 bouyer /*
858 1.1 bouyer * the status byte was not updated, cmd was
859 1.1 bouyer * aborted
860 1.1 bouyer */
861 1.1 bouyer xs->error = XS_SELTIMEOUT;
862 1.2 bouyer break;
863 1.1 bouyer default:
864 1.1 bouyer xs->error = XS_DRIVER_STUFFUP;
865 1.1 bouyer }
866 1.1 bouyer goto end;
867 1.1 bouyer default:
868 1.1 bouyer printf("unknown irqcode %x\n", irqcode);
869 1.1 bouyer xs->error = XS_SELTIMEOUT;
870 1.1 bouyer goto end;
871 1.1 bouyer }
872 1.1 bouyer return 1;
873 1.1 bouyer }
874 1.2 bouyer /* We just should't get there */
875 1.2 bouyer panic("siop_intr: I shouldn't be there !");
876 1.2 bouyer return 1;
877 1.1 bouyer end:
878 1.2 bouyer siop_scsicmd_end(siop_cmd);
879 1.2 bouyer if (siop_cmd->status == CMDST_FREE) {
880 1.2 bouyer TAILQ_REMOVE(&sc->active_list[xs->sc_link->scsipi_scsi.target],
881 1.2 bouyer siop_cmd, next);
882 1.2 bouyer TAILQ_INSERT_TAIL(&sc->free_list, siop_cmd, next);
883 1.2 bouyer }
884 1.2 bouyer bus_space_write_4(sc->sc_rt, sc->sc_rh, SIOP_DSP,
885 1.4 bouyer sc->sc_scriptdma->dm_segs[0].ds_addr + Ent_reselect);
886 1.2 bouyer siop_start(sc);
887 1.2 bouyer return 1;
888 1.2 bouyer }
889 1.2 bouyer
890 1.2 bouyer void
891 1.2 bouyer siop_scsicmd_end(siop_cmd)
892 1.2 bouyer struct siop_cmd *siop_cmd;
893 1.2 bouyer {
894 1.2 bouyer struct scsipi_xfer *xs = siop_cmd->xs;
895 1.2 bouyer struct siop_softc *sc = siop_cmd->siop_sc;
896 1.2 bouyer
897 1.1 bouyer if (siop_cmd->status != CMDST_SENSE_DONE &&
898 1.1 bouyer xs->xs_control & (XS_CTL_DATA_IN | XS_CTL_DATA_OUT)) {
899 1.1 bouyer bus_dmamap_sync(sc->sc_dmat, siop_cmd->dmamap_data, 0,
900 1.1 bouyer siop_cmd->dmamap_data->dm_mapsize,
901 1.1 bouyer (xs->xs_control & XS_CTL_DATA_IN) ?
902 1.1 bouyer BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
903 1.1 bouyer bus_dmamap_unload(sc->sc_dmat, siop_cmd->dmamap_data);
904 1.1 bouyer }
905 1.1 bouyer bus_dmamap_unload(sc->sc_dmat, siop_cmd->dmamap_cmd);
906 1.1 bouyer if (siop_cmd->status == CMDST_SENSE) {
907 1.1 bouyer /* issue a request sense for this target */
908 1.1 bouyer int error, i;
909 1.1 bouyer siop_cmd->rs_cmd.opcode = REQUEST_SENSE;
910 1.1 bouyer siop_cmd->rs_cmd.byte2 = xs->sc_link->scsipi_scsi.lun << 5;
911 1.1 bouyer siop_cmd->rs_cmd.unused[0] = siop_cmd->rs_cmd.unused[1] = 0;
912 1.1 bouyer siop_cmd->rs_cmd.length = sizeof(struct scsipi_sense_data);
913 1.1 bouyer siop_cmd->rs_cmd.control = 0;
914 1.2 bouyer siop_cmd->siop_table->status = htole32(0xff); /*invalid status*/
915 1.2 bouyer siop_cmd->siop_table->t_msgout.count= htole32(1);
916 1.2 bouyer siop_cmd->siop_table->t_msgout.addr = htole32(siop_cmd->dsa);
917 1.2 bouyer siop_cmd->siop_table->msg_out[0] =
918 1.2 bouyer MSG_IDENTIFY(xs->sc_link->scsipi_scsi.lun, 1);
919 1.1 bouyer error = bus_dmamap_load(sc->sc_dmat, siop_cmd->dmamap_cmd,
920 1.1 bouyer &siop_cmd->rs_cmd, sizeof(struct scsipi_sense),
921 1.1 bouyer NULL, BUS_DMA_NOWAIT);
922 1.1 bouyer if (error) {
923 1.1 bouyer printf("%s: unable to load cmd DMA map: %d",
924 1.1 bouyer sc->sc_dev.dv_xname, error);
925 1.1 bouyer xs->error = XS_DRIVER_STUFFUP;
926 1.1 bouyer goto out;
927 1.1 bouyer }
928 1.1 bouyer siop_cmd->siop_table->cmd.count =
929 1.1 bouyer htole32(siop_cmd->dmamap_cmd->dm_segs[0].ds_len);
930 1.1 bouyer siop_cmd->siop_table->cmd.addr =
931 1.1 bouyer htole32(siop_cmd->dmamap_cmd->dm_segs[0].ds_addr);
932 1.1 bouyer error = bus_dmamap_load(sc->sc_dmat, siop_cmd->dmamap_data,
933 1.1 bouyer &xs->sense.scsi_sense, sizeof(struct scsipi_sense_data),
934 1.1 bouyer NULL, BUS_DMA_NOWAIT);
935 1.1 bouyer if (error) {
936 1.1 bouyer printf("%s: unable to load sense DMA map: %d",
937 1.1 bouyer sc->sc_dev.dv_xname, error);
938 1.1 bouyer xs->error = XS_DRIVER_STUFFUP;
939 1.1 bouyer bus_dmamap_unload(sc->sc_dmat, siop_cmd->dmamap_cmd);
940 1.1 bouyer goto out;
941 1.1 bouyer }
942 1.1 bouyer for (i = 0; i < siop_cmd->dmamap_data->dm_nsegs; i++) {
943 1.1 bouyer siop_cmd->siop_table->data[i].count =
944 1.1 bouyer htole32(siop_cmd->dmamap_data->dm_segs[i].ds_len);
945 1.1 bouyer siop_cmd->siop_table->data[i].addr =
946 1.1 bouyer htole32(siop_cmd->dmamap_data->dm_segs[i].ds_addr);
947 1.1 bouyer }
948 1.1 bouyer bus_dmamap_sync(sc->sc_dmat, siop_cmd->dmamap_data, 0,
949 1.1 bouyer siop_cmd->dmamap_data->dm_mapsize, BUS_DMASYNC_PREREAD);
950 1.1 bouyer bus_dmamap_sync(sc->sc_dmat, siop_cmd->dmamap_cmd, 0,
951 1.1 bouyer siop_cmd->dmamap_cmd->dm_mapsize, BUS_DMASYNC_PREWRITE);
952 1.2 bouyer siop_table_sync(siop_cmd, BUS_DMASYNC_PREWRITE);
953 1.2 bouyer #if 0
954 1.2 bouyer bus_dmamap_sync(sc->sc_dmat, sc->sc_scriptdma, CMD_OFF,
955 1.2 bouyer sc->sc_scriptdma->dm_mapsize - CMD_OFF,
956 1.2 bouyer BUS_DMASYNC_PREWRITE);
957 1.2 bouyer #endif
958 1.2 bouyer return;
959 1.1 bouyer } else if (siop_cmd->status == CMDST_SENSE_DONE) {
960 1.1 bouyer bus_dmamap_sync(sc->sc_dmat, siop_cmd->dmamap_data, 0,
961 1.1 bouyer siop_cmd->dmamap_data->dm_mapsize, BUS_DMASYNC_POSTREAD);
962 1.1 bouyer bus_dmamap_unload(sc->sc_dmat, siop_cmd->dmamap_data);
963 1.1 bouyer }
964 1.1 bouyer out:
965 1.1 bouyer callout_stop(&siop_cmd->xs->xs_callout);
966 1.1 bouyer siop_cmd->status = CMDST_FREE;
967 1.1 bouyer xs->xs_status |= XS_STS_DONE;
968 1.1 bouyer xs->resid = 0;
969 1.1 bouyer scsipi_done (xs);
970 1.2 bouyer }
971 1.2 bouyer
972 1.2 bouyer /*
973 1.2 bouyer * handle a bus reset: reset chip, unqueue all active commands and report
974 1.2 bouyer * loosage to upper layer.
975 1.2 bouyer * As the upper layer may requeue immediatly we have to first store
976 1.2 bouyer * all active commands in a temporary queue.
977 1.2 bouyer */
978 1.2 bouyer void
979 1.2 bouyer siop_handle_reset(sc)
980 1.2 bouyer struct siop_softc *sc;
981 1.2 bouyer {
982 1.2 bouyer struct cmd_list reset_list;
983 1.2 bouyer struct siop_cmd *siop_cmd, *next_siop_cmd;
984 1.2 bouyer int target;
985 1.2 bouyer /*
986 1.2 bouyer * scsi bus reset. reset the chip and restart
987 1.2 bouyer * the queue. Need to clean up all active commands
988 1.2 bouyer */
989 1.2 bouyer printf("%s: scsi bus reset\n", sc->sc_dev.dv_xname);
990 1.2 bouyer /* stop, reset and restart the chip */
991 1.2 bouyer siop_reset(sc);
992 1.2 bouyer TAILQ_INIT(&reset_list);
993 1.2 bouyer /* find all active commands */
994 1.2 bouyer for (target = 0; target < 16; target++) {
995 1.2 bouyer for (siop_cmd = TAILQ_FIRST(&sc->active_list[target]);
996 1.2 bouyer siop_cmd != NULL; siop_cmd = next_siop_cmd) {
997 1.2 bouyer next_siop_cmd = TAILQ_NEXT(siop_cmd, next);
998 1.2 bouyer if (siop_cmd->status < CMDST_ACTIVE)
999 1.2 bouyer continue;
1000 1.2 bouyer printf("cmd %p (target %d) in reset list\n", siop_cmd,
1001 1.2 bouyer target);
1002 1.2 bouyer TAILQ_REMOVE( &sc->active_list[target], siop_cmd, next);
1003 1.2 bouyer TAILQ_INSERT_TAIL(&reset_list, siop_cmd, next);
1004 1.2 bouyer }
1005 1.2 bouyer }
1006 1.2 bouyer for (siop_cmd = TAILQ_FIRST(&reset_list); siop_cmd != NULL;
1007 1.2 bouyer siop_cmd = next_siop_cmd) {
1008 1.2 bouyer next_siop_cmd = TAILQ_NEXT(siop_cmd, next);
1009 1.2 bouyer siop_cmd->xs->error = (siop_cmd->flags & CMDFL_TIMEOUT) ?
1010 1.2 bouyer XS_TIMEOUT : XS_RESET;
1011 1.2 bouyer printf("cmd %p about to be processed\n", siop_cmd);
1012 1.2 bouyer TAILQ_REMOVE(&reset_list, siop_cmd, next);
1013 1.2 bouyer siop_scsicmd_end(siop_cmd);
1014 1.2 bouyer TAILQ_INSERT_TAIL(&sc->free_list, siop_cmd, next);
1015 1.2 bouyer }
1016 1.1 bouyer }
1017 1.1 bouyer
1018 1.1 bouyer void
1019 1.1 bouyer siop_minphys(bp)
1020 1.1 bouyer struct buf *bp;
1021 1.1 bouyer {
1022 1.1 bouyer minphys(bp);
1023 1.1 bouyer }
1024 1.1 bouyer
1025 1.1 bouyer int
1026 1.2 bouyer siop_ioctl(link, cmd, arg, flag, p)
1027 1.2 bouyer struct scsipi_link *link;
1028 1.2 bouyer u_long cmd;
1029 1.2 bouyer caddr_t arg;
1030 1.2 bouyer int flag;
1031 1.2 bouyer struct proc *p;
1032 1.2 bouyer {
1033 1.2 bouyer struct siop_softc *sc = link->adapter_softc;
1034 1.2 bouyer u_int8_t scntl1;
1035 1.2 bouyer int s;
1036 1.2 bouyer
1037 1.2 bouyer switch (cmd) {
1038 1.2 bouyer case SCBUSIORESET:
1039 1.2 bouyer s = splbio();
1040 1.2 bouyer scntl1 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1);
1041 1.2 bouyer bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1,
1042 1.2 bouyer scntl1 | SCNTL1_RST);
1043 1.2 bouyer /* minimum 25 us, more time won't hurt */
1044 1.2 bouyer delay(100);
1045 1.2 bouyer bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1, scntl1);
1046 1.2 bouyer splx(s);
1047 1.2 bouyer return (0);
1048 1.2 bouyer default:
1049 1.2 bouyer return (ENOTTY);
1050 1.2 bouyer }
1051 1.2 bouyer }
1052 1.2 bouyer
1053 1.2 bouyer int
1054 1.1 bouyer siop_scsicmd(xs)
1055 1.1 bouyer struct scsipi_xfer *xs;
1056 1.1 bouyer {
1057 1.1 bouyer struct siop_softc *sc = (struct siop_softc *)xs->sc_link->adapter_softc;
1058 1.1 bouyer struct siop_cmd *siop_cmd;
1059 1.1 bouyer int s, error, i;
1060 1.1 bouyer u_int32_t id;
1061 1.1 bouyer
1062 1.1 bouyer s = splbio();
1063 1.1 bouyer #if 0
1064 1.1 bouyer printf("starting cmd for %d:%d\n", xs->sc_link->scsipi_scsi.target,xs->sc_link->scsipi_scsi.lun);
1065 1.1 bouyer #endif
1066 1.1 bouyer siop_cmd = sc->free_list.tqh_first;
1067 1.1 bouyer if (siop_cmd) {
1068 1.1 bouyer TAILQ_REMOVE(&sc->free_list, siop_cmd, next);
1069 1.1 bouyer }
1070 1.1 bouyer splx(s);
1071 1.1 bouyer if (siop_cmd == NULL) {
1072 1.1 bouyer xs->error = XS_DRIVER_STUFFUP;
1073 1.1 bouyer return(TRY_AGAIN_LATER);
1074 1.1 bouyer }
1075 1.1 bouyer #ifdef DIAGNOSTIC
1076 1.1 bouyer if (siop_cmd->status != CMDST_FREE)
1077 1.1 bouyer panic("siop_scsicmd: new cmd not free");
1078 1.1 bouyer #endif
1079 1.1 bouyer siop_cmd->xs = xs;
1080 1.1 bouyer id = 0x3 << 24; /* scntl3 */
1081 1.1 bouyer id |= xs->sc_link->scsipi_scsi.target << 16; /* id */
1082 1.1 bouyer id |= 0xe0 << 8; /* scxfer */
1083 1.1 bouyer siop_cmd->siop_table->id = htole32(id);
1084 1.2 bouyer siop_cmd->siop_table->t_msgout.count= htole32(1);
1085 1.2 bouyer siop_cmd->siop_table->t_msgout.addr = htole32(siop_cmd->dsa);
1086 1.2 bouyer siop_cmd->siop_table->msg_out[0] =
1087 1.1 bouyer MSG_IDENTIFY(xs->sc_link->scsipi_scsi.lun, 1);
1088 1.2 bouyer siop_cmd->siop_table->status = htole32(0xff); /* set invalid status */
1089 1.1 bouyer
1090 1.1 bouyer /* load the DMA maps */
1091 1.1 bouyer error = bus_dmamap_load(sc->sc_dmat, siop_cmd->dmamap_cmd,
1092 1.1 bouyer xs->cmd, xs->cmdlen, NULL, BUS_DMA_NOWAIT);
1093 1.1 bouyer if (error) {
1094 1.1 bouyer printf("%s: unable to load cmd DMA map: %d",
1095 1.1 bouyer sc->sc_dev.dv_xname, error);
1096 1.1 bouyer xs->error = XS_DRIVER_STUFFUP;
1097 1.1 bouyer return(TRY_AGAIN_LATER);
1098 1.1 bouyer }
1099 1.1 bouyer siop_cmd->siop_table->cmd.count =
1100 1.1 bouyer htole32(siop_cmd->dmamap_cmd->dm_segs[0].ds_len);
1101 1.1 bouyer siop_cmd->siop_table->cmd.addr =
1102 1.1 bouyer htole32(siop_cmd->dmamap_cmd->dm_segs[0].ds_addr);
1103 1.1 bouyer if (xs->xs_control & (XS_CTL_DATA_IN | XS_CTL_DATA_OUT)) {
1104 1.1 bouyer error = bus_dmamap_load(sc->sc_dmat, siop_cmd->dmamap_data,
1105 1.1 bouyer xs->data, xs->datalen, NULL, BUS_DMA_NOWAIT);
1106 1.1 bouyer if (error) {
1107 1.1 bouyer printf("%s: unable to load cmd DMA map: %d",
1108 1.1 bouyer sc->sc_dev.dv_xname, error);
1109 1.1 bouyer xs->error = XS_DRIVER_STUFFUP;
1110 1.1 bouyer return(TRY_AGAIN_LATER);
1111 1.1 bouyer bus_dmamap_unload(sc->sc_dmat, siop_cmd->dmamap_cmd);
1112 1.1 bouyer }
1113 1.1 bouyer for (i = 0; i < siop_cmd->dmamap_data->dm_nsegs; i++) {
1114 1.1 bouyer siop_cmd->siop_table->data[i].count =
1115 1.1 bouyer htole32(siop_cmd->dmamap_data->dm_segs[i].ds_len);
1116 1.1 bouyer siop_cmd->siop_table->data[i].addr =
1117 1.1 bouyer htole32(siop_cmd->dmamap_data->dm_segs[i].ds_addr);
1118 1.1 bouyer }
1119 1.1 bouyer bus_dmamap_sync(sc->sc_dmat, siop_cmd->dmamap_data, 0,
1120 1.1 bouyer siop_cmd->dmamap_data->dm_mapsize,
1121 1.1 bouyer (xs->xs_control & XS_CTL_DATA_IN) ?
1122 1.1 bouyer BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE);
1123 1.1 bouyer }
1124 1.1 bouyer bus_dmamap_sync(sc->sc_dmat, siop_cmd->dmamap_cmd, 0,
1125 1.1 bouyer siop_cmd->dmamap_cmd->dm_mapsize, BUS_DMASYNC_PREWRITE);
1126 1.2 bouyer siop_table_sync(siop_cmd, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1127 1.2 bouyer #if 0
1128 1.1 bouyer bus_dmamap_sync(sc->sc_dmat, sc->sc_scriptdma, 0,
1129 1.1 bouyer sc->sc_scriptdma->dm_mapsize, BUS_DMASYNC_PREWRITE);
1130 1.2 bouyer #endif
1131 1.1 bouyer
1132 1.1 bouyer siop_cmd->status = CMDST_READY;
1133 1.1 bouyer s = splbio();
1134 1.1 bouyer TAILQ_INSERT_TAIL(&sc->active_list[xs->sc_link->scsipi_scsi.target],
1135 1.1 bouyer siop_cmd, next);
1136 1.2 bouyer siop_start(sc);
1137 1.1 bouyer splx(s);
1138 1.1 bouyer return (SUCCESSFULLY_QUEUED);
1139 1.1 bouyer }
1140 1.1 bouyer
1141 1.1 bouyer void
1142 1.1 bouyer siop_start(sc)
1143 1.1 bouyer struct siop_softc *sc;
1144 1.1 bouyer {
1145 1.1 bouyer struct siop_cmd *siop_cmd;
1146 1.2 bouyer u_int32_t *scr;
1147 1.2 bouyer u_int32_t dsa;
1148 1.2 bouyer u_int8_t *dsap = (u_int8_t *)&dsa;
1149 1.1 bouyer int timeout;
1150 1.2 bouyer int target, slot;
1151 1.2 bouyer int newcmd = 0;
1152 1.2 bouyer
1153 1.2 bouyer /*
1154 1.2 bouyer * first make sure to read valid data
1155 1.2 bouyer */
1156 1.2 bouyer siop_script_sync(sc, BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
1157 1.1 bouyer
1158 1.2 bouyer /*
1159 1.2 bouyer * no need to restart at slot 0 each time we're looking for a free
1160 1.2 bouyer * slot; init slot before the target loop.
1161 1.2 bouyer */
1162 1.2 bouyer slot = 0;
1163 1.2 bouyer for (target = 0; target < 16; target++) {
1164 1.2 bouyer siop_cmd = sc->active_list[target].tqh_first;
1165 1.2 bouyer if (siop_cmd == NULL)
1166 1.2 bouyer continue;
1167 1.2 bouyer if (siop_cmd->status != CMDST_READY &&
1168 1.2 bouyer siop_cmd->status != CMDST_SENSE)
1169 1.2 bouyer continue;
1170 1.2 bouyer /* mark command as active (if not reqsense) and start script */
1171 1.2 bouyer if (siop_cmd->status == CMDST_READY)
1172 1.2 bouyer siop_cmd->status = CMDST_ACTIVE;
1173 1.2 bouyer else if (siop_cmd->status == CMDST_SENSE)
1174 1.2 bouyer siop_cmd->status = CMDST_SENSE_ACTIVE;
1175 1.2 bouyer else
1176 1.2 bouyer panic("siop_start: bad status");
1177 1.2 bouyer /* find a free sheduler slot and load it */
1178 1.2 bouyer for (; slot < sc->sc_nshedslots; slot++) {
1179 1.2 bouyer scr = &sc->sc_script[Ent_sheduler / 4 +
1180 1.2 bouyer (Ent_nextslot / 4) * slot];
1181 1.2 bouyer /*
1182 1.2 bouyer * if relative addr of first jump is 0 the slot isn't
1183 1.2 bouyer * free
1184 1.2 bouyer */
1185 1.2 bouyer if (scr[Ent_slot / 4 + 1] == 0)
1186 1.2 bouyer continue;
1187 1.2 bouyer #ifdef DEBUG_SHED
1188 1.2 bouyer printf("using slot %d\n", slot);
1189 1.2 bouyer #endif
1190 1.2 bouyer /* record that we started at last one new comand */
1191 1.2 bouyer newcmd = 1;
1192 1.2 bouyer /* ok, patch script with DSA addr */
1193 1.2 bouyer dsa = siop_cmd->dsa;
1194 1.2 bouyer /*
1195 1.2 bouyer * 0x78000000 is a 'move data8 to reg'. data8 is the
1196 1.2 bouyer * second octet, reg offset is the third.
1197 1.2 bouyer */
1198 1.2 bouyer scr[Ent_idsa0 / 4] =
1199 1.2 bouyer htole32(0x78100000 | (dsap[0] << 8));
1200 1.2 bouyer scr[Ent_idsa1 / 4] =
1201 1.2 bouyer htole32(0x78110000 | (dsap[1] << 8));
1202 1.2 bouyer scr[Ent_idsa2 / 4] =
1203 1.2 bouyer htole32(0x78120000 | (dsap[2] << 8));
1204 1.2 bouyer scr[Ent_idsa3 / 4] =
1205 1.2 bouyer htole32(0x78130000 | (dsap[3] << 8));
1206 1.2 bouyer /* change status of cmd */
1207 1.2 bouyer if (siop_cmd->status == CMDST_ACTIVE) {
1208 1.2 bouyer if ((siop_cmd->xs->xs_control & XS_CTL_POLL)
1209 1.2 bouyer == 0) {
1210 1.2 bouyer /* start exire timer */
1211 1.2 bouyer timeout =
1212 1.2 bouyer siop_cmd->xs->timeout * hz / 1000;
1213 1.2 bouyer if (timeout == 0)
1214 1.2 bouyer timeout = 1;
1215 1.2 bouyer callout_reset(&siop_cmd->xs->xs_callout,
1216 1.2 bouyer timeout, siop_timeout, siop_cmd);
1217 1.2 bouyer }
1218 1.2 bouyer }
1219 1.2 bouyer /*
1220 1.2 bouyer * Change jump offset so that this slot will be
1221 1.2 bouyer * handled
1222 1.2 bouyer */
1223 1.2 bouyer scr[Ent_slot / 4 + 1] = 0;
1224 1.1 bouyer break;
1225 1.1 bouyer }
1226 1.2 bouyer /* if we didn't find any free slot no need to try next target */
1227 1.2 bouyer if (slot == sc->sc_nshedslots)
1228 1.2 bouyer break;
1229 1.1 bouyer }
1230 1.2 bouyer /* if nothing changed no need to flush cache and wakeup script */
1231 1.2 bouyer if (newcmd == 0)
1232 1.1 bouyer return;
1233 1.2 bouyer /* make sure SCRIPT processor will read valid data */
1234 1.2 bouyer siop_script_sync(sc, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1235 1.2 bouyer /* Signal script it has some work to do */
1236 1.2 bouyer bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_ISTAT, ISTAT_SIGP);
1237 1.2 bouyer /* and wait for IRQ */
1238 1.2 bouyer return;
1239 1.1 bouyer }
1240 1.1 bouyer
1241 1.1 bouyer void
1242 1.1 bouyer siop_timeout(v)
1243 1.1 bouyer void *v;
1244 1.1 bouyer {
1245 1.1 bouyer struct siop_cmd *siop_cmd = v;
1246 1.1 bouyer struct siop_softc *sc = siop_cmd->siop_sc;
1247 1.1 bouyer int s;
1248 1.1 bouyer u_int8_t scntl1;
1249 1.1 bouyer
1250 1.1 bouyer scsi_print_addr(siop_cmd->xs->sc_link);
1251 1.1 bouyer printf("command timeout\n");
1252 1.1 bouyer
1253 1.1 bouyer s = splbio();
1254 1.1 bouyer /* reset the scsi bus */
1255 1.1 bouyer scntl1 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1);
1256 1.1 bouyer bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1,
1257 1.1 bouyer scntl1 | SCNTL1_RST);
1258 1.1 bouyer /* minimum 25 us, more time won't hurt */
1259 1.1 bouyer delay(100);
1260 1.1 bouyer bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1, scntl1);
1261 1.1 bouyer
1262 1.1 bouyer /* desactivate callout */
1263 1.1 bouyer callout_stop(&siop_cmd->xs->xs_callout);
1264 1.1 bouyer /* mark command has being timed out; siop_intr will handle it */
1265 1.1 bouyer /*
1266 1.1 bouyer * mark command has being timed out and just return;
1267 1.1 bouyer * the bus reset will generate an interrupt,
1268 1.1 bouyer * it will be handled in siop_intr()
1269 1.1 bouyer */
1270 1.1 bouyer siop_cmd->flags |= CMDFL_TIMEOUT;
1271 1.1 bouyer splx(s);
1272 1.1 bouyer return;
1273 1.1 bouyer
1274 1.1 bouyer }
1275 1.1 bouyer
1276 1.1 bouyer void
1277 1.1 bouyer siop_sdp(siop_cmd)
1278 1.1 bouyer struct siop_cmd *siop_cmd;
1279 1.1 bouyer {
1280 1.1 bouyer /* save data pointer. Handle async only for now */
1281 1.1 bouyer int offset, dbc, sstat;
1282 1.1 bouyer struct siop_softc *sc = siop_cmd->siop_sc;
1283 1.1 bouyer scr_table_t *table; /* table to patch */
1284 1.1 bouyer
1285 1.1 bouyer if ((siop_cmd->xs->xs_control & (XS_CTL_DATA_OUT | XS_CTL_DATA_IN))
1286 1.1 bouyer == 0)
1287 1.1 bouyer return; /* no data pointers to save */
1288 1.1 bouyer offset = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SCRATCHA + 1);
1289 1.1 bouyer if (offset >= SIOP_NSG) {
1290 1.1 bouyer printf("%s: bad offset in siop_sdp (%d)\n",
1291 1.1 bouyer sc->sc_dev.dv_xname, offset);
1292 1.1 bouyer return;
1293 1.1 bouyer }
1294 1.1 bouyer table = &siop_cmd->siop_table->data[offset];
1295 1.1 bouyer #ifdef DEBUG_DR
1296 1.1 bouyer printf("sdp: offset %d count=%d addr=0x%x ", offset,
1297 1.1 bouyer table->count, table->addr);
1298 1.1 bouyer #endif
1299 1.1 bouyer dbc = bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DBC) & 0x00ffffff;
1300 1.1 bouyer if (siop_cmd->xs->xs_control & XS_CTL_DATA_OUT) {
1301 1.1 bouyer /* need to account stale data in FIFO */
1302 1.1 bouyer /* XXX check for large fifo */
1303 1.1 bouyer dbc += (bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_DFIFO) -
1304 1.1 bouyer (dbc & 0x7f)) & 0x7f;
1305 1.1 bouyer sstat = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SSTAT0);
1306 1.1 bouyer if (sstat & SSTAT0_OLF)
1307 1.1 bouyer dbc++;
1308 1.1 bouyer if (sstat & SSTAT0_ORF)
1309 1.1 bouyer dbc++;
1310 1.1 bouyer /* XXX check sstat1 for wide adapters */
1311 1.1 bouyer /* Flush the FIFO */
1312 1.1 bouyer bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3,
1313 1.1 bouyer bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3) |
1314 1.1 bouyer CTEST3_CLF);
1315 1.1 bouyer }
1316 1.1 bouyer table->addr =
1317 1.4 bouyer htole32(le32toh(table->addr) + le32toh(table->count) - dbc);
1318 1.1 bouyer table->count = htole32(dbc);
1319 1.1 bouyer #ifdef DEBUG_DR
1320 1.1 bouyer printf("now count=%d addr=0x%x\n", table->count, table->addr);
1321 1.1 bouyer #endif
1322 1.1 bouyer }
1323 1.2 bouyer
1324 1.2 bouyer void
1325 1.2 bouyer siop_dump_script(sc)
1326 1.2 bouyer struct siop_softc *sc;
1327 1.2 bouyer {
1328 1.2 bouyer int i;
1329 1.2 bouyer siop_script_sync(sc, BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
1330 1.2 bouyer for (i = 0; i < CMD_OFF / 4; i += 2) {
1331 1.4 bouyer printf("0x%04x: 0x%08x 0x%08x", i * 4,
1332 1.4 bouyer le32toh(sc->sc_script[i]), le32toh(sc->sc_script[i+1]));
1333 1.4 bouyer if ((le32toh(sc->sc_script[i]) & 0xe0000000) == 0xc0000000) {
1334 1.2 bouyer i++;
1335 1.4 bouyer printf(" 0x%08x", le32toh(sc->sc_script[i+1]));
1336 1.2 bouyer }
1337 1.2 bouyer printf("\n");
1338 1.2 bouyer }
1339 1.2 bouyer }
1340 1.2 bouyer
1341 1.2 bouyer #ifdef SIOP_STATS
1342 1.2 bouyer void
1343 1.2 bouyer siop_printstats()
1344 1.2 bouyer {
1345 1.2 bouyer printf("siop_stat_intr %d\n", siop_stat_intr);
1346 1.2 bouyer printf("siop_stat_intr_shortxfer %d\n", siop_stat_intr_shortxfer);
1347 1.2 bouyer printf("siop_stat_intr_xferdisc %d\n", siop_stat_intr_xferdisc);
1348 1.2 bouyer printf("siop_stat_intr_sdp %d\n", siop_stat_intr_sdp);
1349 1.2 bouyer printf("siop_stat_intr_reselect %d\n", siop_stat_intr_reselect);
1350 1.2 bouyer printf("siop_stat_intr_done %d\n", siop_stat_intr_done);
1351 1.2 bouyer }
1352 1.2 bouyer #endif
1353