siop.c revision 1.35
1/*	$NetBSD: siop.c,v 1.35 2000/10/23 14:56:16 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 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 <dev/microcode/siop/siop.out>
46
47#include <dev/scsipi/scsi_all.h>
48#include <dev/scsipi/scsi_message.h>
49#include <dev/scsipi/scsipi_all.h>
50
51#include <dev/scsipi/scsiconf.h>
52
53#include <dev/ic/siopreg.h>
54#include <dev/ic/siopvar.h>
55#include <dev/ic/siopvar_common.h>
56
57#ifndef DEBUG
58#undef DEBUG
59#endif
60#undef SIOP_DEBUG
61#undef SIOP_DEBUG_DR
62#undef SIOP_DEBUG_INTR
63#undef SIOP_DEBUG_SCHED
64#undef DUMP_SCRIPT
65
66#define SIOP_STATS
67
68#ifndef SIOP_DEFAULT_TARGET
69#define SIOP_DEFAULT_TARGET 7
70#endif
71
72/* number of cmd descriptors per block */
73#define SIOP_NCMDPB (NBPG / sizeof(struct siop_xfer))
74
75/* Number of scheduler slot (needs to match script) */
76#define SIOP_NSLOTS 40
77
78void	siop_reset __P((struct siop_softc *));
79void	siop_handle_reset __P((struct siop_softc *));
80int	siop_handle_qtag_reject __P((struct siop_cmd *));
81void	siop_scsicmd_end __P((struct siop_cmd *));
82void	siop_start __P((struct siop_softc *));
83void 	siop_timeout __P((void *));
84int	siop_scsicmd __P((struct scsipi_xfer *));
85void	siop_dump_script __P((struct siop_softc *));
86int	siop_morecbd __P((struct siop_softc *));
87struct siop_lunsw *siop_get_lunsw __P((struct siop_softc *));
88void	siop_add_reselsw __P((struct siop_softc *, int));
89void	siop_update_scntl3 __P((struct siop_softc *, struct siop_target *));
90
91struct scsipi_adapter siop_adapter = {
92	0,
93	siop_scsicmd,
94	siop_minphys,
95	siop_ioctl,
96	NULL,
97	NULL,
98};
99
100struct scsipi_device siop_dev = {
101	NULL,
102	NULL,
103	NULL,
104	NULL,
105};
106
107#ifdef SIOP_STATS
108static int siop_stat_intr = 0;
109static int siop_stat_intr_shortxfer = 0;
110static int siop_stat_intr_sdp = 0;
111static int siop_stat_intr_done = 0;
112static int siop_stat_intr_xferdisc = 0;
113static int siop_stat_intr_lunresel = 0;
114void siop_printstats __P((void));
115#define INCSTAT(x) x++
116#else
117#define INCSTAT(x)
118#endif
119
120static __inline__ void siop_script_sync __P((struct siop_softc *, int));
121static __inline__ void
122siop_script_sync(sc, ops)
123	struct siop_softc *sc;
124	int ops;
125{
126	if ((sc->features & SF_CHIP_RAM) == 0)
127		bus_dmamap_sync(sc->sc_dmat, sc->sc_scriptdma, 0, NBPG, ops);
128}
129
130static __inline__ u_int32_t siop_script_read __P((struct siop_softc *, u_int));
131static __inline__ u_int32_t
132siop_script_read(sc, offset)
133	struct siop_softc *sc;
134	u_int offset;
135{
136	if (sc->features & SF_CHIP_RAM) {
137		return bus_space_read_4(sc->sc_ramt, sc->sc_ramh, offset * 4);
138	} else {
139		return le32toh(sc->sc_script[offset]);
140	}
141}
142
143static __inline__ void siop_script_write __P((struct siop_softc *, u_int,
144	u_int32_t));
145static __inline__ void
146siop_script_write(sc, offset, val)
147	struct siop_softc *sc;
148	u_int offset;
149	u_int32_t val;
150{
151	if (sc->features & SF_CHIP_RAM) {
152		bus_space_write_4(sc->sc_ramt, sc->sc_ramh, offset * 4, val);
153	} else {
154		sc->sc_script[offset] = htole32(val);
155	}
156}
157
158void
159siop_attach(sc)
160	struct siop_softc *sc;
161{
162	int error, i;
163	bus_dma_segment_t seg;
164	int rseg;
165
166	/*
167	 * Allocate DMA-safe memory for the script and map it.
168	 */
169	if ((sc->features & SF_CHIP_RAM) == 0) {
170		error = bus_dmamem_alloc(sc->sc_dmat, NBPG,
171		    NBPG, 0, &seg, 1, &rseg, BUS_DMA_NOWAIT);
172		if (error) {
173			printf("%s: unable to allocate script DMA memory, "
174			    "error = %d\n", sc->sc_dev.dv_xname, error);
175			return;
176		}
177		error = bus_dmamem_map(sc->sc_dmat, &seg, rseg, NBPG,
178		    (caddr_t *)&sc->sc_script, BUS_DMA_NOWAIT|BUS_DMA_COHERENT);
179		if (error) {
180			printf("%s: unable to map script DMA memory, "
181			    "error = %d\n", sc->sc_dev.dv_xname, error);
182			return;
183		}
184		error = bus_dmamap_create(sc->sc_dmat, NBPG, 1,
185		    NBPG, 0, BUS_DMA_NOWAIT, &sc->sc_scriptdma);
186		if (error) {
187			printf("%s: unable to create script DMA map, "
188			    "error = %d\n", sc->sc_dev.dv_xname, error);
189			return;
190		}
191		error = bus_dmamap_load(sc->sc_dmat, sc->sc_scriptdma,
192		    sc->sc_script, NBPG, NULL, BUS_DMA_NOWAIT);
193		if (error) {
194			printf("%s: unable to load script DMA map, "
195			    "error = %d\n", sc->sc_dev.dv_xname, error);
196			return;
197		}
198		sc->sc_scriptaddr = sc->sc_scriptdma->dm_segs[0].ds_addr;
199		sc->ram_size = NBPG;
200	}
201	TAILQ_INIT(&sc->free_list);
202	TAILQ_INIT(&sc->ready_list);
203	TAILQ_INIT(&sc->cmds);
204	TAILQ_INIT(&sc->lunsw_list);
205	sc->sc_currschedslot = 0;
206#ifdef SIOP_DEBUG
207	printf("%s: script size = %d, PHY addr=0x%x, VIRT=%p\n",
208	    sc->sc_dev.dv_xname, (int)sizeof(siop_script),
209	    (u_int32_t)sc->sc_scriptaddr, sc->sc_script);
210#endif
211
212	sc->sc_link.adapter_softc = sc;
213	sc->sc_link.openings = 2;
214	sc->sc_link.scsipi_scsi.channel = SCSI_CHANNEL_ONLY_ONE;
215	sc->sc_link.scsipi_scsi.max_target  =
216	    (sc->features & SF_BUS_WIDE) ? 15 : 7;
217	sc->sc_link.scsipi_scsi.max_lun = 7;
218	sc->sc_link.scsipi_scsi.adapter_target = bus_space_read_1(sc->sc_rt,
219	    sc->sc_rh, SIOP_SCID);
220	if (sc->sc_link.scsipi_scsi.adapter_target == 0 ||
221	    sc->sc_link.scsipi_scsi.adapter_target >
222	    sc->sc_link.scsipi_scsi.max_target)
223		sc->sc_link.scsipi_scsi.adapter_target = SIOP_DEFAULT_TARGET;
224	sc->sc_link.type = BUS_SCSI;
225	sc->sc_link.adapter = &siop_adapter;
226	sc->sc_link.device = &siop_dev;
227	sc->sc_link.flags  = 0;
228
229	for (i = 0; i < 16; i++)
230		sc->targets[i] = NULL;
231
232	/* find min/max sync period for this chip */
233	sc->maxsync = 0;
234	sc->minsync = 255;
235	for (i = 0; i < sizeof(scf_period) / sizeof(scf_period[0]); i++) {
236		if (sc->clock_period != scf_period[i].clock)
237			continue;
238		if (sc->maxsync < scf_period[i].period)
239			sc->maxsync = scf_period[i].period;
240		if (sc->minsync > scf_period[i].period)
241			sc->minsync = scf_period[i].period;
242	}
243	if (sc->maxsync == 255 || sc->minsync == 0)
244		panic("siop: can't find my sync parameters\n");
245	/* Do a bus reset, so that devices fall back to narrow/async */
246	siop_resetbus(sc);
247	/*
248	 * siop_reset() will reset the chip, thus clearing pending interrupts
249	 */
250	siop_reset(sc);
251#ifdef DUMP_SCRIPT
252	siop_dump_script(sc);
253#endif
254
255	config_found((struct device*)sc, &sc->sc_link, scsiprint);
256}
257
258void
259siop_reset(sc)
260	struct siop_softc *sc;
261{
262	int i, j;
263	struct siop_lunsw *lunsw;
264
265	siop_common_reset(sc);
266
267	/* copy and patch the script */
268	if (sc->features & SF_CHIP_RAM) {
269		bus_space_write_region_4(sc->sc_ramt, sc->sc_ramh, 0,
270		    siop_script, sizeof(siop_script) / sizeof(siop_script[0]));
271		for (j = 0; j <
272		    (sizeof(E_abs_msgin_Used) / sizeof(E_abs_msgin_Used[0]));
273		    j++) {
274			bus_space_write_4(sc->sc_ramt, sc->sc_ramh,
275			    E_abs_msgin_Used[j] * 4,
276			    sc->sc_scriptaddr + Ent_msgin_space);
277		}
278	} else {
279		for (j = 0;
280		    j < (sizeof(siop_script) / sizeof(siop_script[0])); j++) {
281			sc->sc_script[j] = htole32(siop_script[j]);
282		}
283		for (j = 0; j <
284		    (sizeof(E_abs_msgin_Used) / sizeof(E_abs_msgin_Used[0]));
285		    j++) {
286			sc->sc_script[E_abs_msgin_Used[j]] =
287			    htole32(sc->sc_scriptaddr + Ent_msgin_space);
288		}
289	}
290	sc->script_free_lo = sizeof(siop_script) / sizeof(siop_script[0]);
291	sc->script_free_hi = sc->ram_size / 4;
292
293	/* free used and unused lun switches */
294	while((lunsw = TAILQ_FIRST(&sc->lunsw_list)) != NULL) {
295#ifdef SIOP_DEBUG
296		printf("%s: free lunsw at offset %d\n",
297				sc->sc_dev.dv_xname, lunsw->lunsw_off);
298#endif
299		TAILQ_REMOVE(&sc->lunsw_list, lunsw, next);
300		free(lunsw, M_DEVBUF);
301	}
302	TAILQ_INIT(&sc->lunsw_list);
303	/* restore reselect switch */
304	for (i = 0; i <= sc->sc_link.scsipi_scsi.max_target; i++) {
305		if (sc->targets[i] == NULL)
306			continue;
307#ifdef SIOP_DEBUG
308		printf("%s: restore sw for target %d\n",
309				sc->sc_dev.dv_xname, i);
310#endif
311		free(sc->targets[i]->lunsw, M_DEVBUF);
312		sc->targets[i]->lunsw = siop_get_lunsw(sc);
313		if (sc->targets[i]->lunsw == NULL) {
314			printf("%s: can't alloc lunsw for target %d\n",
315			    sc->sc_dev.dv_xname, i);
316			break;
317		}
318		siop_add_reselsw(sc, i);
319	}
320
321	/* start script */
322	if ((sc->features & SF_CHIP_RAM) == 0) {
323		bus_dmamap_sync(sc->sc_dmat, sc->sc_scriptdma, 0, NBPG,
324		    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
325	}
326	bus_space_write_4(sc->sc_rt, sc->sc_rh, SIOP_DSP,
327	    sc->sc_scriptaddr + Ent_reselect);
328}
329
330#if 0
331#define CALL_SCRIPT(ent) do {\
332	printf ("start script DSA 0x%lx DSP 0x%lx\n", \
333	    siop_cmd->dsa, \
334	    sc->sc_scriptaddr + ent); \
335bus_space_write_4(sc->sc_rt, sc->sc_rh, SIOP_DSP, sc->sc_scriptaddr + ent); \
336} while (0)
337#else
338#define CALL_SCRIPT(ent) do {\
339bus_space_write_4(sc->sc_rt, sc->sc_rh, SIOP_DSP, sc->sc_scriptaddr + ent); \
340} while (0)
341#endif
342
343int
344siop_intr(v)
345	void *v;
346{
347	struct siop_softc *sc = v;
348	struct siop_target *siop_target;
349	struct siop_cmd *siop_cmd;
350	struct siop_lun *siop_lun;
351	struct scsipi_xfer *xs;
352	int istat, sist, sstat1, dstat;
353	u_int32_t irqcode;
354	int need_reset = 0;
355	int offset, target, lun, tag;
356	bus_addr_t dsa;
357	struct siop_cbd *cbdp;
358	int freetarget = 0;
359
360	istat = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_ISTAT);
361	if ((istat & (ISTAT_INTF | ISTAT_DIP | ISTAT_SIP)) == 0)
362		return 0;
363	INCSTAT(siop_stat_intr);
364	if (istat & ISTAT_INTF) {
365		printf("INTRF\n");
366		bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_ISTAT, ISTAT_INTF);
367	}
368	/* use DSA to find the current siop_cmd */
369	dsa = bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSA);
370	for (cbdp = TAILQ_FIRST(&sc->cmds); cbdp != NULL;
371	    cbdp = TAILQ_NEXT(cbdp, next)) {
372		if (dsa >= cbdp->xferdma->dm_segs[0].ds_addr &&
373	    	    dsa < cbdp->xferdma->dm_segs[0].ds_addr + NBPG) {
374			dsa -= cbdp->xferdma->dm_segs[0].ds_addr;
375			siop_cmd = &cbdp->cmds[dsa / sizeof(struct siop_xfer)];
376			siop_table_sync(siop_cmd,
377			    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
378			break;
379		}
380	}
381	if (cbdp == NULL) {
382		siop_cmd = NULL;
383	}
384	if (siop_cmd) {
385		xs = siop_cmd->xs;
386		siop_target = siop_cmd->siop_target;
387		target = siop_cmd->xs->sc_link->scsipi_scsi.target;
388		lun = siop_cmd->xs->sc_link->scsipi_scsi.lun;
389		tag = siop_cmd->tag;
390		siop_lun = siop_target->siop_lun[lun];
391#ifdef DIAGNOSTIC
392		if (siop_cmd->status != CMDST_ACTIVE &&
393		    siop_cmd->status != CMDST_SENSE_ACTIVE) {
394			printf("siop_cmd (lun %d) not active (%d)\n",
395				lun, siop_cmd->status);
396			xs = NULL;
397			siop_target = NULL;
398			target = -1;
399			lun = -1;
400			tag = -1;
401			siop_lun = NULL;
402			siop_cmd = NULL;
403		} else if (siop_lun->siop_tag[tag].active != siop_cmd) {
404			printf("siop_cmd (lun %d tag %d) not in siop_lun "
405			    "active (%p != %p)\n", lun, tag, siop_cmd,
406			    siop_lun->siop_tag[tag].active);
407		}
408#endif
409	} else {
410		xs = NULL;
411		siop_target = NULL;
412		target = -1;
413		lun = -1;
414		tag = -1;
415		siop_lun = NULL;
416	}
417	if (istat & ISTAT_DIP) {
418		dstat = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_DSTAT);
419		if (dstat & DSTAT_SSI) {
420			printf("single step dsp 0x%08x dsa 0x08%x\n",
421			    (int)(bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSP) -
422			    sc->sc_scriptaddr),
423			    bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSA));
424			if ((dstat & ~(DSTAT_DFE | DSTAT_SSI)) == 0 &&
425			    (istat & ISTAT_SIP) == 0) {
426				bus_space_write_1(sc->sc_rt, sc->sc_rh,
427				    SIOP_DCNTL, bus_space_read_1(sc->sc_rt,
428				    sc->sc_rh, SIOP_DCNTL) | DCNTL_STD);
429			}
430			return 1;
431		}
432		if (dstat & ~(DSTAT_SIR | DSTAT_DFE | DSTAT_SSI)) {
433		printf("DMA IRQ:");
434		if (dstat & DSTAT_IID)
435			printf(" Illegal instruction");
436		if (dstat & DSTAT_ABRT)
437			printf(" abort");
438		if (dstat & DSTAT_BF)
439			printf(" bus fault");
440		if (dstat & DSTAT_MDPE)
441			printf(" parity");
442		if (dstat & DSTAT_DFE)
443			printf(" dma fifo empty");
444		printf(", DSP=0x%x DSA=0x%x: ",
445		    (int)(bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSP) -
446		    sc->sc_scriptaddr),
447		    bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSA));
448		if (siop_cmd)
449			printf("last msg_in=0x%x status=0x%x\n",
450			    siop_cmd->siop_tables.msg_in[0],
451			    le32toh(siop_cmd->siop_tables.status));
452		else
453			printf("%s: current DSA invalid\n",
454			    sc->sc_dev.dv_xname);
455		need_reset = 1;
456		}
457	}
458	if (istat & ISTAT_SIP) {
459		if (istat & ISTAT_DIP)
460			delay(10);
461		/*
462		 * Can't read sist0 & sist1 independantly, or we have to
463		 * insert delay
464		 */
465		sist = bus_space_read_2(sc->sc_rt, sc->sc_rh, SIOP_SIST0);
466		sstat1 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SSTAT1);
467#ifdef SIOP_DEBUG_INTR
468		printf("scsi interrupt, sist=0x%x sstat1=0x%x "
469		    "DSA=0x%x DSP=0x%lx\n", sist,
470		    bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SSTAT1),
471		    bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSA),
472		    (u_long)(bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSP) -
473		    sc->sc_scriptaddr));
474#endif
475		if (sist & SIST0_RST) {
476			siop_handle_reset(sc);
477			siop_start(sc);
478			/* no table to flush here */
479			return 1;
480		}
481		if (sist & SIST0_SGE) {
482			if (siop_cmd)
483				scsi_print_addr(xs->sc_link);
484			else
485				printf("%s:", sc->sc_dev.dv_xname);
486			printf("scsi gross error\n");
487			goto reset;
488		}
489		if ((sist & SIST0_MA) && need_reset == 0) {
490			if (siop_cmd) {
491				int scratcha0;
492				dstat = bus_space_read_1(sc->sc_rt, sc->sc_rh,
493				    SIOP_DSTAT);
494				/*
495				 * first restore DSA, in case we were in a S/G
496				 * operation.
497				 */
498				bus_space_write_4(sc->sc_rt, sc->sc_rh,
499				    SIOP_DSA, siop_cmd->dsa);
500				scratcha0 = bus_space_read_1(sc->sc_rt,
501				    sc->sc_rh, SIOP_SCRATCHA);
502				switch (sstat1 & SSTAT1_PHASE_MASK) {
503				case SSTAT1_PHASE_STATUS:
504				/*
505				 * previous phase may be aborted for any reason
506				 * ( for example, the target has less data to
507				 * transfer than requested). Just go to status
508				 * and the command should terminate.
509				 */
510					INCSTAT(siop_stat_intr_shortxfer);
511					if ((dstat & DSTAT_DFE) == 0)
512						siop_clearfifo(sc);
513					/* no table to flush here */
514					CALL_SCRIPT(Ent_status);
515					return 1;
516				case SSTAT1_PHASE_MSGIN:
517					/*
518					 * target may be ready to disconnect
519					 * Save data pointers just in case.
520					 */
521					INCSTAT(siop_stat_intr_xferdisc);
522					if (scratcha0 & A_flag_data)
523						siop_sdp(siop_cmd);
524					else if ((dstat & DSTAT_DFE) == 0)
525						siop_clearfifo(sc);
526					bus_space_write_1(sc->sc_rt, sc->sc_rh,
527					    SIOP_SCRATCHA,
528					    scratcha0 & ~A_flag_data);
529					siop_table_sync(siop_cmd,
530					    BUS_DMASYNC_PREREAD |
531					    BUS_DMASYNC_PREWRITE);
532					CALL_SCRIPT(Ent_msgin);
533					return 1;
534				}
535				printf("%s: unexpected phase mismatch %d\n",
536				    sc->sc_dev.dv_xname,
537				    sstat1 & SSTAT1_PHASE_MASK);
538			} else {
539				printf("%s: phase mismatch without command\n",
540				    sc->sc_dev.dv_xname);
541			}
542			need_reset = 1;
543		}
544		if (sist & SIST0_PAR) {
545			/* parity error, reset */
546			if (siop_cmd)
547				scsi_print_addr(xs->sc_link);
548			else
549				printf("%s:", sc->sc_dev.dv_xname);
550			printf("parity error\n");
551			goto reset;
552		}
553		if ((sist & (SIST1_STO << 8)) && need_reset == 0) {
554			/* selection time out, assume there's no device here */
555			if (siop_cmd) {
556				siop_cmd->status = CMDST_DONE;
557				xs->error = XS_SELTIMEOUT;
558				freetarget = 1;
559				goto end;
560			} else {
561				printf("%s: selection timeout without "
562				    "command\n", sc->sc_dev.dv_xname);
563				need_reset = 1;
564			}
565		}
566		if (sist & SIST0_UDC) {
567			/*
568			 * unexpected disconnect. Usually the target signals
569			 * a fatal condition this way. Attempt to get sense.
570			 */
571			 if (siop_cmd)
572				goto check_sense;
573			printf("%s: unexpected disconnect without "
574			    "command\n", sc->sc_dev.dv_xname);
575			goto reset;
576		}
577		if (sist & (SIST1_SBMC << 8)) {
578			/* SCSI bus mode change */
579			if (siop_modechange(sc) == 0 || need_reset == 1)
580				goto reset;
581			if ((istat & ISTAT_DIP) && (dstat & DSTAT_SIR)) {
582				/*
583				 * we have a script interrupt, it will
584				 * restart the script.
585				 */
586				goto scintr;
587			}
588			/*
589			 * else we have to restart it ourselve, at the
590			 * interrupted instruction.
591			 */
592			bus_space_write_4(sc->sc_rt, sc->sc_rh, SIOP_DSP,
593			    bus_space_read_4(sc->sc_rt, sc->sc_rh,
594			    SIOP_DSP) - 8);
595			return 1;
596		}
597		/* Else it's an unhandled exeption (for now). */
598		printf("%s: unhandled scsi interrupt, sist=0x%x sstat1=0x%x "
599		    "DSA=0x%x DSP=0x%x\n", sc->sc_dev.dv_xname, sist,
600		    bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SSTAT1),
601		    bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSA),
602		    (int)(bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSP) -
603		    sc->sc_scriptaddr));
604		if (siop_cmd) {
605			siop_cmd->status = CMDST_DONE;
606			xs->error = XS_SELTIMEOUT;
607			goto end;
608		}
609		need_reset = 1;
610	}
611	if (need_reset) {
612reset:
613		/* fatal error, reset the bus */
614		siop_resetbus(sc);
615		/* no table to flush here */
616		return 1;
617	}
618
619scintr:
620	if ((istat & ISTAT_DIP) && (dstat & DSTAT_SIR)) { /* script interrupt */
621		irqcode = bus_space_read_4(sc->sc_rt, sc->sc_rh,
622		    SIOP_DSPS);
623#ifdef SIOP_DEBUG_INTR
624		printf("script interrupt 0x%x\n", irqcode);
625#endif
626		/*
627		 * no command, or an inactive command is only valid for a
628		 * reselect interrupt
629		 */
630		if ((irqcode & 0x80) == 0) {
631			if (siop_cmd == NULL) {
632				printf("%s: script interrupt (0x%x) with
633				    invalid DSA !!!\n", sc->sc_dev.dv_xname,
634				    irqcode);
635				goto reset;
636			}
637			if (siop_cmd->status != CMDST_ACTIVE &&
638			    siop_cmd->status != CMDST_SENSE_ACTIVE) {
639				printf("%s: command with invalid status "
640				    "(IRQ code 0x%x current status %d) !\n",
641				    sc->sc_dev.dv_xname,
642				    irqcode, siop_cmd->status);
643				xs = NULL;
644			}
645		}
646		switch(irqcode) {
647		case A_int_err:
648			printf("error, DSP=0x%x\n",
649			    (int)(bus_space_read_4(sc->sc_rt, sc->sc_rh,
650			    SIOP_DSP) - sc->sc_scriptaddr));
651			if (xs) {
652				xs->error = XS_SELTIMEOUT;
653				goto end;
654			} else {
655				goto reset;
656			}
657		case A_int_reseltarg:
658			printf("%s: reselect with invalid target\n",
659				    sc->sc_dev.dv_xname);
660			goto reset;
661		case A_int_resellun:
662			INCSTAT(siop_stat_intr_lunresel);
663			target = bus_space_read_1(sc->sc_rt, sc->sc_rh,
664			    SIOP_SCRATCHA) & 0xf;
665			lun = bus_space_read_1(sc->sc_rt, sc->sc_rh,
666			    SIOP_SCRATCHA + 1);
667			tag = bus_space_read_1(sc->sc_rt, sc->sc_rh,
668			    SIOP_SCRATCHA + 2);
669			siop_target = sc->targets[target];
670			if (siop_target == NULL) {
671				printf("%s: reselect with invalid "
672				    "target %d\n", sc->sc_dev.dv_xname, target);
673				goto reset;
674			}
675			siop_lun = siop_target->siop_lun[lun];
676			if (siop_lun == NULL) {
677				printf("%s: target %d reselect with invalid "
678				    "lun %d\n", sc->sc_dev.dv_xname,
679				    target, lun);
680				goto reset;
681			}
682			if (siop_lun->siop_tag[tag].active == NULL) {
683				printf("%s: target %d lun %d tag %d reselect "
684				    "without command\n", sc->sc_dev.dv_xname,
685				    target, lun, tag);
686				goto reset;
687			}
688			siop_cmd = siop_lun->siop_tag[tag].active;
689			bus_space_write_4(sc->sc_rt, sc->sc_rh, SIOP_DSP,
690			    siop_cmd->dsa + sizeof(struct siop_xfer_common) +
691			    Ent_ldsa_reload_dsa);
692			return 1;
693		case A_int_reseltag:
694			printf("%s: reselect with invalid tag\n",
695				    sc->sc_dev.dv_xname);
696			goto reset;
697		case A_int_msgin:
698		{
699			int msgin = bus_space_read_1(sc->sc_rt, sc->sc_rh,
700			    SIOP_SFBR);
701			if (msgin == MSG_MESSAGE_REJECT) {
702				int msg, extmsg;
703				if (siop_cmd->siop_tables.msg_out[0] & 0x80) {
704					/*
705					 * message was part of a identify +
706					 * something else. Identify shoudl't
707					 * have been rejected.
708					 */
709					msg = siop_cmd->siop_tables.msg_out[1];
710					extmsg =
711					    siop_cmd->siop_tables.msg_out[3];
712				} else {
713					msg = siop_cmd->siop_tables.msg_out[0];
714					extmsg =
715					    siop_cmd->siop_tables.msg_out[2];
716				}
717				if (msg == MSG_MESSAGE_REJECT) {
718					/* MSG_REJECT  for a MSG_REJECT  !*/
719					if (xs)
720						scsi_print_addr(xs->sc_link);
721					else
722						printf("%s: ",
723						   sc->sc_dev.dv_xname);
724					printf("our reject message was "
725					    "rejected\n");
726					goto reset;
727				}
728				if (msg == MSG_EXTENDED &&
729				    extmsg == MSG_EXT_WDTR) {
730					/* WDTR rejected, initiate sync */
731					printf("%s: target %d using 8bit "
732					    "transfers\n", sc->sc_dev.dv_xname,
733					    target);
734					if ((siop_target->flags & TARF_SYNC)
735					    == 0) {
736						siop_target->status = TARST_OK;
737						/* no table to flush here */
738						CALL_SCRIPT(Ent_msgin_ack);
739						return 1;
740					}
741					siop_target->status = TARST_SYNC_NEG;
742					siop_sdtr_msg(siop_cmd, 0,
743					    sc->minsync, sc->maxoff);
744					siop_table_sync(siop_cmd,
745					    BUS_DMASYNC_PREREAD |
746					    BUS_DMASYNC_PREWRITE);
747					CALL_SCRIPT(Ent_send_msgout);
748					return 1;
749				} else if (msg == MSG_EXTENDED &&
750				    extmsg == MSG_EXT_SDTR) {
751					/* sync rejected */
752					printf("%s: target %d asynchronous\n",
753					    sc->sc_dev.dv_xname,
754					    target);
755					siop_target->status = TARST_OK;
756					/* no table to flush here */
757					CALL_SCRIPT(Ent_msgin_ack);
758					return 1;
759				} else if (msg == MSG_SIMPLE_Q_TAG ||
760				    msg == MSG_HEAD_OF_Q_TAG ||
761				    msg == MSG_ORDERED_Q_TAG) {
762					if (siop_handle_qtag_reject(
763					    siop_cmd) == -1)
764						goto reset;
765					CALL_SCRIPT(Ent_msgin_ack);
766					return 1;
767				}
768				if (xs)
769					scsi_print_addr(xs->sc_link);
770				else
771					printf("%s: ", sc->sc_dev.dv_xname);
772				if (msg == MSG_EXTENDED) {
773					printf("scsi message reject, extended "
774					    "message sent was 0x%x\n", extmsg);
775				} else {
776					printf("scsi message reject, message "
777					    "sent was 0x%x\n", msg);
778				}
779				/* no table to flush here */
780				CALL_SCRIPT(Ent_msgin_ack);
781				return 1;
782			}
783			if (xs)
784				scsi_print_addr(xs->sc_link);
785			else
786				printf("%s: ", sc->sc_dev.dv_xname);
787			printf("unhandled message 0x%x\n",
788			    siop_cmd->siop_tables.msg_in[0]);
789			siop_cmd->siop_tables.msg_out[0] = MSG_MESSAGE_REJECT;
790			siop_cmd->siop_tables.t_msgout.count= htole32(1);
791			siop_table_sync(siop_cmd,
792			    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
793			CALL_SCRIPT(Ent_send_msgout);
794			return 1;
795		}
796		case A_int_extmsgin:
797#ifdef SIOP_DEBUG_INTR
798			printf("extended message: msg 0x%x len %d\n",
799			    siop_cmd->siop_tables.msg_in[2],
800			    siop_cmd->siop_tables.msg_in[1]);
801#endif
802			if (siop_cmd->siop_tables.msg_in[1] > 6)
803				printf("%s: extended message too big (%d)\n",
804				    sc->sc_dev.dv_xname,
805				    siop_cmd->siop_tables.msg_in[1]);
806			siop_cmd->siop_tables.t_extmsgdata.count =
807			    htole32(siop_cmd->siop_tables.msg_in[1] - 1);
808			siop_table_sync(siop_cmd,
809			    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
810			CALL_SCRIPT(Ent_get_extmsgdata);
811			return 1;
812		case A_int_extmsgdata:
813#ifdef SIOP_DEBUG_INTR
814			{
815			int i;
816			printf("extended message: 0x%x, data:",
817			    siop_cmd->siop_tables.msg_in[2]);
818			for (i = 3; i < 2 + siop_cmd->siop_tables.msg_in[1];
819			    i++)
820				printf(" 0x%x",
821				    siop_cmd->siop_tables.msg_in[i]);
822			printf("\n");
823			}
824#endif
825			if (siop_cmd->siop_tables.msg_in[2] == MSG_EXT_WDTR) {
826				switch (siop_wdtr_neg(siop_cmd)) {
827				case SIOP_NEG_MSGOUT:
828					siop_update_scntl3(sc,
829					    siop_cmd->siop_target);
830					siop_table_sync(siop_cmd,
831					    BUS_DMASYNC_PREREAD |
832					    BUS_DMASYNC_PREWRITE);
833					CALL_SCRIPT(Ent_send_msgout);
834					return(1);
835				case SIOP_NEG_ACK:
836					siop_update_scntl3(sc,
837					    siop_cmd->siop_target);
838					CALL_SCRIPT(Ent_msgin_ack);
839					return(1);
840				default:
841					panic("invalid retval from "
842					    "siop_wdtr_neg()");
843				}
844				return(1);
845			}
846			if (siop_cmd->siop_tables.msg_in[2] == MSG_EXT_SDTR) {
847				switch (siop_sdtr_neg(siop_cmd)) {
848				case SIOP_NEG_MSGOUT:
849					siop_update_scntl3(sc,
850					    siop_cmd->siop_target);
851					siop_table_sync(siop_cmd,
852					    BUS_DMASYNC_PREREAD |
853					    BUS_DMASYNC_PREWRITE);
854					CALL_SCRIPT(Ent_send_msgout);
855					return(1);
856				case SIOP_NEG_ACK:
857					siop_update_scntl3(sc,
858					    siop_cmd->siop_target);
859					CALL_SCRIPT(Ent_msgin_ack);
860					return(1);
861				default:
862					panic("invalid retval from "
863					    "siop_wdtr_neg()");
864				}
865				return(1);
866			}
867			/* send a message reject */
868			siop_cmd->siop_tables.msg_out[0] = MSG_MESSAGE_REJECT;
869			siop_cmd->siop_tables.t_msgout.count = htole32(1);
870			siop_table_sync(siop_cmd,
871			    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
872			CALL_SCRIPT(Ent_send_msgout);
873			return 1;
874		case A_int_disc:
875			INCSTAT(siop_stat_intr_sdp);
876			offset = bus_space_read_1(sc->sc_rt, sc->sc_rh,
877			    SIOP_SCRATCHA + 1);
878#ifdef SIOP_DEBUG_DR
879			printf("disconnect offset %d\n", offset);
880#endif
881			if (offset > SIOP_NSG) {
882				printf("%s: bad offset for disconnect (%d)\n",
883				    sc->sc_dev.dv_xname, offset);
884				goto reset;
885			}
886			/*
887			 * offset == SIOP_NSG may be a valid condition if
888			 * we get a sdp when the xfer is done.
889			 * Don't call memmove in this case.
890			 */
891			if (offset < SIOP_NSG) {
892				memmove(&siop_cmd->siop_tables.data[0],
893				    &siop_cmd->siop_tables.data[offset],
894				    (SIOP_NSG - offset) * sizeof(scr_table_t));
895				siop_table_sync(siop_cmd,
896				    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
897			}
898			CALL_SCRIPT(Ent_script_sched);
899			/* check if we can put some command in scheduler */
900			siop_start(sc);
901			return 1;
902		case A_int_resfail:
903			printf("reselect failed\n");
904			CALL_SCRIPT(Ent_script_sched);
905			return  1;
906		case A_int_done:
907			if (xs == NULL) {
908				printf("%s: done without command, DSA=0x%lx\n",
909				    sc->sc_dev.dv_xname, (u_long)siop_cmd->dsa);
910				siop_cmd->status = CMDST_FREE;
911				siop_start(sc);
912				CALL_SCRIPT(Ent_script_sched);
913				return 1;
914			}
915#ifdef SIOP_DEBUG_INTR
916			printf("done, DSA=0x%lx target id 0x%x last msg "
917			    "in=0x%x status=0x%x\n", (u_long)siop_cmd->dsa,
918			    le32toh(siop_cmd->siop_tables.id),
919			    siop_cmd->siop_tables.msg_in[0],
920			    le32toh(siop_cmd->siop_tables.status));
921#endif
922			INCSTAT(siop_stat_intr_done);
923			if (siop_cmd->status == CMDST_SENSE_ACTIVE)
924				siop_cmd->status = CMDST_SENSE_DONE;
925			else
926				siop_cmd->status = CMDST_DONE;
927			switch(le32toh(siop_cmd->siop_tables.status)) {
928			case SCSI_OK:
929				xs->error = (siop_cmd->status == CMDST_DONE) ?
930				    XS_NOERROR : XS_SENSE;
931				break;
932			case SCSI_BUSY:
933				xs->error = XS_BUSY;
934				break;
935			case SCSI_CHECK:
936check_sense:
937				if (siop_cmd->status == CMDST_SENSE_DONE) {
938					/* request sense on a request sense ? */
939					printf("request sense failed\n");
940					xs->error = XS_DRIVER_STUFFUP;
941				} else {
942					siop_cmd->status = CMDST_SENSE;
943				}
944				break;
945			case SCSI_QUEUE_FULL:
946				/*
947				 * device didn't queue the command. We have to
948				 * retry it.
949				 * We insert it at the head of the queue,
950				 * hoping to preserve order. Also remember the
951				 * condition, to avoid starting new commands
952				 * for this device before one is done.
953				 */
954				CALL_SCRIPT(Ent_script_sched);
955				siop_lun->siop_tag[tag].active = NULL;
956				siop_lun->lun_flags |= SIOP_LUNF_FULL;
957				siop_cmd->status = CMDST_READY;
958				siop_setuptables(siop_cmd);
959				TAILQ_INSERT_HEAD(&sc->ready_list,
960				    siop_cmd, next);
961				siop_start(sc);
962				return 1;
963			case 0xff:
964				/*
965				 * the status byte was not updated, cmd was
966				 * aborted
967				 */
968				xs->error = XS_SELTIMEOUT;
969				break;
970			default:
971				xs->error = XS_DRIVER_STUFFUP;
972			}
973			goto end;
974		default:
975			printf("unknown irqcode %x\n", irqcode);
976			if (xs) {
977				xs->error = XS_SELTIMEOUT;
978				goto end;
979			}
980			goto reset;
981		}
982		return 1;
983	}
984	/* We just should't get there */
985	panic("siop_intr: I shouldn't be there !");
986	return 1;
987end:
988	CALL_SCRIPT(Ent_script_sched);
989	siop_scsicmd_end(siop_cmd);
990	siop_lun->siop_tag[tag].active = NULL;
991	if (siop_cmd->status == CMDST_FREE) {
992		TAILQ_INSERT_TAIL(&sc->free_list, siop_cmd, next);
993		siop_lun->lun_flags &= ~SIOP_LUNF_FULL;
994		if (freetarget && siop_target->status == TARST_PROBING)
995			siop_del_dev(sc, target, lun);
996	}
997	siop_start(sc);
998	return 1;
999}
1000
1001void
1002siop_scsicmd_end(siop_cmd)
1003	struct siop_cmd *siop_cmd;
1004{
1005	struct scsipi_xfer *xs = siop_cmd->xs;
1006	struct siop_softc *sc = siop_cmd->siop_sc;
1007
1008	if (siop_cmd->status != CMDST_SENSE_DONE &&
1009	    xs->xs_control & (XS_CTL_DATA_IN | XS_CTL_DATA_OUT)) {
1010		bus_dmamap_sync(sc->sc_dmat, siop_cmd->dmamap_data, 0,
1011		    siop_cmd->dmamap_data->dm_mapsize,
1012		    (xs->xs_control & XS_CTL_DATA_IN) ?
1013		    BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
1014		bus_dmamap_unload(sc->sc_dmat, siop_cmd->dmamap_data);
1015	}
1016	bus_dmamap_unload(sc->sc_dmat, siop_cmd->dmamap_cmd);
1017	if (siop_cmd->status == CMDST_SENSE) {
1018		/* issue a request sense for this target */
1019		int error;
1020		siop_cmd->rs_cmd.opcode = REQUEST_SENSE;
1021		siop_cmd->rs_cmd.byte2 = xs->sc_link->scsipi_scsi.lun << 5;
1022		siop_cmd->rs_cmd.unused[0] = siop_cmd->rs_cmd.unused[1] = 0;
1023		siop_cmd->rs_cmd.length = sizeof(struct scsipi_sense_data);
1024		siop_cmd->rs_cmd.control = 0;
1025		siop_cmd->flags &= ~CMDFL_TAG;
1026		error = bus_dmamap_load(sc->sc_dmat, siop_cmd->dmamap_cmd,
1027		    &siop_cmd->rs_cmd, sizeof(struct scsipi_sense),
1028		    NULL, BUS_DMA_NOWAIT);
1029		if (error) {
1030			printf("%s: unable to load cmd DMA map: %d",
1031			    sc->sc_dev.dv_xname, error);
1032			xs->error = XS_DRIVER_STUFFUP;
1033			goto out;
1034		}
1035		error = bus_dmamap_load(sc->sc_dmat, siop_cmd->dmamap_data,
1036		    &xs->sense.scsi_sense, sizeof(struct  scsipi_sense_data),
1037		    NULL, BUS_DMA_NOWAIT);
1038		if (error) {
1039			printf("%s: unable to load sense DMA map: %d",
1040			    sc->sc_dev.dv_xname, error);
1041			xs->error = XS_DRIVER_STUFFUP;
1042			bus_dmamap_unload(sc->sc_dmat, siop_cmd->dmamap_cmd);
1043			goto out;
1044		}
1045		bus_dmamap_sync(sc->sc_dmat, siop_cmd->dmamap_data, 0,
1046		    siop_cmd->dmamap_data->dm_mapsize, BUS_DMASYNC_PREREAD);
1047		bus_dmamap_sync(sc->sc_dmat, siop_cmd->dmamap_cmd, 0,
1048		    siop_cmd->dmamap_cmd->dm_mapsize, BUS_DMASYNC_PREWRITE);
1049
1050		siop_setuptables(siop_cmd);
1051		/* arrange for the cmd to be handled now */
1052		TAILQ_INSERT_HEAD(&sc->ready_list, siop_cmd, next);
1053		return;
1054	} else if (siop_cmd->status == CMDST_SENSE_DONE) {
1055		bus_dmamap_sync(sc->sc_dmat, siop_cmd->dmamap_data, 0,
1056		    siop_cmd->dmamap_data->dm_mapsize, BUS_DMASYNC_POSTREAD);
1057		bus_dmamap_unload(sc->sc_dmat, siop_cmd->dmamap_data);
1058	}
1059out:
1060	callout_stop(&siop_cmd->xs->xs_callout);
1061	siop_cmd->status = CMDST_FREE;
1062	xs->xs_status |= XS_STS_DONE;
1063	xs->resid = 0;
1064	if ((xs->xs_control & XS_CTL_POLL) == 0)
1065		scsipi_done (xs);
1066}
1067
1068/*
1069 * handle a rejected queue tag message: the command will run untagged,
1070 * has to adjust the reselect script.
1071 */
1072int
1073siop_handle_qtag_reject(siop_cmd)
1074	struct siop_cmd *siop_cmd;
1075{
1076	struct siop_softc *sc = siop_cmd->siop_sc;
1077	int target = siop_cmd->xs->sc_link->scsipi_scsi.target;
1078	int lun = siop_cmd->xs->sc_link->scsipi_scsi.lun;
1079	int tag = siop_cmd->siop_tables.msg_out[2];
1080	struct siop_lun *siop_lun = sc->targets[target]->siop_lun[lun];
1081
1082	if (siop_lun->siop_tag[0].active != NULL) {
1083		printf("%s: untagged command already running for target %d
1084		    lun %d\n", sc->sc_dev.dv_xname, target, lun);
1085		return -1;
1086	}
1087	/* clear tag slot */
1088	siop_lun->siop_tag[tag].active = NULL;
1089	/* add command to non-tagged slot */
1090	siop_lun->siop_tag[0].active = siop_cmd;
1091	siop_cmd->tag = 0;
1092	/* adjust reselect script if there is one */
1093	if (siop_lun->siop_tag[0].reseloff > 0) {
1094		siop_script_write(sc,
1095		    siop_lun->siop_tag[0].reseloff + 1,
1096		    siop_cmd->dsa + sizeof(struct siop_xfer_common) +
1097		    Ent_ldsa_reload_dsa);
1098	}
1099	return 0;
1100}
1101
1102/*
1103 * handle a bus reset: reset chip, unqueue all active commands, free all
1104 * target struct and report loosage to upper layer.
1105 * As the upper layer may requeue immediatly we have to first store
1106 * all active commands in a temporary queue.
1107 */
1108void
1109siop_handle_reset(sc)
1110	struct siop_softc *sc;
1111{
1112	struct cmd_list reset_list;
1113	struct siop_cmd *siop_cmd, *next_siop_cmd;
1114	struct siop_lun *siop_lun;
1115	int target, lun, tag;
1116	/*
1117	 * scsi bus reset. reset the chip and restart
1118	 * the queue. Need to clean up all active commands
1119	 */
1120	printf("%s: scsi bus reset\n", sc->sc_dev.dv_xname);
1121	/* stop, reset and restart the chip */
1122	siop_reset(sc);
1123	TAILQ_INIT(&reset_list);
1124	/* find all active commands */
1125	for (target = 0; target <= sc->sc_link.scsipi_scsi.max_target;
1126	    target++) {
1127		if (sc->targets[target] == NULL)
1128			continue;
1129		for (lun = 0; lun < 8; lun++) {
1130			siop_lun = sc->targets[target]->siop_lun[lun];
1131			if (siop_lun == NULL)
1132				continue;
1133			for (tag = 0; tag <
1134			    ((sc->targets[target]->flags & TARF_TAG) ?
1135			    SIOP_NTAG : 0);
1136			    tag++) {
1137				siop_cmd = siop_lun->siop_tag[tag].active;
1138				if (siop_cmd == NULL)
1139					continue;
1140				printf("cmd %p (target %d:%d) in reset list\n",
1141				    siop_cmd, target, lun);
1142				TAILQ_INSERT_TAIL(&reset_list, siop_cmd, next);
1143				siop_lun->siop_tag[tag].active = NULL;
1144			}
1145		}
1146		sc->targets[target]->status = TARST_ASYNC;
1147		sc->targets[target]->flags &= ~TARF_ISWIDE;
1148	}
1149	for (siop_cmd = TAILQ_FIRST(&sc->ready_list); siop_cmd != NULL;
1150	    siop_cmd = next_siop_cmd) {
1151		next_siop_cmd = TAILQ_NEXT(siop_cmd, next);
1152		if (siop_cmd->status != CMDST_SENSE)
1153			continue;
1154		printf("cmd %p (target %d:%d) in reset list (sense)\n",
1155		    siop_cmd, siop_cmd->xs->sc_link->scsipi_scsi.target,
1156		    siop_cmd->xs->sc_link->scsipi_scsi.lun);
1157		TAILQ_REMOVE(&sc->ready_list, siop_cmd, next);
1158		TAILQ_INSERT_TAIL(&reset_list, siop_cmd, next);
1159	}
1160
1161	for (siop_cmd = TAILQ_FIRST(&reset_list); siop_cmd != NULL;
1162	    siop_cmd = next_siop_cmd) {
1163		next_siop_cmd = TAILQ_NEXT(siop_cmd, next);
1164		siop_cmd->xs->error = (siop_cmd->flags & CMDFL_TIMEOUT) ?
1165		    XS_TIMEOUT : XS_RESET;
1166		printf("cmd %p (status %d) about to be processed\n", siop_cmd,
1167		    siop_cmd->status);
1168		if (siop_cmd->status == CMDST_SENSE ||
1169		    siop_cmd->status == CMDST_SENSE_ACTIVE)
1170			siop_cmd->status = CMDST_SENSE_DONE;
1171		else
1172			siop_cmd->status = CMDST_DONE;
1173		TAILQ_REMOVE(&reset_list, siop_cmd, next);
1174		siop_scsicmd_end(siop_cmd);
1175		TAILQ_INSERT_TAIL(&sc->free_list, siop_cmd, next);
1176	}
1177}
1178
1179int
1180siop_scsicmd(xs)
1181	struct scsipi_xfer *xs;
1182{
1183	struct siop_softc *sc = (struct siop_softc *)xs->sc_link->adapter_softc;
1184	struct siop_cmd *siop_cmd;
1185	int s, error, i;
1186	const int target = xs->sc_link->scsipi_scsi.target;
1187	const int lun = xs->sc_link->scsipi_scsi.lun;
1188
1189	s = splbio();
1190#ifdef SIOP_DEBUG_SCHED
1191	printf("starting cmd for %d:%d\n", target, lun);
1192#endif
1193	siop_cmd = TAILQ_FIRST(&sc->free_list);
1194	if (siop_cmd) {
1195		TAILQ_REMOVE(&sc->free_list, siop_cmd, next);
1196	} else {
1197		if (siop_morecbd(sc) == 0) {
1198			siop_cmd = TAILQ_FIRST(&sc->free_list);
1199#ifdef DIAGNOSTIC
1200			if (siop_cmd == NULL)
1201				panic("siop_morecbd succeed and does nothing");
1202#endif
1203			TAILQ_REMOVE(&sc->free_list, siop_cmd, next);
1204		}
1205	}
1206	if (siop_cmd == NULL) {
1207		xs->error = XS_DRIVER_STUFFUP;
1208		splx(s);
1209		return(TRY_AGAIN_LATER);
1210	}
1211#ifdef DIAGNOSTIC
1212	if (siop_cmd->status != CMDST_FREE)
1213		panic("siop_scsicmd: new cmd not free");
1214#endif
1215	if (sc->targets[target] == NULL) {
1216#ifdef SIOP_DEBUG
1217		printf("%s: alloc siop_target for target %d\n",
1218			sc->sc_dev.dv_xname, target);
1219#endif
1220		sc->targets[target] =
1221		    malloc(sizeof(struct siop_target), M_DEVBUF, M_NOWAIT);
1222		if (sc->targets[target] == NULL) {
1223			printf("%s: can't malloc memory for target %d\n",
1224			    sc->sc_dev.dv_xname, target);
1225			xs->error = XS_DRIVER_STUFFUP;
1226			splx(s);
1227			return(TRY_AGAIN_LATER);
1228		}
1229		sc->targets[target]->status = TARST_PROBING;
1230		sc->targets[target]->flags = 0;
1231		sc->targets[target]->id = sc->clock_div << 24; /* scntl3 */
1232		sc->targets[target]->id |=  target << 16; /* id */
1233		/* sc->targets[target]->id |= 0x0 << 8; scxfer is 0 */
1234
1235		/* get a lun switch script */
1236		sc->targets[target]->lunsw = siop_get_lunsw(sc);
1237		if (sc->targets[target]->lunsw == NULL) {
1238			printf("%s: can't alloc lunsw for target %d\n",
1239			    sc->sc_dev.dv_xname, target);
1240			xs->error = XS_DRIVER_STUFFUP;
1241			splx(s);
1242			return(TRY_AGAIN_LATER);
1243		}
1244		for (i=0; i < 8; i++)
1245			sc->targets[target]->siop_lun[i] = NULL;
1246		siop_add_reselsw(sc, target);
1247	}
1248	if (sc->targets[target]->siop_lun[lun] == NULL) {
1249		sc->targets[target]->siop_lun[lun] =
1250		    malloc(sizeof(struct siop_lun), M_DEVBUF, M_NOWAIT);
1251		if (sc->targets[target]->siop_lun[lun] == NULL) {
1252			printf("%s: can't alloc siop_lun for target %d "
1253			    "lun %d\n", sc->sc_dev.dv_xname, target, lun);
1254			xs->error = XS_DRIVER_STUFFUP;
1255			splx(s);
1256			return(TRY_AGAIN_LATER);
1257		}
1258		memset(sc->targets[target]->siop_lun[lun], 0,
1259		    sizeof(struct siop_lun));
1260	}
1261	siop_cmd->siop_target = sc->targets[target];
1262	siop_cmd->xs = xs;
1263	siop_cmd->flags = 0;
1264	siop_cmd->status = CMDST_READY;
1265
1266	/* load the DMA maps */
1267	error = bus_dmamap_load(sc->sc_dmat, siop_cmd->dmamap_cmd,
1268	    xs->cmd, xs->cmdlen, NULL, BUS_DMA_NOWAIT);
1269	if (error) {
1270		printf("%s: unable to load cmd DMA map: %d",
1271		    sc->sc_dev.dv_xname, error);
1272		xs->error = XS_DRIVER_STUFFUP;
1273		splx(s);
1274		return(TRY_AGAIN_LATER);
1275	}
1276	if (xs->xs_control & (XS_CTL_DATA_IN | XS_CTL_DATA_OUT)) {
1277		error = bus_dmamap_load(sc->sc_dmat, siop_cmd->dmamap_data,
1278		    xs->data, xs->datalen, NULL, BUS_DMA_NOWAIT);
1279		if (error) {
1280			printf("%s: unable to load cmd DMA map: %d",
1281			    sc->sc_dev.dv_xname, error);
1282			xs->error = XS_DRIVER_STUFFUP;
1283			bus_dmamap_unload(sc->sc_dmat, siop_cmd->dmamap_cmd);
1284			splx(s);
1285			return(TRY_AGAIN_LATER);
1286		}
1287		bus_dmamap_sync(sc->sc_dmat, siop_cmd->dmamap_data, 0,
1288		    siop_cmd->dmamap_data->dm_mapsize,
1289		    (xs->xs_control & XS_CTL_DATA_IN) ?
1290		    BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE);
1291	}
1292	bus_dmamap_sync(sc->sc_dmat, siop_cmd->dmamap_cmd, 0,
1293	    siop_cmd->dmamap_cmd->dm_mapsize, BUS_DMASYNC_PREWRITE);
1294
1295	siop_setuptables(siop_cmd);
1296
1297	TAILQ_INSERT_TAIL(&sc->ready_list, siop_cmd, next);
1298	siop_start(sc);
1299	if (xs->xs_control & XS_CTL_POLL) {
1300		/* poll for command completion */
1301		while ((xs->xs_status & XS_STS_DONE) == 0) {
1302			delay(1000);
1303			siop_intr(sc);
1304		}
1305		splx(s);
1306		return (COMPLETE);
1307	}
1308	splx(s);
1309	return (SUCCESSFULLY_QUEUED);
1310}
1311
1312void
1313siop_start(sc)
1314	struct siop_softc *sc;
1315{
1316	struct siop_cmd *siop_cmd, *next_siop_cmd;
1317	struct siop_lun *siop_lun;
1318	u_int32_t dsa;
1319	int timeout;
1320	int target, lun, tag, slot;
1321	int newcmd = 0;
1322	int msgcount;
1323
1324	/*
1325	 * first make sure to read valid data
1326	 */
1327	siop_script_sync(sc, BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
1328
1329	/*
1330	 * The queue management here is a bit tricky: the script always looks
1331	 * at the slot from first to last, so if we always use the first
1332	 * free slot commands can stay at the tail of the queue ~forever.
1333	 * The algorithm used here is to restart from the head when we know
1334	 * that the queue is empty, and only add commands after the last one.
1335	 * When we're at the end of the queue wait for the script to clear it.
1336	 * The best thing to do here would be to implement a circular queue,
1337	 * but using only 53c720 features this can be "interesting".
1338	 * A mid-way solution could be to implement 2 queues and swap orders.
1339	 */
1340	slot = sc->sc_currschedslot;
1341	/*
1342	 * If the instruction is 0x80000000 (JUMP foo, IF FALSE) the slot is
1343	 * free. As this is the last used slot, all previous slots are free,
1344	 * we can restart from 0.
1345	 */
1346	if (siop_script_read(sc, (Ent_script_sched_slot0 / 4) + slot * 2) ==
1347	    0x80000000) {
1348		slot = sc->sc_currschedslot = 0;
1349	} else {
1350		slot++;
1351	}
1352
1353	for (siop_cmd = TAILQ_FIRST(&sc->ready_list); siop_cmd != NULL;
1354	    siop_cmd = next_siop_cmd) {
1355		next_siop_cmd = TAILQ_NEXT(siop_cmd, next);
1356#ifdef DIAGNOSTIC
1357		if (siop_cmd->status != CMDST_READY &&
1358		    siop_cmd->status != CMDST_SENSE)
1359			panic("siop: non-ready cmd in ready list");
1360#endif
1361		target = siop_cmd->xs->sc_link->scsipi_scsi.target;
1362		lun = siop_cmd->xs->sc_link->scsipi_scsi.lun;
1363		siop_lun = sc->targets[target]->siop_lun[lun];
1364		/* if non-tagged command active, wait */
1365		if (siop_lun->siop_tag[0].active != NULL)
1366			continue;
1367		/*
1368		 * if we're in a queue full condition don't start a new
1369		 * command, unless it's a request sense
1370		 */
1371		if ((siop_lun->lun_flags & SIOP_LUNF_FULL) &&
1372		    siop_cmd->status == CMDST_READY)
1373			continue;
1374		/* find a free tag if needed */
1375		if (siop_cmd->flags & CMDFL_TAG) {
1376			for (tag = 1; tag < SIOP_NTAG; tag++) {
1377				if (siop_lun->siop_tag[tag].active == NULL)
1378					break;
1379			}
1380			if (tag == SIOP_NTAG) /* no free tag */
1381				continue;
1382			msgcount =
1383			    le32toh(siop_cmd->siop_tables.t_msgout.count);
1384			if (siop_cmd->xs->bp != NULL &&
1385			    (siop_cmd->xs->bp->b_flags & B_ASYNC))
1386				siop_cmd->siop_tables.msg_out[msgcount] =
1387				    MSG_SIMPLE_Q_TAG;
1388			else
1389				siop_cmd->siop_tables.msg_out[msgcount] =
1390				    MSG_ORDERED_Q_TAG;
1391			siop_cmd->siop_tables.msg_out[msgcount + 1] = tag;
1392			siop_cmd->siop_tables.t_msgout.count =
1393			    htole32(msgcount + 2);
1394		} else {
1395			tag = 0;
1396		}
1397		siop_cmd->tag = tag;
1398		/* find a free scheduler slot and load it */
1399		for (; slot < SIOP_NSLOTS; slot++) {
1400			/*
1401			 * If cmd if 0x80000000 the slot is free
1402			 */
1403			if (siop_script_read(sc,
1404			    (Ent_script_sched_slot0 / 4) + slot * 2) ==
1405			    0x80000000)
1406				break;
1407		}
1408		/* no more free slot, no need to continue */
1409		if (slot == SIOP_NSLOTS) {
1410			goto end;
1411		}
1412#ifdef SIOP_DEBUG_SCHED
1413		printf("using slot %d for DSA 0x%lx\n", slot,
1414		    (u_long)siop_cmd->dsa);
1415#endif
1416		/* note that we started a new command */
1417		newcmd = 1;
1418		/* mark command as active */
1419		if (siop_cmd->status == CMDST_READY) {
1420			siop_cmd->status = CMDST_ACTIVE;
1421		} else if (siop_cmd->status == CMDST_SENSE) {
1422			siop_cmd->status = CMDST_SENSE_ACTIVE;
1423		} else
1424			panic("siop_start: bad status");
1425		TAILQ_REMOVE(&sc->ready_list, siop_cmd, next);
1426		siop_lun->siop_tag[tag].active = siop_cmd;
1427		/* patch scripts with DSA addr */
1428		dsa = siop_cmd->dsa;
1429		/* first reselect switch, if we have an entry */
1430		if (siop_lun->siop_tag[tag].reseloff > 0)
1431			siop_script_write(sc,
1432			    siop_lun->siop_tag[tag].reseloff + 1,
1433			    dsa + sizeof(struct siop_xfer_common) +
1434			    Ent_ldsa_reload_dsa);
1435		/* CMD script: MOVE MEMORY addr */
1436		siop_cmd->siop_xfer->resel[E_ldsa_abs_slot_Used[0]] =
1437		   htole32(sc->sc_scriptaddr + Ent_script_sched_slot0 +
1438		   slot * 8);
1439		/* scheduler slot: JUMP ldsa_select */
1440		siop_script_write(sc,
1441		    (Ent_script_sched_slot0 / 4) + slot * 2 + 1,
1442		    dsa + sizeof(struct siop_xfer_common) + Ent_ldsa_select);
1443		/* handle timeout */
1444		if (siop_cmd->status == CMDST_ACTIVE) {
1445			if ((siop_cmd->xs->xs_control &
1446			    XS_CTL_POLL) == 0) {
1447				/* start exire timer */
1448				timeout = (u_int64_t) siop_cmd->xs->timeout *
1449				    (u_int64_t)hz / 1000;
1450				if (timeout == 0)
1451					timeout = 1;
1452				callout_reset( &siop_cmd->xs->xs_callout,
1453				    timeout, siop_timeout, siop_cmd);
1454			}
1455		}
1456		/*
1457		 * Change JUMP cmd so that this slot will be handled
1458		 */
1459		siop_script_write(sc, (Ent_script_sched_slot0 / 4) + slot * 2,
1460		    0x80080000);
1461		sc->sc_currschedslot = slot;
1462		slot++;
1463	}
1464end:
1465	/* if nothing changed no need to flush cache and wakeup script */
1466	if (newcmd == 0)
1467		return;
1468	/* make sure SCRIPT processor will read valid data */
1469	siop_script_sync(sc,BUS_DMASYNC_PREREAD |  BUS_DMASYNC_PREWRITE);
1470	/* Signal script it has some work to do */
1471	bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_ISTAT, ISTAT_SIGP);
1472	/* and wait for IRQ */
1473	return;
1474}
1475
1476void
1477siop_timeout(v)
1478	void *v;
1479{
1480	struct siop_cmd *siop_cmd = v;
1481	struct siop_softc *sc = siop_cmd->siop_sc;
1482	int s;
1483
1484	scsi_print_addr(siop_cmd->xs->sc_link);
1485	printf("command timeout\n");
1486
1487	s = splbio();
1488	/* reset the scsi bus */
1489	siop_resetbus(sc);
1490
1491	/* deactivate callout */
1492	callout_stop(&siop_cmd->xs->xs_callout);
1493	/* mark command as being timed out; siop_intr will handle it */
1494	/*
1495	 * mark command has being timed out and just return;
1496	 * the bus reset will generate an interrupt,
1497	 * it will be handled in siop_intr()
1498	 */
1499	siop_cmd->flags |= CMDFL_TIMEOUT;
1500	splx(s);
1501	return;
1502
1503}
1504
1505void
1506siop_dump_script(sc)
1507	struct siop_softc *sc;
1508{
1509	int i;
1510	for (i = 0; i < NBPG / 4; i += 2) {
1511		printf("0x%04x: 0x%08x 0x%08x", i * 4,
1512		    le32toh(sc->sc_script[i]), le32toh(sc->sc_script[i+1]));
1513		if ((le32toh(sc->sc_script[i]) & 0xe0000000) == 0xc0000000) {
1514			i++;
1515			printf(" 0x%08x", le32toh(sc->sc_script[i+1]));
1516		}
1517		printf("\n");
1518	}
1519}
1520
1521int
1522siop_morecbd(sc)
1523	struct siop_softc *sc;
1524{
1525	int error, i, j;
1526	bus_dma_segment_t seg;
1527	int rseg;
1528	struct siop_cbd *newcbd;
1529	bus_addr_t dsa;
1530	u_int32_t *scr;
1531
1532	/* allocate a new list head */
1533	newcbd = malloc(sizeof(struct siop_cbd), M_DEVBUF, M_NOWAIT);
1534	if (newcbd == NULL) {
1535		printf("%s: can't allocate memory for command descriptors "
1536		    "head\n", sc->sc_dev.dv_xname);
1537		return ENOMEM;
1538	}
1539	memset(newcbd, 0, sizeof(struct siop_cbd));
1540
1541	/* allocate cmd list */
1542	newcbd->cmds =
1543	    malloc(sizeof(struct siop_cmd) * SIOP_NCMDPB, M_DEVBUF, M_NOWAIT);
1544	if (newcbd->cmds == NULL) {
1545		printf("%s: can't allocate memory for command descriptors\n",
1546		    sc->sc_dev.dv_xname);
1547		error = ENOMEM;
1548		goto bad3;
1549	}
1550	memset(newcbd->cmds, 0, sizeof(struct siop_cmd) * SIOP_NCMDPB);
1551	error = bus_dmamem_alloc(sc->sc_dmat, NBPG, NBPG, 0, &seg, 1, &rseg,
1552	    BUS_DMA_NOWAIT);
1553	if (error) {
1554		printf("%s: unable to allocate cbd DMA memory, error = %d\n",
1555		    sc->sc_dev.dv_xname, error);
1556		goto bad2;
1557	}
1558	error = bus_dmamem_map(sc->sc_dmat, &seg, rseg, NBPG,
1559	    (caddr_t *)&newcbd->xfers, BUS_DMA_NOWAIT|BUS_DMA_COHERENT);
1560	if (error) {
1561		printf("%s: unable to map cbd DMA memory, error = %d\n",
1562		    sc->sc_dev.dv_xname, error);
1563		goto bad2;
1564	}
1565	error = bus_dmamap_create(sc->sc_dmat, NBPG, 1, NBPG, 0,
1566	    BUS_DMA_NOWAIT, &newcbd->xferdma);
1567	if (error) {
1568		printf("%s: unable to create cbd DMA map, error = %d\n",
1569		    sc->sc_dev.dv_xname, error);
1570		goto bad1;
1571	}
1572	error = bus_dmamap_load(sc->sc_dmat, newcbd->xferdma, newcbd->xfers,
1573	    NBPG, NULL, BUS_DMA_NOWAIT);
1574	if (error) {
1575		printf("%s: unable to load cbd DMA map, error = %d\n",
1576		    sc->sc_dev.dv_xname, error);
1577		goto bad0;
1578	}
1579#ifdef DEBUG
1580	printf("%s: alloc newcdb at PHY addr 0x%lx\n", sc->sc_dev.dv_xname,
1581	    (unsigned long)newcbd->xferdma->dm_segs[0].ds_addr);
1582#endif
1583
1584	for (i = 0; i < SIOP_NCMDPB; i++) {
1585		error = bus_dmamap_create(sc->sc_dmat, MAXPHYS, SIOP_NSG,
1586		    MAXPHYS, 0, BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW,
1587		    &newcbd->cmds[i].dmamap_data);
1588		if (error) {
1589			printf("%s: unable to create data DMA map for cbd: "
1590			    "error %d\n",
1591			    sc->sc_dev.dv_xname, error);
1592			goto bad0;
1593		}
1594		error = bus_dmamap_create(sc->sc_dmat,
1595		    sizeof(struct scsipi_generic), 1,
1596		    sizeof(struct scsipi_generic), 0,
1597		    BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW,
1598		    &newcbd->cmds[i].dmamap_cmd);
1599		if (error) {
1600			printf("%s: unable to create cmd DMA map for cbd %d\n",
1601			    sc->sc_dev.dv_xname, error);
1602			goto bad0;
1603		}
1604		newcbd->cmds[i].siop_sc = sc;
1605		newcbd->cmds[i].siop_cbdp = newcbd;
1606		newcbd->cmds[i].siop_xfer = &newcbd->xfers[i];
1607		memset(newcbd->cmds[i].siop_xfer, 0,
1608		    sizeof(struct siop_xfer));
1609		newcbd->cmds[i].dsa = newcbd->xferdma->dm_segs[0].ds_addr +
1610		    i * sizeof(struct siop_xfer);
1611		dsa = newcbd->cmds[i].dsa;
1612		newcbd->cmds[i].status = CMDST_FREE;
1613		newcbd->cmds[i].siop_tables.t_msgout.count= htole32(1);
1614		newcbd->cmds[i].siop_tables.t_msgout.addr = htole32(dsa);
1615		newcbd->cmds[i].siop_tables.t_msgin.count= htole32(1);
1616		newcbd->cmds[i].siop_tables.t_msgin.addr = htole32(dsa + 8);
1617		newcbd->cmds[i].siop_tables.t_extmsgin.count= htole32(2);
1618		newcbd->cmds[i].siop_tables.t_extmsgin.addr = htole32(dsa + 9);
1619		newcbd->cmds[i].siop_tables.t_extmsgdata.addr =
1620		    htole32(dsa + 11);
1621		newcbd->cmds[i].siop_tables.t_status.count= htole32(1);
1622		newcbd->cmds[i].siop_tables.t_status.addr = htole32(dsa + 16);
1623
1624		/* The select/reselect script */
1625		scr = &newcbd->cmds[i].siop_xfer->resel[0];
1626		for (j = 0; j < sizeof(load_dsa) / sizeof(load_dsa[0]); j++)
1627			scr[j] = htole32(load_dsa[j]);
1628		/*
1629		 * 0x78000000 is a 'move data8 to reg'. data8 is the second
1630		 * octet, reg offset is the third.
1631		 */
1632		scr[Ent_rdsa0 / 4] =
1633		    htole32(0x78100000 | ((dsa & 0x000000ff) <<  8));
1634		scr[Ent_rdsa1 / 4] =
1635		    htole32(0x78110000 | ( dsa & 0x0000ff00       ));
1636		scr[Ent_rdsa2 / 4] =
1637		    htole32(0x78120000 | ((dsa & 0x00ff0000) >>  8));
1638		scr[Ent_rdsa3 / 4] =
1639		    htole32(0x78130000 | ((dsa & 0xff000000) >> 16));
1640		scr[E_ldsa_abs_reselected_Used[0]] =
1641		    htole32(sc->sc_scriptaddr + Ent_reselected);
1642		scr[E_ldsa_abs_reselect_Used[0]] =
1643		    htole32(sc->sc_scriptaddr + Ent_reselect);
1644		scr[E_ldsa_abs_selected_Used[0]] =
1645		    htole32(sc->sc_scriptaddr + Ent_selected);
1646		scr[E_ldsa_abs_data_Used[0]] =
1647		    htole32(dsa + sizeof(struct siop_xfer_common) +
1648		    Ent_ldsa_data);
1649		/* JUMP foo, IF FALSE - used by MOVE MEMORY to clear the slot */
1650		scr[Ent_ldsa_data / 4] = htole32(0x80000000);
1651		TAILQ_INSERT_TAIL(&sc->free_list, &newcbd->cmds[i], next);
1652#ifdef SIOP_DEBUG
1653		printf("tables[%d]: in=0x%x out=0x%x status=0x%x\n", i,
1654		    le32toh(newcbd->cmds[i].siop_tables.t_msgin.addr),
1655		    le32toh(newcbd->cmds[i].siop_tables.t_msgout.addr),
1656		    le32toh(newcbd->cmds[i].siop_tables.t_status.addr));
1657		for (j = 0; j < sizeof(load_dsa) / sizeof(load_dsa[0]);
1658		    j += 2) {
1659			printf("0x%x 0x%x\n", scr[j], scr[j+1]);
1660		}
1661#endif
1662	}
1663	TAILQ_INSERT_TAIL(&sc->cmds, newcbd, next);
1664	return 0;
1665bad0:
1666	bus_dmamap_destroy(sc->sc_dmat, newcbd->xferdma);
1667bad1:
1668	bus_dmamem_free(sc->sc_dmat, &seg, rseg);
1669bad2:
1670	free(newcbd->cmds, M_DEVBUF);
1671bad3:
1672	free(newcbd, M_DEVBUF);
1673	return error;
1674}
1675
1676struct siop_lunsw *
1677siop_get_lunsw(sc)
1678	struct siop_softc *sc;
1679{
1680	struct siop_lunsw *lunsw;
1681	int i;
1682
1683	if (sc->script_free_lo + (sizeof(lun_switch) / sizeof(lun_switch[0])) >=
1684	    sc->script_free_hi)
1685		return NULL;
1686	lunsw = TAILQ_FIRST(&sc->lunsw_list);
1687	if (lunsw != NULL) {
1688#ifdef SIOP_DEBUG
1689		printf("siop_get_lunsw got lunsw at offset %d\n",
1690		    lunsw->lunsw_off);
1691#endif
1692		TAILQ_REMOVE(&sc->lunsw_list, lunsw, next);
1693		return lunsw;
1694	}
1695	lunsw = malloc(sizeof(struct siop_lunsw), M_DEVBUF, M_NOWAIT);
1696	if (lunsw == NULL)
1697		return NULL;
1698	memset(lunsw, 0, sizeof(struct siop_lunsw));
1699#ifdef SIOP_DEBUG
1700	printf("allocating lunsw at offset %d\n", sc->script_free_lo);
1701#endif
1702	if (sc->features & SF_CHIP_RAM) {
1703		bus_space_write_region_4(sc->sc_ramt, sc->sc_ramh,
1704		    sc->script_free_lo * 4, lun_switch,
1705		    sizeof(lun_switch) / sizeof(lun_switch[0]));
1706		bus_space_write_4(sc->sc_ramt, sc->sc_ramh,
1707		    (sc->script_free_lo + E_abs_lunsw_return_Used[0]) * 4,
1708		    sc->sc_scriptaddr + Ent_lunsw_return);
1709	} else {
1710		for (i = 0; i < sizeof(lun_switch) / sizeof(lun_switch[0]);
1711		    i++)
1712			sc->sc_script[sc->script_free_lo + i] =
1713			    htole32(lun_switch[i]);
1714		sc->sc_script[sc->script_free_lo + E_abs_lunsw_return_Used[0]] =
1715		    htole32(sc->sc_scriptaddr + Ent_lunsw_return);
1716	}
1717	lunsw->lunsw_off = sc->script_free_lo;
1718	lunsw->lunsw_size = sizeof(lun_switch) / sizeof(lun_switch[0]);
1719	sc->script_free_lo += lunsw->lunsw_size;
1720	if (sc->script_free_lo > 1024)
1721		printf("%s: script_free_lo (%d) > 1024\n", sc->sc_dev.dv_xname,
1722		    sc->script_free_lo);
1723	siop_script_sync(sc, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1724	return lunsw;
1725}
1726
1727void
1728siop_add_reselsw(sc, target)
1729	struct siop_softc *sc;
1730	int target;
1731{
1732	int i;
1733	struct siop_lun *siop_lun;
1734	/*
1735	 * add an entry to resel switch
1736	 */
1737	siop_script_sync(sc, BUS_DMASYNC_POSTWRITE);
1738	for (i = 0; i < 15; i++) {
1739		sc->targets[target]->reseloff = Ent_resel_targ0 / 4 + i * 2;
1740		if ((siop_script_read(sc, sc->targets[target]->reseloff) & 0xff)
1741		    == 0xff) { /* it's free */
1742#ifdef SIOP_DEBUG
1743			printf("siop: target %d slot %d offset %d\n",
1744			    target, i, sc->targets[target]->reseloff);
1745#endif
1746			/* JUMP abs_foo, IF target | 0x80; */
1747			siop_script_write(sc, sc->targets[target]->reseloff,
1748			    0x800c0080 | target);
1749			siop_script_write(sc, sc->targets[target]->reseloff + 1,
1750			    sc->sc_scriptaddr +
1751			    sc->targets[target]->lunsw->lunsw_off * 4 +
1752			    Ent_lun_switch_entry);
1753			break;
1754		}
1755	}
1756	if (i == 15) /* no free slot, shouldn't happen */
1757		panic("siop: resel switch full");
1758
1759	sc->sc_ntargets++;
1760	for (i = 0; i < 8; i++) {
1761		siop_lun = sc->targets[target]->siop_lun[i];
1762		if (siop_lun == NULL)
1763			continue;
1764		if (siop_lun->reseloff > 0) {
1765			siop_lun->reseloff = 0;
1766			siop_add_dev(sc, target, i);
1767		}
1768	}
1769	siop_update_scntl3(sc, sc->targets[target]);
1770	siop_script_sync(sc, BUS_DMASYNC_PREWRITE);
1771}
1772
1773void
1774siop_update_scntl3(sc, siop_target)
1775	struct siop_softc *sc;
1776	struct siop_target *siop_target;
1777{
1778	/* MOVE target->id >> 24 TO SCNTL3 */
1779	siop_script_write(sc,
1780	    siop_target->lunsw->lunsw_off + (Ent_restore_scntl3 / 4),
1781	    0x78030000 | ((siop_target->id >> 16) & 0x0000ff00));
1782	/* MOVE target->id >> 8 TO SXFER */
1783	siop_script_write(sc,
1784	    siop_target->lunsw->lunsw_off + (Ent_restore_scntl3 / 4) + 2,
1785	    0x78050000 | (siop_target->id & 0x0000ff00));
1786	siop_script_sync(sc, BUS_DMASYNC_PREWRITE);
1787}
1788
1789void
1790siop_add_dev(sc, target, lun)
1791	struct siop_softc *sc;
1792	int target;
1793	int lun;
1794{
1795	struct siop_lunsw *lunsw;
1796	struct siop_lun *siop_lun = sc->targets[target]->siop_lun[lun];
1797	int i, ntargets;
1798
1799	if (siop_lun->reseloff > 0)
1800		return;
1801	lunsw = sc->targets[target]->lunsw;
1802	if ((lunsw->lunsw_off + lunsw->lunsw_size) < sc->script_free_lo) {
1803		/*
1804		 * can't extend this slot. Probably not worth trying to deal
1805		 * with this case
1806		 */
1807#ifdef DEBUG
1808		printf("%s:%d:%d: can't allocate a lun sw slot\n",
1809		    sc->sc_dev.dv_xname, target, lun);
1810#endif
1811		return;
1812	}
1813	/* count how many free targets we still have to probe */
1814	ntargets =  sc->sc_link.scsipi_scsi.max_target - 1 - sc->sc_ntargets;
1815
1816	/*
1817	 * we need 8 bytes for the lun sw additionnal entry, and
1818	 * eventually sizeof(tag_switch) for the tag switch entry.
1819	 * Keep enouth free space for the free targets that could be
1820	 * probed later.
1821	 */
1822	if (sc->script_free_lo + 2 +
1823	    (ntargets * sizeof(lun_switch) / sizeof(lun_switch[0])) >=
1824	    ((sc->targets[target]->flags & TARF_TAG) ?
1825	    sc->script_free_hi - (sizeof(tag_switch) / sizeof(tag_switch[0])) :
1826	    sc->script_free_hi)) {
1827		/*
1828		 * not enouth space, probably not worth dealing with it.
1829		 * We can hold 13 tagged-queuing capable devices in the 4k RAM.
1830		 */
1831#ifdef DEBUG
1832		printf("%s:%d:%d: not enouth memory for a lun sw slot\n",
1833		    sc->sc_dev.dv_xname, target, lun);
1834#endif
1835		return;
1836	}
1837#ifdef SIOP_DEBUG
1838	printf("%s:%d:%d: allocate lun sw entry\n",
1839	    sc->sc_dev.dv_xname, target, lun);
1840#endif
1841	/* INT int_resellun */
1842	siop_script_write(sc, sc->script_free_lo, 0x98080000);
1843	siop_script_write(sc, sc->script_free_lo + 1, A_int_resellun);
1844	/* Now the slot entry: JUMP abs_foo, IF lun */
1845	siop_script_write(sc, sc->script_free_lo - 2,
1846	    0x800c0000 | lun);
1847	siop_script_write(sc, sc->script_free_lo - 1, 0);
1848	siop_lun->reseloff = sc->script_free_lo - 2;
1849	lunsw->lunsw_size += 2;
1850	sc->script_free_lo += 2;
1851	if (sc->targets[target]->flags & TARF_TAG) {
1852		/* we need a tag switch */
1853		sc->script_free_hi -=
1854		    sizeof(tag_switch) / sizeof(tag_switch[0]);
1855		if (sc->features & SF_CHIP_RAM) {
1856			bus_space_write_region_4(sc->sc_ramt, sc->sc_ramh,
1857			    sc->script_free_hi * 4, tag_switch,
1858			    sizeof(tag_switch) / sizeof(tag_switch[0]));
1859		} else {
1860			for(i = 0;
1861			    i < sizeof(tag_switch) / sizeof(tag_switch[0]);
1862			    i++) {
1863				sc->sc_script[sc->script_free_hi + i] =
1864				    htole32(tag_switch[i]);
1865			}
1866		}
1867		siop_script_write(sc,
1868		    siop_lun->reseloff + 1,
1869		    sc->sc_scriptaddr + sc->script_free_hi * 4 +
1870		    Ent_tag_switch_entry);
1871
1872		for (i = 0; i < SIOP_NTAG; i++) {
1873			siop_lun->siop_tag[i].reseloff =
1874			    sc->script_free_hi + (Ent_resel_tag0 / 4) + i * 2;
1875		}
1876	} else {
1877		/* non-tag case; just work with the lun switch */
1878		siop_lun->siop_tag[0].reseloff =
1879		    sc->targets[target]->siop_lun[lun]->reseloff;
1880	}
1881	siop_script_sync(sc, BUS_DMASYNC_PREWRITE);
1882}
1883
1884void
1885siop_del_dev(sc, target, lun)
1886	struct siop_softc *sc;
1887	int target;
1888	int lun;
1889{
1890	int i;
1891#ifdef SIOP_DEBUG
1892		printf("%s:%d:%d: free lun sw entry\n",
1893		    sc->sc_dev.dv_xname, target, lun);
1894#endif
1895	if (sc->targets[target] == NULL)
1896		return;
1897	free(sc->targets[target]->siop_lun[lun], M_DEVBUF);
1898	sc->targets[target]->siop_lun[lun] = NULL;
1899	/* XXX compact sw entry too ? */
1900	/* check if we can free the whole target */
1901	for (i = 0; i < 8; i++) {
1902		if (sc->targets[target]->siop_lun[i] != NULL)
1903			return;
1904	}
1905#ifdef SIOP_DEBUG
1906	printf("%s: free siop_target for target %d lun %d lunsw offset %d\n",
1907	    sc->sc_dev.dv_xname, target, lun,
1908	    sc->targets[target]->lunsw->lunsw_off);
1909#endif
1910	/*
1911	 * nothing here, free the target struct and resel
1912	 * switch entry
1913	 */
1914	siop_script_write(sc, sc->targets[target]->reseloff, 0x800c00ff);
1915	siop_script_sync(sc, BUS_DMASYNC_PREWRITE);
1916	TAILQ_INSERT_TAIL(&sc->lunsw_list, sc->targets[target]->lunsw, next);
1917	free(sc->targets[target], M_DEVBUF);
1918	sc->targets[target] = NULL;
1919	sc->sc_ntargets--;
1920}
1921
1922#ifdef SIOP_STATS
1923void
1924siop_printstats()
1925{
1926	printf("siop_stat_intr %d\n", siop_stat_intr);
1927	printf("siop_stat_intr_shortxfer %d\n", siop_stat_intr_shortxfer);
1928	printf("siop_stat_intr_xferdisc %d\n", siop_stat_intr_xferdisc);
1929	printf("siop_stat_intr_sdp %d\n", siop_stat_intr_sdp);
1930	printf("siop_stat_intr_done %d\n", siop_stat_intr_done);
1931	printf("siop_stat_intr_lunresel %d\n", siop_stat_intr_lunresel);
1932}
1933#endif
1934