siop.c revision 1.23
1/*	$NetBSD: siop.c,v 1.23 2000/06/26 14:21:10 mrg 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 Manuel Bouyer
17 * 4. The name of the author may not be used to endorse or promote products
18 *    derived from this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 *
31 */
32
33/* SYM53c7/8xx PCI-SCSI I/O Processors driver */
34
35#include <sys/param.h>
36#include <sys/systm.h>
37#include <sys/device.h>
38#include <sys/malloc.h>
39#include <sys/buf.h>
40#include <sys/kernel.h>
41
42#include <machine/endian.h>
43#include <machine/bus.h>
44
45#include <vm/vm.h>
46
47#include <dev/microcode/siop/siop.out>
48
49#include <dev/scsipi/scsi_all.h>
50#include <dev/scsipi/scsi_message.h>
51#include <dev/scsipi/scsipi_all.h>
52
53#include <dev/scsipi/scsiconf.h>
54
55#include <dev/ic/siopreg.h>
56#include <dev/ic/siopvar.h>
57#include <dev/ic/siopvar_common.h>
58
59#undef DEBUG
60#undef DEBUG_DR
61#undef DEBUG_INTR
62#undef DEBUG_SHED
63#undef DUMP_SCRIPT
64
65#define SIOP_STATS
66
67#ifndef SIOP_DEFAULT_TARGET
68#define SIOP_DEFAULT_TARGET 7
69#endif
70
71/* number of cmd descriptors per block */
72#define SIOP_NCMDPB (NBPG / sizeof(struct siop_xfer))
73
74void	siop_reset __P((struct siop_softc *));
75void	siop_handle_reset __P((struct siop_softc *));
76void	siop_scsicmd_end __P((struct siop_cmd *));
77void	siop_start __P((struct siop_softc *));
78void 	siop_timeout __P((void *));
79int	siop_scsicmd __P((struct scsipi_xfer *));
80void	siop_dump_script __P((struct siop_softc *));
81int	siop_morecbd __P((struct siop_softc *));
82
83struct scsipi_adapter siop_adapter = {
84	0,
85	siop_scsicmd,
86	siop_minphys,
87	siop_ioctl,
88	NULL,
89	NULL,
90};
91
92struct scsipi_device siop_dev = {
93	NULL,
94	NULL,
95	NULL,
96	NULL,
97};
98
99#ifdef SIOP_STATS
100static int siop_stat_intr = 0;
101static int siop_stat_intr_shortxfer = 0;
102static int siop_stat_intr_sdp = 0;
103static int siop_stat_intr_done = 0;
104static int siop_stat_intr_reselect = 0;
105static int siop_stat_intr_xferdisc = 0;
106void siop_printstats __P((void));
107#define INCSTAT(x) x++
108#else
109#define INCSTAT(x)
110#endif
111
112static __inline__ void siop_table_sync __P((struct siop_cmd *, int));
113static __inline__ void
114siop_table_sync(siop_cmd, ops)
115	struct siop_cmd *siop_cmd;
116	int ops;
117{
118	struct siop_softc *sc  = siop_cmd->siop_target->siop_sc;
119	bus_addr_t offset;
120
121	offset = siop_cmd->dsa -
122	    siop_cmd->siop_cbdp->xferdma->dm_segs[0].ds_addr;
123	bus_dmamap_sync(sc->sc_dmat, siop_cmd->siop_cbdp->xferdma, offset,
124	    sizeof(struct siop_xfer), ops);
125}
126
127static __inline__ void siop_shed_sync __P((struct siop_softc *, int));
128static __inline__ void
129siop_shed_sync(sc, ops)
130	struct siop_softc *sc;
131	int ops;
132{
133	bus_dmamap_sync(sc->sc_dmat, sc->sc_sheddma, 0, NBPG, ops);
134}
135
136void
137siop_attach(sc)
138	struct siop_softc *sc;
139{
140	int error, i;
141	bus_dma_segment_t seg;
142	int rseg;
143
144	/*
145	 * Allocate DMA-safe memory for the script and script scheduler
146	 * and map it.
147	 */
148	if ((sc->features & SF_CHIP_RAM) == 0) {
149		error = bus_dmamem_alloc(sc->sc_dmat, NBPG,
150		    NBPG, 0, &seg, 1, &rseg, BUS_DMA_NOWAIT);
151		if (error) {
152			printf("%s: unable to allocate script DMA memory, "
153			    "error = %d\n", sc->sc_dev.dv_xname, error);
154			return;
155		}
156		error = bus_dmamem_map(sc->sc_dmat, &seg, rseg, NBPG,
157		    (caddr_t *)&sc->sc_script, BUS_DMA_NOWAIT|BUS_DMA_COHERENT);
158		if (error) {
159			printf("%s: unable to map script DMA memory, "
160			    "error = %d\n", sc->sc_dev.dv_xname, error);
161			return;
162		}
163		error = bus_dmamap_create(sc->sc_dmat, NBPG, 1,
164		    NBPG, 0, BUS_DMA_NOWAIT, &sc->sc_scriptdma);
165		if (error) {
166			printf("%s: unable to create script DMA map, "
167			    "error = %d\n", sc->sc_dev.dv_xname, error);
168			return;
169		}
170		error = bus_dmamap_load(sc->sc_dmat, sc->sc_scriptdma,
171		    sc->sc_script,
172		    NBPG, NULL, BUS_DMA_NOWAIT);
173		if (error) {
174			printf("%s: unable to load script DMA map, "
175			    "error = %d\n", sc->sc_dev.dv_xname, error);
176			return;
177		}
178		sc->sc_scriptaddr = sc->sc_scriptdma->dm_segs[0].ds_addr;
179	}
180	error = bus_dmamem_alloc(sc->sc_dmat, NBPG,
181	    NBPG, 0, &seg, 1, &rseg, BUS_DMA_NOWAIT);
182	if (error) {
183		printf("%s: unable to allocate scheduler DMA memory, "
184		    "error = %d\n", sc->sc_dev.dv_xname, error);
185		return;
186	}
187	error = bus_dmamem_map(sc->sc_dmat, &seg, rseg, NBPG,
188	    (caddr_t *)&sc->sc_shed, BUS_DMA_NOWAIT|BUS_DMA_COHERENT);
189	if (error) {
190		printf("%s: unable to map scheduler DMA memory, error = %d\n",
191		    sc->sc_dev.dv_xname, error);
192		return;
193	}
194	error = bus_dmamap_create(sc->sc_dmat, NBPG, 1,
195	    NBPG, 0, BUS_DMA_NOWAIT, &sc->sc_sheddma);
196	if (error) {
197		printf("%s: unable to create scheduler DMA map, error = %d\n",
198		    sc->sc_dev.dv_xname, error);
199		return;
200	}
201	error = bus_dmamap_load(sc->sc_dmat, sc->sc_sheddma, sc->sc_shed,
202	    NBPG, NULL, BUS_DMA_NOWAIT);
203	if (error) {
204		printf("%s: unable to load scheduler DMA map, error = %d\n",
205		    sc->sc_dev.dv_xname, error);
206		return;
207	}
208	TAILQ_INIT(&sc->free_list);
209	TAILQ_INIT(&sc->cmds);
210	/* compute number of scheduler slots */
211	sc->sc_nshedslots = (
212	    NBPG /* memory size allocated for scheduler */
213	    - sizeof(endslot_script) /* memory needed at end of scheduler */
214	    ) / (sizeof(slot_script) - 8);
215	sc->sc_currshedslot = 0;
216#ifdef DEBUG
217	printf("%s: script size = %d, PHY addr=0x%x, VIRT=%p nslots %d\n",
218	    sc->sc_dev.dv_xname, (int)sizeof(siop_script),
219	    sc->sc_scriptaddr, sc->sc_script, sc->sc_nshedslots);
220#endif
221
222	sc->sc_link.adapter_softc = sc;
223	sc->sc_link.openings = 1;
224	sc->sc_link.scsipi_scsi.channel = SCSI_CHANNEL_ONLY_ONE;
225	sc->sc_link.scsipi_scsi.max_target  =
226	    (sc->features & SF_BUS_WIDE) ? 15 : 7;
227	sc->sc_link.scsipi_scsi.max_lun = 7;
228	sc->sc_link.scsipi_scsi.adapter_target = bus_space_read_1(sc->sc_rt,
229	    sc->sc_rh, SIOP_SCID);
230	if (sc->sc_link.scsipi_scsi.adapter_target == 0 ||
231	    sc->sc_link.scsipi_scsi.adapter_target >
232	    sc->sc_link.scsipi_scsi.max_target)
233		sc->sc_link.scsipi_scsi.adapter_target = SIOP_DEFAULT_TARGET;
234	sc->sc_link.type = BUS_SCSI;
235	sc->sc_link.adapter = &siop_adapter;
236	sc->sc_link.device = &siop_dev;
237	sc->sc_link.flags  = 0;
238
239	for (i = 0; i < 16; i++)
240		sc->targets[i] = NULL;
241
242	/* find min/max sync period for this chip */
243	sc->maxsync = 0;
244	sc->minsync = 255;
245	for (i = 0; i < sizeof(scf_period) / sizeof(scf_period[0]); i++) {
246		if (sc->clock_period != scf_period[i].clock)
247			continue;
248		if (sc->maxsync < scf_period[i].period)
249			sc->maxsync = scf_period[i].period;
250		if (sc->minsync > scf_period[i].period)
251			sc->minsync = scf_period[i].period;
252	}
253	if (sc->maxsync == 255 || sc->minsync == 0)
254		panic("siop: can't find my sync parameters\n");
255	siop_reset(sc);
256#ifdef DUMP_SCRIPT
257	siop_dump_script(sc);
258#endif
259
260	config_found((struct device*)sc, &sc->sc_link, scsiprint);
261}
262
263void
264siop_reset(sc)
265	struct siop_softc *sc;
266{
267	int i, j;
268	u_int32_t *scr;
269	bus_addr_t physaddr;
270
271	siop_common_reset(sc);
272
273	/* copy and patch the script */
274	if (sc->features & SF_CHIP_RAM) {
275		bus_space_write_region_4(sc->sc_ramt, sc->sc_ramh, 0,
276		    siop_script, sizeof(siop_script) / sizeof(siop_script[0]));
277		for (j = 0; j <
278		    (sizeof(E_script_abs_shed_Used) /
279		    sizeof(E_script_abs_shed_Used[0]));
280		    j++) {
281			bus_space_write_4(sc->sc_ramt, sc->sc_ramh,
282			    E_script_abs_shed_Used[j] * 4,
283			    sc->sc_sheddma->dm_segs[0].ds_addr);
284		}
285	} else {
286		for (j = 0;
287		    j < (sizeof(siop_script) / sizeof(siop_script[0])); j++) {
288			sc->sc_script[j] = htole32(siop_script[j]);
289		}
290		for (j = 0; j <
291		    (sizeof(E_script_abs_shed_Used) /
292		    sizeof(E_script_abs_shed_Used[0]));
293		    j++) {
294			sc->sc_script[E_script_abs_shed_Used[j]] =
295				htole32(sc->sc_sheddma->dm_segs[0].ds_addr);
296		}
297	}
298	/* copy and init the scheduler slots script */
299	for (i = 0; i < sc->sc_nshedslots; i++) {
300		scr = &sc->sc_shed[(Ent_nextslot / 4) * i];
301		physaddr = sc->sc_sheddma->dm_segs[0].ds_addr +
302		    Ent_nextslot * i;
303		for (j = 0; j < (sizeof(slot_script) / sizeof(slot_script[0]));
304		    j++) {
305			scr[j] = htole32(slot_script[j]);
306		}
307		/*
308		 * save current jump offset and patch MOVE MEMORY operands
309		 * to restore it.
310		 */
311		scr[Ent_slotdata/4 + 1] = scr[Ent_slot/4 + 1];
312		scr[E_slot_nextp_Used[0]] = htole32(physaddr + Ent_slot + 4);
313		scr[E_slot_shed_addrsrc_Used[0]] = htole32(physaddr +
314		    Ent_slotdata + 4);
315		/* JUMP selected, in main script */
316		scr[E_slot_abs_selected_Used[0]] =
317		   htole32(sc->sc_scriptaddr + Ent_selected);
318		/* JUMP addr if SELECT fail */
319		scr[E_slot_abs_reselect_Used[0]] =
320		   htole32(sc->sc_scriptaddr + Ent_reselect);
321	}
322	/* Now the final JUMP */
323	scr = &sc->sc_shed[(Ent_nextslot / 4) * sc->sc_nshedslots];
324	for (j = 0; j < (sizeof(endslot_script) / sizeof(endslot_script[0]));
325	    j++) {
326		scr[j] = htole32(endslot_script[j]);
327	}
328	scr[E_endslot_abs_reselect_Used[0]] =
329	    htole32(sc->sc_scriptaddr + Ent_reselect);
330
331	/* start script */
332	if ((sc->features & SF_CHIP_RAM) == 0) {
333		bus_dmamap_sync(sc->sc_dmat, sc->sc_scriptdma, 0, NBPG,
334		    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
335	}
336	siop_shed_sync(sc, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
337	bus_space_write_4(sc->sc_rt, sc->sc_rh, SIOP_DSP,
338	    sc->sc_scriptaddr + Ent_reselect);
339}
340
341#if 0
342#define CALL_SCRIPT(ent) do {\
343	printf ("start script DSA 0x%lx DSP 0x%lx\n", \
344	    siop_cmd->dsa, \
345	    sc->sc_scriptaddr + ent); \
346bus_space_write_4(sc->sc_rt, sc->sc_rh, SIOP_DSP, sc->sc_scriptaddr + ent); \
347} while (0)
348#else
349#define CALL_SCRIPT(ent) do {\
350bus_space_write_4(sc->sc_rt, sc->sc_rh, SIOP_DSP, sc->sc_scriptaddr + ent); \
351} while (0)
352#endif
353
354int
355siop_intr(v)
356	void *v;
357{
358	struct siop_softc *sc = v;
359	struct siop_target *siop_target;
360	struct siop_cmd *siop_cmd;
361	struct scsipi_xfer *xs;
362	int istat, sist0, sist1, sstat1, dstat, scntl1;
363	u_int32_t irqcode;
364	int need_reset = 0;
365	int offset, target, lun;
366	bus_addr_t dsa;
367	struct siop_cbd *cbdp;
368
369	istat = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_ISTAT);
370	if ((istat & (ISTAT_INTF | ISTAT_DIP | ISTAT_SIP)) == 0)
371		return 0;
372	INCSTAT(siop_stat_intr);
373	if (istat & ISTAT_INTF) {
374		printf("INTRF\n");
375		bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_ISTAT, ISTAT_INTF);
376	}
377	/* use DSA to find the current siop_cmd */
378	dsa = bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSA);
379	for (cbdp = TAILQ_FIRST(&sc->cmds); cbdp != NULL;
380	    cbdp = TAILQ_NEXT(cbdp, next)) {
381		if (dsa >= cbdp->xferdma->dm_segs[0].ds_addr &&
382	    	    dsa < cbdp->xferdma->dm_segs[0].ds_addr + NBPG) {
383			dsa -= cbdp->xferdma->dm_segs[0].ds_addr;
384			siop_cmd = &cbdp->cmds[dsa / sizeof(struct siop_xfer)];
385			siop_table_sync(siop_cmd,
386			    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
387			break;
388		}
389	}
390	if (cbdp == NULL) {
391		siop_cmd = NULL;
392	}
393	if (istat & ISTAT_DIP) {
394		u_int32_t *p;
395		dstat = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_DSTAT);
396		if (dstat & DSTAT_SSI) {
397			printf("single step dsp 0x%08x dsa 0x08%x\n",
398			    (int)(bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSP) -
399			    sc->sc_scriptaddr),
400			    bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSA));
401			if ((dstat & ~(DSTAT_DFE | DSTAT_SSI)) == 0 &&
402			    (istat & ISTAT_SIP) == 0) {
403				bus_space_write_1(sc->sc_rt, sc->sc_rh,
404				    SIOP_DCNTL, bus_space_read_1(sc->sc_rt,
405				    sc->sc_rh, SIOP_DCNTL) | DCNTL_STD);
406			}
407			return 1;
408		}
409		if (dstat & ~(DSTAT_SIR | DSTAT_DFE | DSTAT_SSI)) {
410		printf("DMA IRQ:");
411		if (dstat & DSTAT_IID)
412			printf(" Illegal instruction");
413		if (dstat & DSTAT_ABRT)
414			printf(" abort");
415		if (dstat & DSTAT_BF)
416			printf(" bus fault");
417		if (dstat & DSTAT_MDPE)
418			printf(" parity");
419		if (dstat & DSTAT_DFE)
420			printf(" dma fifo empty");
421		printf(", DSP=0x%x DSA=0x%x: ",
422		    (int)(bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSP) -
423		    sc->sc_scriptaddr),
424		    bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSA));
425		p = sc->sc_script +
426		    (bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSP) -
427		    sc->sc_scriptaddr - 8) / 4;
428		printf("0x%x 0x%x 0x%x 0x%x\n", le32toh(p[0]), le32toh(p[1]),
429		    le32toh(p[2]), le32toh(p[3]));
430		if (siop_cmd)
431			printf("last msg_in=0x%x status=0x%x\n",
432			    siop_cmd->siop_table->msg_in[0],
433			    le32toh(siop_cmd->siop_table->status));
434		else
435			printf("%s: current DSA invalid\n",
436			    sc->sc_dev.dv_xname);
437		need_reset = 1;
438		}
439	}
440	if (istat & ISTAT_SIP) {
441		/*
442		 * SCSI interrupt. If current command is not active,
443		 * we don't need siop_cmd
444		 */
445		if (siop_cmd && siop_cmd->status != CMDST_ACTIVE &&
446		    siop_cmd->status != CMDST_SENSE_ACTIVE) {
447			siop_cmd = NULL;
448		}
449		if (istat & ISTAT_DIP)
450			delay(10);
451		sist0 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SIST0);
452			delay(10);
453		sist1 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SIST1);
454		sstat1 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SSTAT1);
455#ifdef DEBUG_INTR
456		printf("scsi interrupt, sist0=0x%x sist1=0x%x sstat1=0x%x "
457		    "DSA=0x%x DSP=0x%lx\n", sist0, sist1,
458		    bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SSTAT1),
459		    bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSA),
460		    (u_long)(bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSP) -
461		    sc->sc_scriptaddr));
462#endif
463		if (siop_cmd) {
464			xs = siop_cmd->xs;
465			siop_target = siop_cmd->siop_target;
466		}
467		if (sist0 & SIST0_RST) {
468			siop_handle_reset(sc);
469			siop_start(sc);
470			/* no table to flush here */
471			return 1;
472		}
473		if (sist0 & SIST0_SGE) {
474			if (siop_cmd)
475				scsi_print_addr(xs->sc_link);
476			else
477				printf("%s:", sc->sc_dev.dv_xname);
478			printf("scsi gross error\n");
479			goto reset;
480		}
481		if ((sist0 & SIST0_MA) && need_reset == 0) {
482			if (siop_cmd) {
483				int scratcha0;
484				dstat = bus_space_read_1(sc->sc_rt, sc->sc_rh,
485				    SIOP_DSTAT);
486				/*
487				 * first restore DSA, in case we were in a S/G
488				 * operation.
489				 */
490				bus_space_write_4(sc->sc_rt, sc->sc_rh,
491				    SIOP_DSA, siop_cmd->dsa);
492				scratcha0 = bus_space_read_1(sc->sc_rt,
493				    sc->sc_rh, SIOP_SCRATCHA);
494				switch (sstat1 & SSTAT1_PHASE_MASK) {
495				case SSTAT1_PHASE_STATUS:
496				/*
497				 * previous phase may be aborted for any reason
498				 * ( for example, the target has less data to
499				 * transfer than requested). Just go to status
500				 * and the command should terminate.
501				 */
502					INCSTAT(siop_stat_intr_shortxfer);
503					CALL_SCRIPT(Ent_status);
504					if ((dstat & DSTAT_DFE) == 0)
505						siop_clearfifo(sc);
506					/* no table to flush here */
507					return 1;
508				case SSTAT1_PHASE_MSGIN:
509					/*
510					 * target may be ready to disconnect
511					 * Save data pointers just in case.
512					 */
513					INCSTAT(siop_stat_intr_xferdisc);
514					if (scratcha0 & A_flag_data)
515						siop_sdp(siop_cmd);
516					else if ((dstat & DSTAT_DFE) == 0)
517						siop_clearfifo(sc);
518					bus_space_write_1(sc->sc_rt, sc->sc_rh,
519					    SIOP_SCRATCHA,
520					    scratcha0 & ~A_flag_data);
521					siop_table_sync(siop_cmd,
522					    BUS_DMASYNC_PREREAD |
523					    BUS_DMASYNC_PREWRITE);
524					CALL_SCRIPT(Ent_msgin);
525					return 1;
526				}
527				printf("%s: unexpected phase mismatch %d\n",
528				    sc->sc_dev.dv_xname,
529				    sstat1 & SSTAT1_PHASE_MASK);
530			} else {
531				printf("%s: phase mismatch without command\n",
532				    sc->sc_dev.dv_xname);
533			}
534			need_reset = 1;
535		}
536		if (sist0 & SIST0_PAR) {
537			/* parity error, reset */
538			if (siop_cmd)
539				scsi_print_addr(xs->sc_link);
540			else
541				printf("%s:", sc->sc_dev.dv_xname);
542			printf("parity error\n");
543			goto reset;
544		}
545		if ((sist1 & SIST1_STO) && need_reset == 0) {
546			/* selection time out, assume there's no device here */
547			if (siop_cmd) {
548				siop_cmd->status = CMDST_DONE;
549				xs->error = XS_SELTIMEOUT;
550				goto end;
551			} else {
552				printf("%s: selection timeout without "
553				    "command\n", sc->sc_dev.dv_xname);
554				need_reset = 1;
555			}
556		}
557		if (sist0 & SIST0_UDC) {
558			/*
559			 * unexpected disconnect. Usually the target signals
560			 * a fatal condition this way. Attempt to get sense.
561			 */
562			 if (siop_cmd)
563				goto check_sense;
564			printf("%s: unexpected disconnect without "
565			    "command\n", sc->sc_dev.dv_xname);
566			goto reset;
567		}
568		if (sist1 & SIST1_SBMC) {
569			/* SCSI bus mode change */
570			if (siop_modechange(sc) == 0 || need_reset == 1)
571				goto reset;
572			if ((istat & ISTAT_DIP) && (dstat & DSTAT_SIR)) {
573				/*
574				 * we have a script interrupt, it will
575				 * restart the script.
576				 */
577				goto scintr;
578			}
579			/*
580			 * else we have to restart it ourselve, at the
581			 * interrupted instruction.
582			 */
583			bus_space_write_4(sc->sc_rt, sc->sc_rh, SIOP_DSP,
584			    bus_space_read_4(sc->sc_rt, sc->sc_rh,
585			    SIOP_DSP) - 8);
586			return 1;
587		}
588		/* Else it's an unhandled exeption (for now). */
589		printf("%s: unhandled scsi interrupt, sist0=0x%x sist1=0x%x "
590		    "sstat1=0x%x DSA=0x%x DSP=0x%x\n", sc->sc_dev.dv_xname,
591		    sist0, sist1,
592		    bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SSTAT1),
593		    bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSA),
594		    (int)(bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSP) -
595		    sc->sc_scriptaddr));
596		if (siop_cmd) {
597			siop_cmd->status = CMDST_DONE;
598			xs->error = XS_SELTIMEOUT;
599			goto end;
600		}
601		need_reset = 1;
602	}
603	if (need_reset) {
604reset:
605		/* fatal error, reset the bus */
606		scntl1 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1);
607		bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1,
608		    scntl1 | SCNTL1_RST);
609		/* minimum 25 us, more time won't hurt */
610		delay(100);
611		bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1, scntl1);
612		/* no table to flush here */
613		return 1;
614	}
615
616scintr:
617	if ((istat & ISTAT_DIP) && (dstat & DSTAT_SIR)) { /* script interrupt */
618		irqcode = bus_space_read_4(sc->sc_rt, sc->sc_rh,
619		    SIOP_DSPS);
620#ifdef DEBUG_INTR
621		printf("script interrupt 0x%x\n", irqcode);
622#endif
623		if (siop_cmd == NULL) {
624			printf("%s: script interrupt (0x%x) with invalid "
625			    "DSA !!!\n", sc->sc_dev.dv_xname, irqcode);
626			goto reset;
627		}
628		/*
629		 * an inactive command is only valid if it's a reselect
630		 * interrupt: we'll change siop_cmd to point to the rigth one
631		 * just here
632		 */
633		if (irqcode != A_int_resel && irqcode != A_int_reseltag &&
634		    siop_cmd->status != CMDST_ACTIVE &&
635		    siop_cmd->status != CMDST_SENSE_ACTIVE) {
636			printf("%s: Aie, no command (IRQ code 0x%x current "
637			    "status %d) !\n", sc->sc_dev.dv_xname,
638			    irqcode, siop_cmd->status);
639			xs = NULL;
640		} else {
641			xs = siop_cmd->xs;
642			siop_target = siop_cmd->siop_target;
643		}
644		switch(irqcode) {
645		case A_int_err:
646			printf("error, DSP=0x%x\n",
647			    (int)(bus_space_read_4(sc->sc_rt, sc->sc_rh,
648			    SIOP_DSP) - sc->sc_scriptaddr));
649			if (xs) {
650				xs->error = XS_SELTIMEOUT;
651				goto end;
652			} else {
653				goto reset;
654			}
655		case A_int_msgin:
656			if (siop_cmd->siop_table->msg_in[0] ==
657			    MSG_MESSAGE_REJECT) {
658				int msg, extmsg;
659				if (siop_cmd->siop_table->msg_out[0] & 0x80) {
660					/*
661					 * message was part of a identify +
662					 * something else. Identify shoudl't
663					 * have been rejected.
664					 */
665					msg = siop_cmd->siop_table->msg_out[1];
666					extmsg =
667					    siop_cmd->siop_table->msg_out[3];
668				} else {
669					msg = siop_cmd->siop_table->msg_out[0];
670					extmsg =
671					    siop_cmd->siop_table->msg_out[2];
672				}
673				if (msg == MSG_MESSAGE_REJECT) {
674					/* MSG_REJECT  for a MSG_REJECT  !*/
675					if (xs)
676						scsi_print_addr(xs->sc_link);
677					else
678						printf("%s: ",
679						   sc->sc_dev.dv_xname);
680					printf("our reject message was "
681					    "rejected\n");
682					goto reset;
683				}
684				if (msg == MSG_EXTENDED &&
685				    extmsg == MSG_EXT_WDTR) {
686					/* WDTR rejected, initiate sync */
687					printf("%s: target %d using 8bit "
688					    "transfers\n", sc->sc_dev.dv_xname,
689					    xs->sc_link->scsipi_scsi.target);
690					siop_target->status = TARST_SYNC_NEG;
691					siop_cmd->siop_table->msg_out[0] =
692					    MSG_EXTENDED;
693					siop_cmd->siop_table->msg_out[1] =
694					    MSG_EXT_SDTR_LEN;
695					siop_cmd->siop_table->msg_out[2] =
696					    MSG_EXT_SDTR;
697					siop_cmd->siop_table->msg_out[3] =
698					    sc->minsync;
699					siop_cmd->siop_table->msg_out[4] =
700					    sc->maxoff;
701					siop_cmd->siop_table->t_msgout.count =
702					    htole32(MSG_EXT_SDTR_LEN + 2);
703					siop_cmd->siop_table->t_msgout.addr =
704					    htole32(siop_cmd->dsa);
705					siop_table_sync(siop_cmd,
706					    BUS_DMASYNC_PREREAD |
707					    BUS_DMASYNC_PREWRITE);
708					CALL_SCRIPT(Ent_send_msgout);
709					return 1;
710				} else if (msg == MSG_EXTENDED &&
711				    extmsg == MSG_EXT_SDTR) {
712					/* sync rejected */
713					printf("%s: target %d asynchronous\n",
714					    sc->sc_dev.dv_xname,
715					    xs->sc_link->scsipi_scsi.target);
716					siop_cmd->siop_target->status =
717					    TARST_OK;
718					/* no table to flush here */
719					CALL_SCRIPT(Ent_msgin_ack);
720					return 1;
721				}
722				if (xs)
723					scsi_print_addr(xs->sc_link);
724				else
725					printf("%s: ", sc->sc_dev.dv_xname);
726				if (msg == MSG_EXTENDED) {
727					printf("scsi message reject, extended "
728					    "message sent was 0x%x\n", extmsg);
729				} else {
730					printf("scsi message reject, message "
731					    "sent was 0x%x\n", msg);
732				}
733				/* no table to flush here */
734				CALL_SCRIPT(Ent_msgin_ack);
735				return 1;
736			}
737			if (xs)
738				scsi_print_addr(xs->sc_link);
739			else
740				printf("%s: ", sc->sc_dev.dv_xname);
741			printf("unhandled message 0x%x\n",
742			    siop_cmd->siop_table->msg_in[0]);
743			siop_cmd->siop_table->t_msgout.count= htole32(1);
744			siop_cmd->siop_table->t_msgout.addr =
745			    htole32(siop_cmd->dsa);
746			siop_cmd->siop_table->msg_out[0] = MSG_MESSAGE_REJECT;
747			siop_table_sync(siop_cmd,
748			    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
749			CALL_SCRIPT(Ent_send_msgout);
750			return 1;
751		case A_int_extmsgin:
752#ifdef DEBUG_INTR
753			printf("extended message: msg 0x%x len %d\n",
754			    siop_cmd->siop_table->msg_in[2],
755			    siop_cmd->siop_table->msg_in[1]);
756#endif
757			if (siop_cmd->siop_table->msg_in[1] > 6)
758				printf("%s: extended message too big (%d)\n",
759				    sc->sc_dev.dv_xname,
760				    siop_cmd->siop_table->msg_in[1]);
761			siop_cmd->siop_table->t_extmsgdata.count =
762			    htole32(siop_cmd->siop_table->msg_in[1] - 1);
763			siop_cmd->siop_table->t_extmsgdata.addr =
764			    htole32(
765			    le32toh(siop_cmd->siop_table->t_extmsgin.addr)
766			    + 2);
767			siop_table_sync(siop_cmd,
768			    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
769			CALL_SCRIPT(Ent_get_extmsgdata);
770			return 1;
771		case A_int_extmsgdata:
772#ifdef DEBUG_INTR
773			{
774			int i;
775			printf("extended message: 0x%x, data:",
776			    siop_cmd->siop_table->msg_in[2]);
777			for (i = 3; i < 2 + siop_cmd->siop_table->msg_in[1];
778			    i++)
779				printf(" 0x%x",
780				    siop_cmd->siop_table->msg_in[i]);
781			printf("\n");
782			}
783#endif
784			if (siop_cmd->siop_table->msg_in[2] == MSG_EXT_WDTR) {
785				switch (siop_wdtr_neg(siop_cmd)) {
786				case SIOP_NEG_NOP:
787					break;
788				case SIOP_NEG_MSGOUT:
789					siop_table_sync(siop_cmd,
790					    BUS_DMASYNC_PREREAD |
791					    BUS_DMASYNC_PREWRITE);
792					CALL_SCRIPT(Ent_send_msgout);
793					break;
794				default:
795					panic("invalid retval from "
796					    "siop_wdtr_neg()");
797				}
798				return(1);
799			}
800			if (siop_cmd->siop_table->msg_in[2] == MSG_EXT_SDTR) {
801				switch (siop_sdtr_neg(siop_cmd)) {
802				case SIOP_NEG_NOP:
803					break;
804				case SIOP_NEG_MSGOUT:
805					siop_table_sync(siop_cmd,
806					    BUS_DMASYNC_PREREAD |
807					    BUS_DMASYNC_PREWRITE);
808					CALL_SCRIPT(Ent_send_msgout);
809					break;
810				case SIOP_NEG_ACK:
811					CALL_SCRIPT(Ent_msgin_ack);
812					break;
813				default:
814					panic("invalid retval from "
815					    "siop_wdtr_neg()");
816				}
817				return(1);
818			}
819			/* send a message reject */
820			siop_cmd->siop_table->t_msgout.count =
821			    htole32(1);
822			siop_cmd->siop_table->t_msgout.addr =
823			    htole32(siop_cmd->dsa);
824			siop_cmd->siop_table->msg_out[0] =
825			    MSG_MESSAGE_REJECT;
826			siop_table_sync(siop_cmd,
827			    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
828			CALL_SCRIPT(Ent_send_msgout);
829			return 1;
830		case A_int_resel: /* reselected */
831		case A_int_reseltag: /* reselected  with tag */
832			INCSTAT(siop_stat_intr_reselect);
833			if ((siop_cmd->siop_table->msg_in[0] & 0x80) == 0) {
834				printf("%s: reselect without identify (%d)\n",
835				    sc->sc_dev.dv_xname,
836				    siop_cmd->siop_table->msg_in[0]);
837				goto reset;
838			}
839			target = bus_space_read_1(sc->sc_rt,
840			    sc->sc_rh, SIOP_SCRATCHA);
841			if ((target & 0x80) == 0) {
842				printf("reselect without id (%d)\n", target);
843				goto reset;
844			}
845			target &= 0x0f;
846			lun = siop_cmd->siop_table->msg_in[0] & 0x07;
847#ifdef DEBUG_DR
848			printf("reselected by target %d lun %d\n",
849			    target, lun);
850#endif
851			siop_cmd =
852			    sc->targets[target]->active_list[lun].tqh_first;
853			if (siop_cmd == NULL) {
854				printf("%s: reselected without cmd\n",
855				    sc->sc_dev.dv_xname);
856				goto reset;
857			}
858			bus_space_write_4(sc->sc_rt, sc->sc_rh, SIOP_DSA,
859			    siop_cmd->dsa);
860			bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL3,
861			    (sc->targets[target]->id >> 24) & 0xff);
862			bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCXFER,
863			    (sc->targets[target]->id >> 8) & 0xff);
864			/* no table to flush */
865			CALL_SCRIPT(Ent_selected);
866			return 1;
867		case A_int_disc:
868			INCSTAT(siop_stat_intr_sdp);
869			offset = bus_space_read_1(sc->sc_rt, sc->sc_rh,
870			    SIOP_SCRATCHA + 1);
871#ifdef DEBUG_DR
872			printf("disconnect offset %d\n", offset);
873#endif
874			if (offset > SIOP_NSG) {
875				printf("%s: bad offset for disconnect (%d)\n",
876				    sc->sc_dev.dv_xname, offset);
877				goto reset;
878			}
879			/*
880			 * offset == SIOP_NSG may be a valid condition if
881			 * we get a sdp when the xfer is done.
882			 * Don't call memmove in this case.
883			 */
884			if (offset < SIOP_NSG) {
885				memmove(&siop_cmd->siop_table->data[0],
886				    &siop_cmd->siop_table->data[offset],
887				    (SIOP_NSG - offset) * sizeof(scr_table_t));
888				siop_table_sync(siop_cmd,
889				    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
890			}
891			bus_space_write_4(sc->sc_rt, sc->sc_rh, SIOP_DSP,
892			    sc->sc_sheddma->dm_segs[0].ds_addr);
893			return 1;
894		case A_int_resfail:
895			printf("reselect failed\n");
896			bus_space_write_4(sc->sc_rt, sc->sc_rh, SIOP_DSP,
897			    sc->sc_sheddma->dm_segs[0].ds_addr);
898			return  1;
899		case A_int_done:
900			if (xs == NULL) {
901				printf("%s: done without command, DSA=0x%lx\n",
902				    sc->sc_dev.dv_xname, (u_long)siop_cmd->dsa);
903				siop_cmd->status = CMDST_FREE;
904				bus_space_write_4(sc->sc_rt, sc->sc_rh,
905				    SIOP_DSP,
906				    sc->sc_sheddma->dm_segs[0].ds_addr);
907				siop_start(sc);
908				return 1;
909			}
910			if (siop_target->status == TARST_PROBING)
911				siop_target->status = TARST_ASYNC;
912#ifdef DEBUG_INTR
913			printf("done, DSA=0x%lx target id 0x%x last msg "
914			    "in=0x%x status=0x%x\n", (u_long)siop_cmd->dsa,
915			    le32toh(siop_cmd->siop_table->id),
916			    siop_cmd->siop_table->msg_in[0],
917			    le32toh(siop_cmd->siop_table->status));
918#endif
919			INCSTAT(siop_stat_intr_done);
920			if (siop_cmd->status == CMDST_SENSE_ACTIVE)
921				siop_cmd->status = CMDST_SENSE_DONE;
922			else
923				siop_cmd->status = CMDST_DONE;
924			switch(le32toh(siop_cmd->siop_table->status)) {
925			case SCSI_OK:
926				xs->error = (siop_cmd->status == CMDST_DONE) ?
927				    XS_NOERROR : XS_SENSE;
928				break;
929			case SCSI_BUSY:
930				xs->error = XS_BUSY;
931				break;
932			case SCSI_CHECK:
933check_sense:
934				if (siop_cmd->status == CMDST_SENSE_DONE) {
935					/* request sense on a request sense ? */
936					printf("request sense failed\n");
937					xs->error = XS_DRIVER_STUFFUP;
938				} else {
939					siop_cmd->status = CMDST_SENSE;
940				}
941				break;
942			case 0xff:
943				/*
944				 * the status byte was not updated, cmd was
945				 * aborted
946				 */
947				xs->error = XS_SELTIMEOUT;
948				break;
949			default:
950				xs->error = XS_DRIVER_STUFFUP;
951			}
952			goto end;
953		default:
954			printf("unknown irqcode %x\n", irqcode);
955			xs->error = XS_SELTIMEOUT;
956			goto end;
957		}
958		return 1;
959	}
960	/* We just should't get there */
961	panic("siop_intr: I shouldn't be there !");
962	return 1;
963end:
964	bus_space_write_4(sc->sc_rt, sc->sc_rh, SIOP_DSP,
965	    sc->sc_sheddma->dm_segs[0].ds_addr);
966	lun = siop_cmd->xs->sc_link->scsipi_scsi.lun;
967	siop_scsicmd_end(siop_cmd);
968	if (siop_cmd->status == CMDST_FREE) {
969		TAILQ_REMOVE(&siop_target->active_list[lun],
970		    siop_cmd, next);
971		TAILQ_INSERT_TAIL(&sc->free_list, siop_cmd, next);
972	}
973	siop_start(sc);
974	return 1;
975}
976
977void
978siop_scsicmd_end(siop_cmd)
979	struct siop_cmd *siop_cmd;
980{
981	struct scsipi_xfer *xs = siop_cmd->xs;
982	struct siop_softc *sc = siop_cmd->siop_target->siop_sc;
983
984	if (siop_cmd->status != CMDST_SENSE_DONE &&
985	    xs->xs_control & (XS_CTL_DATA_IN | XS_CTL_DATA_OUT)) {
986		bus_dmamap_sync(sc->sc_dmat, siop_cmd->dmamap_data, 0,
987		    siop_cmd->dmamap_data->dm_mapsize,
988		    (xs->xs_control & XS_CTL_DATA_IN) ?
989		    BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
990		bus_dmamap_unload(sc->sc_dmat, siop_cmd->dmamap_data);
991	}
992	bus_dmamap_unload(sc->sc_dmat, siop_cmd->dmamap_cmd);
993	if (siop_cmd->status == CMDST_SENSE) {
994		/* issue a request sense for this target */
995		int error, i;
996		siop_cmd->rs_cmd.opcode = REQUEST_SENSE;
997		siop_cmd->rs_cmd.byte2 = xs->sc_link->scsipi_scsi.lun << 5;
998		siop_cmd->rs_cmd.unused[0] = siop_cmd->rs_cmd.unused[1] = 0;
999		siop_cmd->rs_cmd.length = sizeof(struct scsipi_sense_data);
1000		siop_cmd->rs_cmd.control = 0;
1001		siop_cmd->siop_table->status = htole32(0xff); /*invalid status*/
1002		siop_cmd->siop_table->t_msgout.count= htole32(1);
1003		siop_cmd->siop_table->t_msgout.addr = htole32(siop_cmd->dsa);
1004		siop_cmd->siop_table->msg_out[0] =
1005		    MSG_IDENTIFY(xs->sc_link->scsipi_scsi.lun, 1);
1006		error = bus_dmamap_load(sc->sc_dmat, siop_cmd->dmamap_cmd,
1007		    &siop_cmd->rs_cmd, sizeof(struct scsipi_sense),
1008		    NULL, BUS_DMA_NOWAIT);
1009		if (error) {
1010			printf("%s: unable to load cmd DMA map: %d",
1011			    sc->sc_dev.dv_xname, error);
1012			xs->error = XS_DRIVER_STUFFUP;
1013			goto out;
1014		}
1015		siop_cmd->siop_table->cmd.count =
1016		    htole32(siop_cmd->dmamap_cmd->dm_segs[0].ds_len);
1017		siop_cmd->siop_table->cmd.addr =
1018		    htole32(siop_cmd->dmamap_cmd->dm_segs[0].ds_addr);
1019		error = bus_dmamap_load(sc->sc_dmat, siop_cmd->dmamap_data,
1020		    &xs->sense.scsi_sense, sizeof(struct  scsipi_sense_data),
1021		    NULL, BUS_DMA_NOWAIT);
1022		if (error) {
1023			printf("%s: unable to load sense DMA map: %d",
1024			    sc->sc_dev.dv_xname, error);
1025			xs->error = XS_DRIVER_STUFFUP;
1026			bus_dmamap_unload(sc->sc_dmat, siop_cmd->dmamap_cmd);
1027			goto out;
1028		}
1029		for (i = 0; i < siop_cmd->dmamap_data->dm_nsegs; i++) {
1030			siop_cmd->siop_table->data[i].count =
1031			    htole32(siop_cmd->dmamap_data->dm_segs[i].ds_len);
1032			siop_cmd->siop_table->data[i].addr =
1033			    htole32(siop_cmd->dmamap_data->dm_segs[i].ds_addr);
1034		}
1035		bus_dmamap_sync(sc->sc_dmat, siop_cmd->dmamap_data, 0,
1036		    siop_cmd->dmamap_data->dm_mapsize, BUS_DMASYNC_PREREAD);
1037		bus_dmamap_sync(sc->sc_dmat, siop_cmd->dmamap_cmd, 0,
1038		    siop_cmd->dmamap_cmd->dm_mapsize, BUS_DMASYNC_PREWRITE);
1039		siop_table_sync(siop_cmd, BUS_DMASYNC_PREWRITE);
1040		return;
1041	} else if (siop_cmd->status == CMDST_SENSE_DONE) {
1042		bus_dmamap_sync(sc->sc_dmat, siop_cmd->dmamap_data, 0,
1043		    siop_cmd->dmamap_data->dm_mapsize, BUS_DMASYNC_POSTREAD);
1044		bus_dmamap_unload(sc->sc_dmat, siop_cmd->dmamap_data);
1045	}
1046out:
1047	callout_stop(&siop_cmd->xs->xs_callout);
1048	siop_cmd->status = CMDST_FREE;
1049	xs->xs_status |= XS_STS_DONE;
1050	xs->resid = 0;
1051	if ((xs->xs_control & XS_CTL_POLL) == 0)
1052		scsipi_done (xs);
1053}
1054
1055/*
1056 * handle a bus reset: reset chip, unqueue all active commands and report
1057 * loosage to upper layer.
1058 * As the upper layer may requeue immediatly we have to first store
1059 * all active commands in a temporary queue.
1060 */
1061void
1062siop_handle_reset(sc)
1063	struct siop_softc *sc;
1064{
1065	struct cmd_list reset_list;
1066	struct siop_cmd *siop_cmd, *next_siop_cmd;
1067	int target, lun;
1068	/*
1069	 * scsi bus reset. reset the chip and restart
1070	 * the queue. Need to clean up all active commands
1071	 */
1072	printf("%s: scsi bus reset\n", sc->sc_dev.dv_xname);
1073	/* stop, reset and restart the chip */
1074	siop_reset(sc);
1075	TAILQ_INIT(&reset_list);
1076	/* find all active commands */
1077	for (target = 0; target < sc->sc_link.scsipi_scsi.max_target;
1078	    target++) {
1079		if (sc->targets[target] == NULL)
1080			continue;
1081		for (lun = 0; lun < 8; lun++) {
1082			for (siop_cmd =
1083			    TAILQ_FIRST(&sc->targets[target]->active_list[lun]);
1084			    siop_cmd != NULL; siop_cmd = next_siop_cmd) {
1085				next_siop_cmd = TAILQ_NEXT(siop_cmd, next);
1086				if (siop_cmd->status < CMDST_ACTIVE)
1087					continue;
1088				printf("cmd %p (target %d) in reset list\n",
1089				    siop_cmd, target);
1090				TAILQ_REMOVE(
1091				    &sc->targets[target]->active_list[lun],
1092				    siop_cmd, next);
1093				TAILQ_INSERT_TAIL(&reset_list, siop_cmd, next);
1094			}
1095		}
1096		sc->targets[target]->status = TARST_ASYNC;
1097		sc->targets[target]->flags = ~(TARF_SYNC | TARF_WIDE);
1098	}
1099	for (siop_cmd = TAILQ_FIRST(&reset_list); siop_cmd != NULL;
1100	    siop_cmd = next_siop_cmd) {
1101		next_siop_cmd = TAILQ_NEXT(siop_cmd, next);
1102		siop_cmd->xs->error = (siop_cmd->flags & CMDFL_TIMEOUT) ?
1103		    XS_TIMEOUT : XS_RESET;
1104		printf("cmd %p about to be processed\n", siop_cmd);
1105		if (siop_cmd->status == CMDST_SENSE ||
1106		    siop_cmd->status == CMDST_SENSE_ACTIVE)
1107			siop_cmd->status = CMDST_SENSE_DONE;
1108		else
1109			siop_cmd->status = CMDST_DONE;
1110		TAILQ_REMOVE(&reset_list, siop_cmd, next);
1111		siop_scsicmd_end(siop_cmd);
1112		TAILQ_INSERT_TAIL(&sc->free_list, siop_cmd, next);
1113	}
1114}
1115
1116int
1117siop_scsicmd(xs)
1118	struct scsipi_xfer *xs;
1119{
1120	struct siop_softc *sc = (struct siop_softc *)xs->sc_link->adapter_softc;
1121	struct siop_cmd *siop_cmd;
1122	int s, error, i;
1123	int target = xs->sc_link->scsipi_scsi.target;
1124	int lun = xs->sc_link->scsipi_scsi.lun;
1125
1126	s = splbio();
1127#ifdef DEBUG_SHED
1128	printf("starting cmd for %d:%d\n", target, lun);
1129#endif
1130	siop_cmd = sc->free_list.tqh_first;
1131	if (siop_cmd) {
1132		TAILQ_REMOVE(&sc->free_list, siop_cmd, next);
1133	} else {
1134		if (siop_morecbd(sc) == 0) {
1135			siop_cmd = sc->free_list.tqh_first;
1136#ifdef DIAGNOSTIC
1137			if (siop_cmd == NULL)
1138				panic("siop_morecbd succeed and does nothing");
1139#endif
1140			TAILQ_REMOVE(&sc->free_list, siop_cmd, next);
1141		}
1142	}
1143	splx(s);
1144	if (siop_cmd == NULL) {
1145		xs->error = XS_DRIVER_STUFFUP;
1146		return(TRY_AGAIN_LATER);
1147	}
1148#ifdef DIAGNOSTIC
1149	if (siop_cmd->status != CMDST_FREE)
1150		panic("siop_scsicmd: new cmd not free");
1151#endif
1152	if (sc->targets[target] == NULL) {
1153		sc->targets[target] =
1154		    malloc(sizeof(struct siop_target), M_DEVBUF, M_NOWAIT);
1155		if (sc->targets[target] == NULL) {
1156			printf("%s: can't malloc memory for target %d\n",
1157			    sc->sc_dev.dv_xname, target);
1158			xs->error = XS_DRIVER_STUFFUP;
1159			return(TRY_AGAIN_LATER);
1160		}
1161		sc->targets[target]->siop_sc = sc;
1162		sc->targets[target]->status = TARST_PROBING;
1163		sc->targets[target]->flags = 0;
1164		sc->targets[target]->id = sc->clock_div << 24; /* scntl3 */
1165		sc->targets[target]->id |=  target << 16; /* id */
1166		/* sc->targets[target]->id |= 0x0 << 8; scxfer is 0 */
1167		for (i = 0; i < 8; i++)
1168			TAILQ_INIT(&sc->targets[target]->active_list[i]);
1169	}
1170	siop_cmd->siop_target = sc->targets[target];
1171	siop_cmd->xs = xs;
1172	siop_cmd->siop_table->id = htole32(sc->targets[target]->id);
1173	siop_cmd->siop_table->t_msgout.count= htole32(1);
1174	siop_cmd->siop_table->t_msgout.addr = htole32(siop_cmd->dsa);
1175	memset(siop_cmd->siop_table->msg_out, 0, 8);
1176	siop_cmd->siop_table->msg_out[0] = MSG_IDENTIFY(lun, 1);
1177#if 0
1178	siop_cmd->siop_table->msg_out[1] = MSG_SIMPLE_Q_TAG;
1179	siop_cmd->siop_table->msg_out[2] = 0;
1180#endif
1181	if (sc->targets[target]->status == TARST_ASYNC) {
1182		if (sc->features & SF_BUS_WIDE) {
1183			sc->targets[target]->status = TARST_WIDE_NEG;
1184			siop_cmd->siop_table->msg_out[1] = MSG_EXTENDED;
1185			siop_cmd->siop_table->msg_out[2] = MSG_EXT_WDTR_LEN;
1186			siop_cmd->siop_table->msg_out[3] = MSG_EXT_WDTR;
1187			siop_cmd->siop_table->msg_out[4] =
1188			    MSG_EXT_WDTR_BUS_16_BIT;
1189			siop_cmd->siop_table->t_msgout.count=
1190			    htole32(MSG_EXT_WDTR_LEN + 2 + 1);
1191		} else {
1192			sc->targets[target]->status = TARST_SYNC_NEG;
1193			siop_cmd->siop_table->msg_out[1] = MSG_EXTENDED;
1194			siop_cmd->siop_table->msg_out[2] = MSG_EXT_SDTR_LEN;
1195			siop_cmd->siop_table->msg_out[3] = MSG_EXT_SDTR;
1196			siop_cmd->siop_table->msg_out[4] = sc->minsync;
1197			siop_cmd->siop_table->msg_out[5] = sc->maxoff;
1198			siop_cmd->siop_table->t_msgout.count=
1199			    htole32(MSG_EXT_SDTR_LEN + 2 +1);
1200		}
1201	}
1202	siop_cmd->siop_table->status = htole32(0xff); /* set invalid status */
1203
1204	/* load the DMA maps */
1205	error = bus_dmamap_load(sc->sc_dmat, siop_cmd->dmamap_cmd,
1206	    xs->cmd, xs->cmdlen, NULL, BUS_DMA_NOWAIT);
1207	if (error) {
1208		printf("%s: unable to load cmd DMA map: %d",
1209		    sc->sc_dev.dv_xname, error);
1210		xs->error = XS_DRIVER_STUFFUP;
1211		return(TRY_AGAIN_LATER);
1212	}
1213	siop_cmd->siop_table->cmd.count =
1214	    htole32(siop_cmd->dmamap_cmd->dm_segs[0].ds_len);
1215	siop_cmd->siop_table->cmd.addr =
1216	    htole32(siop_cmd->dmamap_cmd->dm_segs[0].ds_addr);
1217	if (xs->xs_control & (XS_CTL_DATA_IN | XS_CTL_DATA_OUT)) {
1218		error = bus_dmamap_load(sc->sc_dmat, siop_cmd->dmamap_data,
1219		    xs->data, xs->datalen, NULL, BUS_DMA_NOWAIT);
1220		if (error) {
1221			printf("%s: unable to load cmd DMA map: %d",
1222			    sc->sc_dev.dv_xname, error);
1223			xs->error = XS_DRIVER_STUFFUP;
1224			return(TRY_AGAIN_LATER);
1225			bus_dmamap_unload(sc->sc_dmat, siop_cmd->dmamap_cmd);
1226		}
1227		for (i = 0; i < siop_cmd->dmamap_data->dm_nsegs; i++) {
1228			siop_cmd->siop_table->data[i].count =
1229			    htole32(siop_cmd->dmamap_data->dm_segs[i].ds_len);
1230			siop_cmd->siop_table->data[i].addr =
1231			    htole32(siop_cmd->dmamap_data->dm_segs[i].ds_addr);
1232		}
1233		bus_dmamap_sync(sc->sc_dmat, siop_cmd->dmamap_data, 0,
1234		    siop_cmd->dmamap_data->dm_mapsize,
1235		    (xs->xs_control & XS_CTL_DATA_IN) ?
1236		    BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE);
1237	}
1238	bus_dmamap_sync(sc->sc_dmat, siop_cmd->dmamap_cmd, 0,
1239	    siop_cmd->dmamap_cmd->dm_mapsize, BUS_DMASYNC_PREWRITE);
1240	siop_table_sync(siop_cmd, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1241
1242	siop_cmd->status = CMDST_READY;
1243	s = splbio();
1244	TAILQ_INSERT_TAIL(&sc->targets[target]->active_list[lun],
1245	    siop_cmd, next);
1246	siop_start(sc);
1247	if (xs->xs_control & XS_CTL_POLL) {
1248		/* poll for command completion */
1249		while ((xs->xs_status & XS_STS_DONE) == 0)
1250			siop_intr(sc);
1251		splx(s);
1252		return (COMPLETE);
1253	}
1254	splx(s);
1255	return (SUCCESSFULLY_QUEUED);
1256}
1257
1258void
1259siop_start(sc)
1260	struct siop_softc *sc;
1261{
1262	struct siop_cmd *siop_cmd;
1263	u_int32_t *scr;
1264	u_int32_t dsa;
1265	int timeout;
1266	int target, lun, slot;
1267	int newcmd = 0;
1268
1269	/*
1270	 * first make sure to read valid data
1271	 */
1272	siop_shed_sync(sc, BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
1273
1274	/*
1275	 * The queue management here is a bit tricky: the script always looks
1276	 * at the slot from first to last, so if we always use the first
1277	 * free slot commands can stay at the tail of the queue ~forever.
1278	 * The algorithm used here is to restart from the head when we know
1279	 * that the queue is empty, and only add commands after the last one.
1280	 * When we're at the end of the queue wait for the script to clear it.
1281	 * The best thing to do here would be to implement a circular queue,
1282	 * but using only 53c720 features this can be "interesting".
1283	 * A mid-way solution could be to implement 2 queues and swap orders.
1284	 */
1285	slot = sc->sc_currshedslot;
1286	scr = &sc->sc_shed[(Ent_nextslot / 4) * slot];
1287	/*
1288	 * if relative addr of first jump is not 0 the slot is free. As this is
1289	 * the last used slot, all previous slots are free, we can restart
1290	 * from 0.
1291	 */
1292	if (scr[Ent_slot / 4 + 1] != 0) {
1293		slot = sc->sc_currshedslot = 0;
1294	} else {
1295		slot++;
1296	}
1297
1298	for (target = 0; target <= sc->sc_link.scsipi_scsi.max_target;
1299	    target++) {
1300		if (sc->targets[target] == NULL)
1301			continue;
1302		for (lun = 0; lun < 8; lun++) {
1303			siop_cmd =
1304			    sc->targets[target]->active_list[lun].tqh_first;
1305			if (siop_cmd == NULL)
1306				continue;
1307			if (siop_cmd->status != CMDST_READY &&
1308			    siop_cmd->status != CMDST_SENSE)
1309				continue;
1310			/* find a free scheduler slot and load it */
1311			for (; slot < sc->sc_nshedslots; slot++) {
1312				scr = &sc->sc_shed[(Ent_nextslot / 4) * slot];
1313				/*
1314				 * if relative addr of first jump is 0 the
1315				 * slot isn't free
1316				 */
1317				if (scr[Ent_slot / 4 + 1] == 0)
1318					continue;
1319#ifdef DEBUG_SHED
1320				printf("using slot %d for DSA 0x%lx\n", slot,
1321				    (u_long)siop_cmd->dsa);
1322#endif
1323				/* note that we started a new command */
1324				newcmd = 1;
1325				/* mark command as active */
1326				if (siop_cmd->status == CMDST_READY)
1327					siop_cmd->status = CMDST_ACTIVE;
1328				else if (siop_cmd->status == CMDST_SENSE)
1329					siop_cmd->status = CMDST_SENSE_ACTIVE;
1330				else
1331					panic("siop_start: bad status");
1332				/* patch script with DSA addr */
1333				dsa = siop_cmd->dsa;
1334				/*
1335				 * 0x78000000 is a 'move data8 to reg'. data8
1336				 * is the second octet, reg offset is the third.
1337				 */
1338				scr[Ent_idsa0 / 4] =
1339				    htole32(0x78100000 |
1340				    ((dsa & 0x000000ff) <<  8));
1341				scr[Ent_idsa1 / 4] =
1342				    htole32(0x78110000 |
1343				    ( dsa & 0x0000ff00       ));
1344				scr[Ent_idsa2 / 4] =
1345				    htole32(0x78120000 |
1346				    ((dsa & 0x00ff0000) >>  8));
1347				scr[Ent_idsa3 / 4] =
1348				    htole32(0x78130000 |
1349				    ((dsa & 0xff000000) >> 16));
1350				/* handle timeout */
1351				if (siop_cmd->status == CMDST_ACTIVE) {
1352					if ((siop_cmd->xs->xs_control &
1353					    XS_CTL_POLL) == 0) {
1354						/* start exire timer */
1355						timeout =
1356						    siop_cmd->xs->timeout *
1357						    hz / 1000;
1358						if (timeout == 0)
1359							timeout = 1;
1360						callout_reset(
1361						    &siop_cmd->xs->xs_callout,
1362						    timeout, siop_timeout,
1363						    siop_cmd);
1364					}
1365				}
1366				/*
1367				 * Change jump offset so that this slot will be
1368				 * handled
1369				 */
1370				scr[Ent_slot / 4 + 1] = 0;
1371				break;
1372			}
1373			/* no more free slot, no need to continue */
1374			if (slot == sc->sc_nshedslots) {
1375				goto end;
1376			}
1377			sc->sc_currshedslot = slot;
1378		}
1379	}
1380end:
1381	/* if nothing changed no need to flush cache and wakeup script */
1382	if (newcmd == 0)
1383		return;
1384	/* make sure SCRIPT processor will read valid data */
1385	siop_shed_sync(sc, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1386	/* Signal script it has some work to do */
1387	bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_ISTAT, ISTAT_SIGP);
1388	/* and wait for IRQ */
1389	return;
1390}
1391
1392void
1393siop_timeout(v)
1394	void *v;
1395{
1396	struct siop_cmd *siop_cmd = v;
1397	struct siop_softc *sc = siop_cmd->siop_target->siop_sc;
1398	int s;
1399	u_int8_t scntl1;
1400
1401	scsi_print_addr(siop_cmd->xs->sc_link);
1402	printf("command timeout\n");
1403
1404	s = splbio();
1405	/* reset the scsi bus */
1406	scntl1 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1);
1407	bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1,
1408	    scntl1 | SCNTL1_RST);
1409	/* minimum 25 us, more time won't hurt */
1410	delay(100);
1411	bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1, scntl1);
1412
1413	/* deactivate callout */
1414	callout_stop(&siop_cmd->xs->xs_callout);
1415	/* mark command has being timed out; siop_intr will handle it */
1416	/*
1417	 * mark command has being timed out and just return;
1418	 * the bus reset will generate an interrupt,
1419	 * it will be handled in siop_intr()
1420	 */
1421	siop_cmd->flags |= CMDFL_TIMEOUT;
1422	splx(s);
1423	return;
1424
1425}
1426
1427void
1428siop_dump_script(sc)
1429	struct siop_softc *sc;
1430{
1431	int i;
1432	siop_shed_sync(sc, BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
1433	for (i = 0; i < NBPG / 4; i += 2) {
1434		printf("0x%04x: 0x%08x 0x%08x", i * 4,
1435		    le32toh(sc->sc_script[i]), le32toh(sc->sc_script[i+1]));
1436		if ((le32toh(sc->sc_script[i]) & 0xe0000000) == 0xc0000000) {
1437			i++;
1438			printf(" 0x%08x", le32toh(sc->sc_script[i+1]));
1439		}
1440		printf("\n");
1441	}
1442}
1443
1444int
1445siop_morecbd(sc)
1446	struct siop_softc *sc;
1447{
1448	int error, i;
1449	bus_dma_segment_t seg;
1450	int rseg;
1451	struct siop_cbd *newcbd;
1452
1453	/* allocate a new list head */
1454	newcbd = malloc(sizeof(struct siop_cbd), M_DEVBUF, M_NOWAIT);
1455	if (newcbd == NULL) {
1456		printf("%s: can't allocate memory for command descriptors "
1457		    "head\n", sc->sc_dev.dv_xname);
1458		return ENOMEM;
1459	}
1460
1461	/* allocate cmd list */
1462	newcbd->cmds =
1463	    malloc(sizeof(struct siop_cmd) * SIOP_NCMDPB, M_DEVBUF, M_NOWAIT);
1464	if (newcbd->cmds == NULL) {
1465		printf("%s: can't allocate memory for command descriptors\n",
1466		    sc->sc_dev.dv_xname);
1467		error = ENOMEM;
1468		goto bad3;
1469	}
1470	error = bus_dmamem_alloc(sc->sc_dmat, NBPG, NBPG, 0, &seg, 1, &rseg,
1471	    BUS_DMA_NOWAIT);
1472	if (error) {
1473		printf("%s: unable to allocate cbd DMA memory, error = %d\n",
1474		    sc->sc_dev.dv_xname, error);
1475		goto bad2;
1476	}
1477	error = bus_dmamem_map(sc->sc_dmat, &seg, rseg, NBPG,
1478	    (caddr_t *)&newcbd->xfers, BUS_DMA_NOWAIT|BUS_DMA_COHERENT);
1479	if (error) {
1480		printf("%s: unable to map cbd DMA memory, error = %d\n",
1481		    sc->sc_dev.dv_xname, error);
1482		goto bad2;
1483	}
1484	error = bus_dmamap_create(sc->sc_dmat, NBPG, 1, NBPG, 0,
1485	    BUS_DMA_NOWAIT, &newcbd->xferdma);
1486	if (error) {
1487		printf("%s: unable to create cbd DMA map, error = %d\n",
1488		    sc->sc_dev.dv_xname, error);
1489		goto bad1;
1490	}
1491	error = bus_dmamap_load(sc->sc_dmat, newcbd->xferdma, newcbd->xfers,
1492	    NBPG, NULL, BUS_DMA_NOWAIT);
1493	if (error) {
1494		printf("%s: unable to load cbd DMA map, error = %d\n",
1495		    sc->sc_dev.dv_xname, error);
1496		goto bad0;
1497	}
1498
1499	for (i = 0; i < SIOP_NCMDPB; i++) {
1500		error = bus_dmamap_create(sc->sc_dmat, MAXPHYS, SIOP_NSG,
1501		    MAXPHYS, 0, BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW,
1502		    &newcbd->cmds[i].dmamap_data);
1503		if (error) {
1504			printf("%s: unable to create data DMA map for cbd: "
1505			    "error %d\n",
1506			    sc->sc_dev.dv_xname, error);
1507			goto bad0;
1508		}
1509		error = bus_dmamap_create(sc->sc_dmat,
1510		    sizeof(struct scsipi_generic), 1,
1511		    sizeof(struct scsipi_generic), 0,
1512		    BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW,
1513		    &newcbd->cmds[i].dmamap_cmd);
1514		if (error) {
1515			printf("%s: unable to create cmd DMA map for cbd %d\n",
1516			    sc->sc_dev.dv_xname, error);
1517			goto bad0;
1518		}
1519		newcbd->cmds[i].siop_cbdp = newcbd;
1520		newcbd->cmds[i].siop_table = &newcbd->xfers[i];
1521		memset(newcbd->cmds[i].siop_table, 0, sizeof(struct siop_xfer));
1522		newcbd->cmds[i].dsa = newcbd->xferdma->dm_segs[0].ds_addr +
1523		    i * sizeof(struct siop_xfer);
1524		newcbd->cmds[i].status = CMDST_FREE;
1525		newcbd->cmds[i].siop_table->t_msgout.count= htole32(1);
1526		newcbd->cmds[i].siop_table->t_msgout.addr =
1527		    htole32(newcbd->cmds[i].dsa);
1528		newcbd->cmds[i].siop_table->t_msgin.count= htole32(1);
1529		newcbd->cmds[i].siop_table->t_msgin.addr =
1530		    htole32(newcbd->cmds[i].dsa + 8);
1531		newcbd->cmds[i].siop_table->t_extmsgin.count= htole32(2);
1532		newcbd->cmds[i].siop_table->t_extmsgin.addr = htole32(
1533		    le32toh(newcbd->cmds[i].siop_table->t_msgin.addr) + 1);
1534		newcbd->cmds[i].siop_table->t_msgtag.count= htole32(2);
1535		newcbd->cmds[i].siop_table->t_msgtag.addr = htole32(
1536		    le32toh(newcbd->cmds[i].siop_table->t_msgin.addr) + 1);
1537		newcbd->cmds[i].siop_table->t_status.count= htole32(1);
1538		newcbd->cmds[i].siop_table->t_status.addr = htole32(
1539		    le32toh(newcbd->cmds[i].siop_table->t_msgin.addr) + 8);
1540		TAILQ_INSERT_TAIL(&sc->free_list, &newcbd->cmds[i], next);
1541#ifdef DEBUG
1542		printf("tables[%d]: out=0x%x in=0x%x status=0x%x\n", i,
1543		    le32toh(newcbd->cmds[i].siop_table->t_msgin.addr),
1544		    le32toh(newcbd->cmds[i].siop_table->t_msgout.addr),
1545		    le32toh(newcbd->cmds[i].siop_table->t_status.addr));
1546#endif
1547	}
1548	TAILQ_INSERT_TAIL(&sc->cmds, newcbd, next);
1549	return 0;
1550bad0:
1551	bus_dmamap_destroy(sc->sc_dmat, newcbd->xferdma);
1552bad1:
1553	bus_dmamem_free(sc->sc_dmat, &seg, rseg);
1554bad2:
1555	free(newcbd->cmds, M_DEVBUF);
1556bad3:
1557	free(newcbd, M_DEVBUF);
1558	return error;
1559}
1560
1561#ifdef SIOP_STATS
1562void
1563siop_printstats()
1564{
1565	printf("siop_stat_intr %d\n", siop_stat_intr);
1566	printf("siop_stat_intr_shortxfer %d\n", siop_stat_intr_shortxfer);
1567	printf("siop_stat_intr_xferdisc %d\n", siop_stat_intr_xferdisc);
1568	printf("siop_stat_intr_sdp %d\n", siop_stat_intr_sdp);
1569	printf("siop_stat_intr_reselect %d\n", siop_stat_intr_reselect);
1570	printf("siop_stat_intr_done %d\n", siop_stat_intr_done);
1571}
1572#endif
1573