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