ncr53c9x.c revision 145386
1130293Sscottl/*-
2130293Sscottl * Copyright (c) 2004 Scott Long
3130293Sscottl * All rights reserved.
4130293Sscottl *
5130293Sscottl * Redistribution and use in source and binary forms, with or without
6130293Sscottl * modification, are permitted provided that the following conditions
7130293Sscottl * are met:
8130293Sscottl * 1. Redistributions of source code must retain the above copyright
9130293Sscottl *    notice, this list of conditions and the following disclaimer.
10130293Sscottl * 2. Redistributions in binary form must reproduce the above copyright
11130293Sscottl *    notice, this list of conditions and the following disclaimer in the
12130293Sscottl *    documentation and/or other materials provided with the distribution.
13130293Sscottl *
14130293Sscottl * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15130293Sscottl * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16130293Sscottl * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17130293Sscottl * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18130293Sscottl * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19130293Sscottl * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20130293Sscottl * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21130293Sscottl * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22130293Sscottl * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23130293Sscottl * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24130293Sscottl * SUCH DAMAGE.
25130293Sscottl *
26130293Sscottl */
27130293Sscottl
28145202Smarius/*	$NetBSD: ncr53c9x.c,v 1.110 2003/11/02 11:07:45 wiz Exp $	*/
29130293Sscottl
30130293Sscottl/*-
31130293Sscottl * Copyright (c) 1998, 2002 The NetBSD Foundation, Inc.
32130293Sscottl * All rights reserved.
33130293Sscottl *
34130293Sscottl * This code is derived from software contributed to The NetBSD Foundation
35130293Sscottl * by Charles M. Hannum.
36130293Sscottl *
37130293Sscottl * Redistribution and use in source and binary forms, with or without
38130293Sscottl * modification, are permitted provided that the following conditions
39130293Sscottl * are met:
40130293Sscottl * 1. Redistributions of source code must retain the above copyright
41130293Sscottl *    notice, this list of conditions and the following disclaimer.
42130293Sscottl * 2. Redistributions in binary form must reproduce the above copyright
43130293Sscottl *    notice, this list of conditions and the following disclaimer in the
44130293Sscottl *    documentation and/or other materials provided with the distribution.
45130293Sscottl * 3. All advertising materials mentioning features or use of this software
46130293Sscottl *    must display the following acknowledgement:
47130293Sscottl *        This product includes software developed by the NetBSD
48130293Sscottl *        Foundation, Inc. and its contributors.
49130293Sscottl * 4. Neither the name of The NetBSD Foundation nor the names of its
50130293Sscottl *    contributors may be used to endorse or promote products derived
51130293Sscottl *    from this software without specific prior written permission.
52130293Sscottl *
53130293Sscottl * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
54130293Sscottl * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
55130293Sscottl * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
56130293Sscottl * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
57130293Sscottl * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
58130293Sscottl * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
59130293Sscottl * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
60130293Sscottl * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
61130293Sscottl * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
62130293Sscottl * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
63130293Sscottl * POSSIBILITY OF SUCH DAMAGE.
64130293Sscottl */
65130293Sscottl
66139749Simp/*-
67130293Sscottl * Copyright (c) 1994 Peter Galbavy
68130293Sscottl * Copyright (c) 1995 Paul Kranenburg
69130293Sscottl * All rights reserved.
70130293Sscottl *
71130293Sscottl * Redistribution and use in source and binary forms, with or without
72130293Sscottl * modification, are permitted provided that the following conditions
73130293Sscottl * are met:
74130293Sscottl * 1. Redistributions of source code must retain the above copyright
75130293Sscottl *    notice, this list of conditions and the following disclaimer.
76130293Sscottl * 2. Redistributions in binary form must reproduce the above copyright
77130293Sscottl *    notice, this list of conditions and the following disclaimer in the
78130293Sscottl *    documentation and/or other materials provided with the distribution.
79130293Sscottl * 3. All advertising materials mentioning features or use of this software
80130293Sscottl *    must display the following acknowledgement:
81130293Sscottl *	This product includes software developed by Peter Galbavy
82130293Sscottl * 4. The name of the author may not be used to endorse or promote products
83130293Sscottl *    derived from this software without specific prior written permission.
84130293Sscottl *
85130293Sscottl * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
86130293Sscottl * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
87130293Sscottl * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
88130293Sscottl * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
89130293Sscottl * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
90130293Sscottl * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
91130293Sscottl * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
92130293Sscottl * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
93130293Sscottl * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
94130293Sscottl * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
95130293Sscottl * POSSIBILITY OF SUCH DAMAGE.
96130293Sscottl */
97130293Sscottl
98130293Sscottl/*
99130293Sscottl * Based on aic6360 by Jarle Greipsland
100130293Sscottl *
101130293Sscottl * Acknowledgements: Many of the algorithms used in this driver are
102133039Strhodes * inspired by the work of Julian Elischer (julian@FreeBSD.org) and
103130293Sscottl * Charles Hannum (mycroft@duality.gnu.ai.mit.edu).  Thanks a million!
104130293Sscottl */
105130293Sscottl
106130293Sscottl#include <sys/cdefs.h>
107130293Sscottl__FBSDID("$FreeBSD: head/sys/dev/esp/ncr53c9x.c 145386 2005-04-22 03:37:10Z scottl $");
108130293Sscottl
109130293Sscottl#include <sys/param.h>
110130293Sscottl#include <sys/systm.h>
111130293Sscottl#include <sys/bus.h>
112130293Sscottl#include <sys/kernel.h>
113130293Sscottl#include <sys/malloc.h>
114130293Sscottl#include <sys/resource.h>
115130293Sscottl#include <sys/lock.h>
116130293Sscottl#include <sys/mutex.h>
117130293Sscottl#include <sys/queue.h>
118130293Sscottl#include <sys/time.h>
119130293Sscottl#include <sys/callout.h>
120130293Sscottl
121130293Sscottl#include <cam/cam.h>
122130293Sscottl#include <cam/cam_ccb.h>
123130293Sscottl#include <cam/cam_debug.h>
124130293Sscottl#include <cam/cam_sim.h>
125130293Sscottl#include <cam/cam_xpt_sim.h>
126130293Sscottl#include <cam/scsi/scsi_all.h>
127130293Sscottl#include <cam/scsi/scsi_message.h>
128130293Sscottl
129130293Sscottl#include <dev/esp/ncr53c9xreg.h>
130130293Sscottl#include <dev/esp/ncr53c9xvar.h>
131130293Sscottl
132130293Sscottlint ncr53c9x_debug = NCR_SHOWMISC /*|NCR_SHOWPHASE|NCR_SHOWTRAC|NCR_SHOWCMDS*/;
133130293Sscottl#ifdef DEBUG
134130293Sscottlint ncr53c9x_notag = 0;
135130293Sscottl#endif
136130293Sscottl
137130293Sscottlstatic void	ncr53c9x_select(struct ncr53c9x_softc *, struct ncr53c9x_ecb *);
138130293Sscottlstatic int	ncr53c9x_reselect(struct ncr53c9x_softc *, int, int, int);
139130293Sscottlstatic void	ncr53c9x_scsi_reset(struct ncr53c9x_softc *);
140130293Sscottlstatic void	ncr53c9x_poll(struct cam_sim *);
141130293Sscottlstatic void	ncr53c9x_sched(struct ncr53c9x_softc *);
142130293Sscottlstatic void	ncr53c9x_done(struct ncr53c9x_softc *, struct ncr53c9x_ecb *);
143130293Sscottlstatic void	ncr53c9x_msgin(struct ncr53c9x_softc *);
144130293Sscottlstatic void	ncr53c9x_msgout(struct ncr53c9x_softc *);
145130293Sscottlstatic void	ncr53c9x_timeout(void *arg);
146130293Sscottlstatic void	ncr53c9x_watch(void *arg);
147130293Sscottlstatic void	ncr53c9x_abort(struct ncr53c9x_softc *, struct ncr53c9x_ecb *);
148130293Sscottlstatic void	ncr53c9x_dequeue(struct ncr53c9x_softc *,
149130293Sscottl				struct ncr53c9x_ecb *);
150130293Sscottlstatic void	ncr53c9x_sense(struct ncr53c9x_softc *, struct ncr53c9x_ecb *);
151130293Sscottlstatic void	ncr53c9x_free_ecb(struct ncr53c9x_softc *,
152130293Sscottl				  struct ncr53c9x_ecb *);
153130293Sscottlstatic void	ncr53c9x_wrfifo(struct ncr53c9x_softc *, u_char *, int);
154130293Sscottlstatic int	ncr53c9x_rdfifo(struct ncr53c9x_softc *, int);
155130293Sscottl
156130293Sscottlstatic struct ncr53c9x_ecb *ncr53c9x_get_ecb(struct ncr53c9x_softc *);
157130293Sscottlstatic struct ncr53c9x_linfo *ncr53c9x_lunsearch(struct ncr53c9x_tinfo *,
158130293Sscottl						 int64_t lun);
159130293Sscottl
160130293Sscottlstatic __inline void ncr53c9x_readregs(struct ncr53c9x_softc *);
161130293Sscottlstatic __inline int ncr53c9x_stp2cpb(struct ncr53c9x_softc *, int);
162130293Sscottlstatic __inline void ncr53c9x_setsync(struct ncr53c9x_softc *,
163130293Sscottl				      struct ncr53c9x_tinfo *);
164130293Sscottl
165130293Sscottl#define NCR_RDFIFO_START   0
166130293Sscottl#define NCR_RDFIFO_CONTINUE 1
167130293Sscottl
168130293Sscottl#define NCR_SET_COUNT(sc, size) do { \
169130293Sscottl		NCR_WRITE_REG((sc), NCR_TCL, (size)); 			\
170130293Sscottl		NCR_WRITE_REG((sc), NCR_TCM, (size) >> 8);		\
171130293Sscottl		if ((sc->sc_cfg2 & NCRCFG2_FE) || 			\
172130293Sscottl		    (sc->sc_rev == NCR_VARIANT_FAS366)) {		\
173130293Sscottl			NCR_WRITE_REG((sc), NCR_TCH, (size) >> 16);	\
174130293Sscottl		}							\
175130293Sscottl		if (sc->sc_rev == NCR_VARIANT_FAS366) {			\
176130293Sscottl			NCR_WRITE_REG(sc, NCR_RCH, 0);			\
177130293Sscottl		}							\
178130293Sscottl} while (0)
179130293Sscottl
180130293Sscottl#ifndef mstohz
181130293Sscottl#define mstohz(ms) \
182130293Sscottl	(((ms) < 0x20000)  ? \
183130293Sscottl	    ((ms +0u) / 1000u) * hz : \
184130293Sscottl	    ((ms +0u) * hz) /1000u)
185130293Sscottl#endif
186130293Sscottl
187130293Sscottl/*
188145202Smarius * Names for the NCR53c9x variants, corresponding to the variant tags
189130293Sscottl * in ncr53c9xvar.h.
190130293Sscottl */
191130293Sscottlstatic const char *ncr53c9x_variant_names[] = {
192130293Sscottl	"ESP100",
193130293Sscottl	"ESP100A",
194130293Sscottl	"ESP200",
195130293Sscottl	"NCR53C94",
196130293Sscottl	"NCR53C96",
197130293Sscottl	"ESP406",
198130293Sscottl	"FAS408",
199130293Sscottl	"FAS216",
200130293Sscottl	"AM53C974",
201130293Sscottl	"FAS366/HME",
202130293Sscottl	"NCR53C90 (86C01)",
203130293Sscottl};
204130293Sscottl
205130293Sscottl/*
206130293Sscottl * Search linked list for LUN info by LUN id.
207130293Sscottl */
208130293Sscottlstatic struct ncr53c9x_linfo *
209130293Sscottlncr53c9x_lunsearch(struct ncr53c9x_tinfo *ti, int64_t lun)
210130293Sscottl{
211130293Sscottl	struct ncr53c9x_linfo *li;
212130293Sscottl	LIST_FOREACH(li, &ti->luns, link)
213130293Sscottl		if (li->lun == lun)
214130293Sscottl			return (li);
215130293Sscottl	return (NULL);
216130293Sscottl}
217130293Sscottl
218130293Sscottl/*
219133039Strhodes * Attach this instance, and then all the sub-devices.
220130293Sscottl */
221130293Sscottlint
222130293Sscottlncr53c9x_attach(struct ncr53c9x_softc *sc)
223130293Sscottl{
224130293Sscottl	struct cam_devq *devq;
225130293Sscottl	struct cam_sim *sim;
226130293Sscottl	struct cam_path *path;
227130406Sscottl	struct ncr53c9x_ecb *ecb;
228130406Sscottl	int i;
229130293Sscottl
230130293Sscottl	mtx_init(&sc->sc_lock, "ncr", "ncr53c9x lock", MTX_DEF);
231130293Sscottl
232130293Sscottl	/*
233130293Sscottl	 * Note, the front-end has set us up to print the chip variation.
234130293Sscottl	 */
235130293Sscottl	if (sc->sc_rev >= NCR_VARIANT_MAX) {
236130293Sscottl		device_printf(sc->sc_dev, "unknown variant %d, devices not "
237130293Sscottl		    "attached\n", sc->sc_rev);
238130293Sscottl		return (EINVAL);
239130293Sscottl	}
240130293Sscottl
241130293Sscottl	device_printf(sc->sc_dev, "%s, %dMHz, SCSI ID %d\n",
242130293Sscottl	    ncr53c9x_variant_names[sc->sc_rev], sc->sc_freq, sc->sc_id);
243130293Sscottl
244130293Sscottl	sc->sc_ntarg = (sc->sc_rev == NCR_VARIANT_FAS366) ? 16 : 8;
245130293Sscottl
246130293Sscottl	/*
247130293Sscottl	 * Allocate SCSI message buffers.
248130293Sscottl	 * Front-ends can override allocation to avoid alignment
249130293Sscottl	 * handling in the DMA engines. Note that that ncr53c9x_msgout()
250130293Sscottl	 * can request a 1 byte DMA transfer.
251130293Sscottl	 */
252130293Sscottl	if (sc->sc_omess == NULL)
253130293Sscottl		sc->sc_omess = malloc(NCR_MAX_MSG_LEN, M_DEVBUF, M_NOWAIT);
254130293Sscottl
255130293Sscottl	if (sc->sc_imess == NULL)
256130293Sscottl		sc->sc_imess = malloc(NCR_MAX_MSG_LEN + 1, M_DEVBUF, M_NOWAIT);
257130293Sscottl
258130293Sscottl	sc->sc_tinfo = malloc(sc->sc_ntarg * sizeof(sc->sc_tinfo[0]),
259130293Sscottl	    M_DEVBUF, M_NOWAIT | M_ZERO);
260130293Sscottl
261130293Sscottl	if (!sc->sc_omess || !sc->sc_imess || !sc->sc_tinfo) {
262130293Sscottl		printf("out of memory\n");
263130293Sscottl		return (ENOMEM);
264130293Sscottl	}
265130293Sscottl
266130293Sscottl	callout_init(&sc->sc_watchdog, 0);
267130293Sscottl
268130293Sscottl	/*
269130293Sscottl	 * Treat NCR53C90 with the 86C01 DMA chip exactly as ESP100
270130293Sscottl	 * from now on.
271130293Sscottl	 */
272130293Sscottl	if (sc->sc_rev == NCR_VARIANT_NCR53C90_86C01)
273130293Sscottl		sc->sc_rev = NCR_VARIANT_ESP100;
274130293Sscottl
275130293Sscottl	sc->sc_ccf = FREQTOCCF(sc->sc_freq);
276130293Sscottl
277130293Sscottl	/* The value *must not* be == 1. Make it 2 */
278130293Sscottl	if (sc->sc_ccf == 1)
279130293Sscottl		sc->sc_ccf = 2;
280130293Sscottl
281130293Sscottl	/*
282130293Sscottl	 * The recommended timeout is 250ms. This register is loaded
283130293Sscottl	 * with a value calculated as follows, from the docs:
284130293Sscottl	 *
285130293Sscottl	 *		(timout period) x (CLK frequency)
286130293Sscottl	 *	reg = -------------------------------------
287130293Sscottl	 *		 8192 x (Clock Conversion Factor)
288130293Sscottl	 *
289130293Sscottl	 * Since CCF has a linear relation to CLK, this generally computes
290130293Sscottl	 * to the constant of 153.
291130293Sscottl	 */
292130293Sscottl	sc->sc_timeout = ((250 * 1000) * sc->sc_freq) / (8192 * sc->sc_ccf);
293130293Sscottl
294130293Sscottl	/* CCF register only has 3 bits; 0 is actually 8 */
295130293Sscottl	sc->sc_ccf &= 7;
296130293Sscottl
297130293Sscottl	/*
298130293Sscottl	 * Register with CAM
299130293Sscottl	 */
300130293Sscottl	devq = cam_simq_alloc(sc->sc_ntarg);
301130293Sscottl	if (devq == NULL)
302130293Sscottl		return (ENOMEM);
303130293Sscottl
304130293Sscottl	sim = cam_sim_alloc(ncr53c9x_action, ncr53c9x_poll, "esp", sc,
305130406Sscottl			    device_get_unit(sc->sc_dev), 1,
306130406Sscottl			    NCR_TAG_DEPTH, devq);
307130293Sscottl	if (sim == NULL) {
308130293Sscottl		cam_simq_free(devq);
309130293Sscottl		return (ENOMEM);
310130293Sscottl	}
311130293Sscottl	if (xpt_bus_register(sim, 0) != CAM_SUCCESS) {
312130293Sscottl		cam_sim_free(sim, TRUE);
313130293Sscottl		return (EIO);
314130293Sscottl	}
315130293Sscottl
316130293Sscottl	if (xpt_create_path(&path, NULL, cam_sim_path(sim),
317130293Sscottl			    CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD)
318130293Sscottl			    != CAM_REQ_CMP) {
319130293Sscottl		xpt_bus_deregister(cam_sim_path(sim));
320130293Sscottl		cam_sim_free(sim, TRUE);
321130293Sscottl		return (EIO);
322130293Sscottl	}
323130293Sscottl
324130293Sscottl	sc->sc_sim = sim;
325130293Sscottl	sc->sc_path = path;
326130293Sscottl
327130293Sscottl	/* Reset state & bus */
328130293Sscottl#if 0
329130293Sscottl	sc->sc_cfflags = sc->sc_dev.dv_cfdata->cf_flags;
330130293Sscottl#endif
331130293Sscottl	sc->sc_state = 0;
332130293Sscottl	ncr53c9x_init(sc, 1);
333130293Sscottl
334130406Sscottl	TAILQ_INIT(&sc->free_list);
335130406Sscottl	if ((sc->ecb_array = malloc(sizeof(struct ncr53c9x_ecb) * NCR_TAG_DEPTH,
336130406Sscottl				    M_DEVBUF, M_NOWAIT|M_ZERO)) == NULL) {
337145202Smarius		device_printf(sc->sc_dev, "cannot allocate ECB array\n");
338130406Sscottl		return (ENOMEM);
339130406Sscottl	}
340130406Sscottl	for (i = 0; i < NCR_TAG_DEPTH; i++) {
341130406Sscottl		ecb = &sc->ecb_array[i];
342130406Sscottl		ecb->sc = sc;
343130406Sscottl		ecb->tag_id = i;
344130406Sscottl		TAILQ_INSERT_HEAD(&sc->free_list, ecb, free_links);
345130406Sscottl	}
346130406Sscottl
347130293Sscottl	callout_reset(&sc->sc_watchdog, 60*hz, ncr53c9x_watch, sc);
348130293Sscottl
349130293Sscottl	return (0);
350130293Sscottl}
351130293Sscottl
352130293Sscottlint
353130293Sscottlncr53c9x_detach(struct ncr53c9x_softc *sc, int flags)
354130293Sscottl{
355130293Sscottl
356130293Sscottl#if 0	/* don't allow detach for now */
357130293Sscottl	free(sc->sc_imess, M_DEVBUF);
358130293Sscottl	free(sc->sc_omess, M_DEVBUF);
359130293Sscottl#endif
360130293Sscottl
361130293Sscottl	return (EINVAL);
362130293Sscottl}
363130293Sscottl
364130293Sscottl/*
365130293Sscottl * This is the generic ncr53c9x reset function. It does not reset the SCSI bus,
366130293Sscottl * only this controller, but kills any on-going commands, and also stops
367130293Sscottl * and resets the DMA.
368130293Sscottl *
369130293Sscottl * After reset, registers are loaded with the defaults from the attach
370130293Sscottl * routine above.
371130293Sscottl */
372130293Sscottlvoid
373130293Sscottlncr53c9x_reset(struct ncr53c9x_softc *sc)
374130293Sscottl{
375130293Sscottl
376130293Sscottl	/* reset DMA first */
377130293Sscottl	NCRDMA_RESET(sc);
378130293Sscottl
379130293Sscottl	/* reset SCSI chip */
380130293Sscottl	NCRCMD(sc, NCRCMD_RSTCHIP);
381130293Sscottl	NCRCMD(sc, NCRCMD_NOP);
382130293Sscottl	DELAY(500);
383130293Sscottl
384130293Sscottl	/* do these backwards, and fall through */
385130293Sscottl	switch (sc->sc_rev) {
386130293Sscottl	case NCR_VARIANT_ESP406:
387130293Sscottl	case NCR_VARIANT_FAS408:
388130293Sscottl		NCR_WRITE_REG(sc, NCR_CFG5, sc->sc_cfg5 | NCRCFG5_SINT);
389130293Sscottl		NCR_WRITE_REG(sc, NCR_CFG4, sc->sc_cfg4);
390130293Sscottl	case NCR_VARIANT_AM53C974:
391130293Sscottl	case NCR_VARIANT_FAS216:
392130293Sscottl	case NCR_VARIANT_NCR53C94:
393130293Sscottl	case NCR_VARIANT_NCR53C96:
394130293Sscottl	case NCR_VARIANT_ESP200:
395130293Sscottl		sc->sc_features |= NCR_F_HASCFG3;
396130293Sscottl		NCR_WRITE_REG(sc, NCR_CFG3, sc->sc_cfg3);
397130293Sscottl	case NCR_VARIANT_ESP100A:
398130293Sscottl		sc->sc_features |= NCR_F_SELATN3;
399130293Sscottl		NCR_WRITE_REG(sc, NCR_CFG2, sc->sc_cfg2);
400130293Sscottl	case NCR_VARIANT_ESP100:
401130293Sscottl		NCR_WRITE_REG(sc, NCR_CFG1, sc->sc_cfg1);
402130293Sscottl		NCR_WRITE_REG(sc, NCR_CCF, sc->sc_ccf);
403130293Sscottl		NCR_WRITE_REG(sc, NCR_SYNCOFF, 0);
404130293Sscottl		NCR_WRITE_REG(sc, NCR_TIMEOUT, sc->sc_timeout);
405130293Sscottl		break;
406130293Sscottl
407130293Sscottl	case NCR_VARIANT_FAS366:
408130293Sscottl		sc->sc_features |=
409130293Sscottl		    NCR_F_HASCFG3 | NCR_F_FASTSCSI | NCR_F_SELATN3;
410130293Sscottl		sc->sc_cfg3 = NCRFASCFG3_FASTCLK | NCRFASCFG3_OBAUTO;
411130293Sscottl		sc->sc_cfg3_fscsi = NCRFASCFG3_FASTSCSI;
412130293Sscottl		NCR_WRITE_REG(sc, NCR_CFG3, sc->sc_cfg3);
413130293Sscottl		sc->sc_cfg2 = 0; /* NCRCFG2_HMEFE| NCRCFG2_HME32 */
414130293Sscottl		NCR_WRITE_REG(sc, NCR_CFG2, sc->sc_cfg2);
415130293Sscottl		NCR_WRITE_REG(sc, NCR_CFG1, sc->sc_cfg1);
416130293Sscottl		NCR_WRITE_REG(sc, NCR_CCF, sc->sc_ccf);
417130293Sscottl		NCR_WRITE_REG(sc, NCR_SYNCOFF, 0);
418130293Sscottl		NCR_WRITE_REG(sc, NCR_TIMEOUT, sc->sc_timeout);
419130293Sscottl		break;
420130293Sscottl
421130293Sscottl	default:
422130293Sscottl		device_printf(sc->sc_dev, "unknown revision code, "
423130293Sscottl			      "assuming ESP100\n");
424130293Sscottl		NCR_WRITE_REG(sc, NCR_CFG1, sc->sc_cfg1);
425130293Sscottl		NCR_WRITE_REG(sc, NCR_CCF, sc->sc_ccf);
426130293Sscottl		NCR_WRITE_REG(sc, NCR_SYNCOFF, 0);
427130293Sscottl		NCR_WRITE_REG(sc, NCR_TIMEOUT, sc->sc_timeout);
428130293Sscottl	}
429130293Sscottl
430130293Sscottl	if (sc->sc_rev == NCR_VARIANT_AM53C974)
431130293Sscottl		NCR_WRITE_REG(sc, NCR_AMDCFG4, sc->sc_cfg4);
432130293Sscottl
433130293Sscottl#if 0
434130293Sscottl	device_printf(sc->sc_dev, "ncr53c9x_reset: revision %d\n",
435130293Sscottl	       sc->sc_rev);
436130293Sscottl	device_printf(sc->sc_dev, "ncr53c9x_reset: cfg1 0x%x, cfg2 0x%x, "
437130293Sscottl	    "cfg3 0x%x, ccf 0x%x, timeout 0x%x\n",
438130293Sscottl	    sc->sc_cfg1, sc->sc_cfg2, sc->sc_cfg3, sc->sc_ccf, sc->sc_timeout);
439130293Sscottl#endif
440130293Sscottl}
441130293Sscottl
442130293Sscottl/*
443130293Sscottl * Reset the SCSI bus, but not the chip
444130293Sscottl */
445130293Sscottlstatic void
446130293Sscottlncr53c9x_scsi_reset(struct ncr53c9x_softc *sc)
447130293Sscottl{
448130293Sscottl
449130293Sscottl	(*sc->sc_glue->gl_dma_stop)(sc);
450130293Sscottl
451130293Sscottl	NCR_MISC(("%s: resetting SCSI bus\n", device_get_nameunit(sc->sc_dev)));
452130293Sscottl	NCRCMD(sc, NCRCMD_RSTSCSI);
453130293Sscottl	DELAY(250000);		/* Give the bus a fighting chance to settle */
454130293Sscottl}
455130293Sscottl
456130293Sscottl/*
457130293Sscottl * Initialize ncr53c9x state machine
458130293Sscottl */
459130293Sscottlvoid
460130293Sscottlncr53c9x_init(struct ncr53c9x_softc *sc, int doreset)
461130293Sscottl{
462130293Sscottl	struct ncr53c9x_ecb *ecb;
463130293Sscottl	struct ncr53c9x_linfo *li;
464130293Sscottl	int i, r;
465130293Sscottl
466130293Sscottl	NCR_MISC(("[NCR_INIT(%d) %d] ", doreset, sc->sc_state));
467130293Sscottl
468130293Sscottl	if (sc->sc_state == 0) {
469130293Sscottl		/* First time through; initialize. */
470130293Sscottl
471130293Sscottl		TAILQ_INIT(&sc->ready_list);
472130293Sscottl		sc->sc_nexus = NULL;
473130293Sscottl		memset(sc->sc_tinfo, 0, sizeof(sc->sc_tinfo));
474130293Sscottl		for (r = 0; r < sc->sc_ntarg; r++) {
475130293Sscottl			LIST_INIT(&sc->sc_tinfo[r].luns);
476130293Sscottl		}
477130293Sscottl	} else {
478130293Sscottl		/* Cancel any active commands. */
479130293Sscottl		sc->sc_state = NCR_CLEANING;
480130293Sscottl		sc->sc_msgify = 0;
481130293Sscottl		if ((ecb = sc->sc_nexus) != NULL) {
482130293Sscottl			ecb->ccb->ccb_h.status = CAM_CMD_TIMEOUT;
483130293Sscottl			ncr53c9x_done(sc, ecb);
484130293Sscottl		}
485130293Sscottl		/* Cancel outstanding disconnected commands on each LUN */
486130293Sscottl		for (r = 0; r < sc->sc_ntarg; r++) {
487130293Sscottl			LIST_FOREACH(li, &sc->sc_tinfo[r].luns, link) {
488130293Sscottl				if ((ecb = li->untagged) != NULL) {
489130293Sscottl					li->untagged = NULL;
490130293Sscottl					/*
491130293Sscottl					 * XXXXXXX
492130293Sscottl					 *
493130293Sscottl					 * Should we terminate a command
494130293Sscottl					 * that never reached the disk?
495130293Sscottl					 */
496130293Sscottl					li->busy = 0;
497130293Sscottl					ecb->ccb->ccb_h.status =
498130293Sscottl					    CAM_CMD_TIMEOUT;
499130293Sscottl					ncr53c9x_done(sc, ecb);
500130293Sscottl				}
501130293Sscottl				for (i = 0; i < 256; i++)
502130293Sscottl					if ((ecb = li->queued[i])) {
503130293Sscottl						li->queued[i] = NULL;
504130293Sscottl						ecb->ccb->ccb_h.status =
505130293Sscottl						    CAM_CMD_TIMEOUT;
506130293Sscottl						ncr53c9x_done(sc, ecb);
507130293Sscottl					}
508130293Sscottl				li->used = 0;
509130293Sscottl			}
510130293Sscottl		}
511130293Sscottl	}
512130293Sscottl
513130293Sscottl	/*
514130293Sscottl	 * reset the chip to a known state
515130293Sscottl	 */
516130293Sscottl	ncr53c9x_reset(sc);
517130293Sscottl
518130293Sscottl	sc->sc_phase = sc->sc_prevphase = INVALID_PHASE;
519130293Sscottl	for (r = 0; r < sc->sc_ntarg; r++) {
520130293Sscottl		struct ncr53c9x_tinfo *ti = &sc->sc_tinfo[r];
521130293Sscottl/* XXX - config flags per target: low bits: no reselect; high bits: no synch */
522130293Sscottl
523130293Sscottl		ti->flags = ((sc->sc_minsync && !(sc->sc_cfflags & (1<<((r&7)+8))))
524130293Sscottl		    ? 0 : T_SYNCHOFF) |
525130293Sscottl		    ((sc->sc_cfflags & (1<<(r&7))) ? T_RSELECTOFF : 0);
526130293Sscottl#ifdef DEBUG
527130293Sscottl		if (ncr53c9x_notag)
528130293Sscottl			ti->flags &= ~T_TAG;
529130293Sscottl#endif
530130293Sscottl		ti->period = sc->sc_minsync;
531130293Sscottl		ti->offset = 0;
532130293Sscottl		ti->cfg3   = 0;
533130293Sscottl	}
534130293Sscottl
535130293Sscottl	if (doreset) {
536130293Sscottl		sc->sc_state = NCR_SBR;
537130293Sscottl		NCRCMD(sc, NCRCMD_RSTSCSI);
538130293Sscottl	} else {
539130293Sscottl		sc->sc_state = NCR_IDLE;
540130293Sscottl		ncr53c9x_sched(sc);
541130293Sscottl	}
542130293Sscottl}
543130293Sscottl
544130293Sscottl/*
545130293Sscottl * Read the NCR registers, and save their contents for later use.
546130293Sscottl * NCR_STAT, NCR_STEP & NCR_INTR are mostly zeroed out when reading
547130293Sscottl * NCR_INTR - so make sure it is the last read.
548130293Sscottl *
549130293Sscottl * I think that (from reading the docs) most bits in these registers
550130293Sscottl * only make sense when he DMA CSR has an interrupt showing. Call only
551130293Sscottl * if an interrupt is pending.
552130293Sscottl */
553130293Sscottlstatic __inline void
554130293Sscottlncr53c9x_readregs(struct ncr53c9x_softc *sc)
555130293Sscottl{
556130293Sscottl
557130293Sscottl	sc->sc_espstat = NCR_READ_REG(sc, NCR_STAT);
558130293Sscottl	/* Only the stepo bits are of interest */
559130293Sscottl	sc->sc_espstep = NCR_READ_REG(sc, NCR_STEP) & NCRSTEP_MASK;
560130293Sscottl
561145202Smarius	if (sc->sc_rev == NCR_VARIANT_FAS366)
562130293Sscottl		sc->sc_espstat2 = NCR_READ_REG(sc, NCR_STAT2);
563130293Sscottl
564130293Sscottl	sc->sc_espintr = NCR_READ_REG(sc, NCR_INTR);
565130293Sscottl
566130293Sscottl	if (sc->sc_glue->gl_clear_latched_intr != NULL)
567130293Sscottl		(*sc->sc_glue->gl_clear_latched_intr)(sc);
568130293Sscottl
569130293Sscottl	/*
570130293Sscottl	 * Determine the SCSI bus phase, return either a real SCSI bus phase
571130293Sscottl	 * or some pseudo phase we use to detect certain exceptions.
572130293Sscottl	 */
573130293Sscottl
574130293Sscottl	sc->sc_phase = (sc->sc_espintr & NCRINTR_DIS) ?
575130293Sscottl	    /* Disconnected */ BUSFREE_PHASE : sc->sc_espstat & NCRSTAT_PHASE;
576130293Sscottl
577130293Sscottl	NCR_INTS(("regs[intr=%02x,stat=%02x,step=%02x,stat2=%02x] ",
578130293Sscottl	    sc->sc_espintr, sc->sc_espstat, sc->sc_espstep, sc->sc_espstat2));
579130293Sscottl}
580130293Sscottl
581130293Sscottl/*
582130293Sscottl * Convert Synchronous Transfer Period to chip register Clock Per Byte value.
583130293Sscottl */
584130293Sscottlstatic __inline int
585130293Sscottlncr53c9x_stp2cpb(struct ncr53c9x_softc *sc, int period)
586130293Sscottl{
587130293Sscottl	int v;
588130293Sscottl	v = (sc->sc_freq * period) / 250;
589130293Sscottl	if (ncr53c9x_cpb2stp(sc, v) < period)
590130293Sscottl		/* Correct round-down error */
591130293Sscottl		v++;
592130293Sscottl	return (v);
593130293Sscottl}
594130293Sscottl
595130293Sscottlstatic __inline void
596130293Sscottlncr53c9x_setsync(struct ncr53c9x_softc *sc, struct ncr53c9x_tinfo *ti)
597130293Sscottl{
598130293Sscottl	u_char syncoff, synctp;
599130293Sscottl	u_char cfg3 = sc->sc_cfg3 | ti->cfg3;
600130293Sscottl
601130293Sscottl	if (ti->flags & T_SYNCMODE) {
602130293Sscottl		syncoff = ti->offset;
603130293Sscottl		synctp = ncr53c9x_stp2cpb(sc, ti->period);
604130293Sscottl		if (sc->sc_features & NCR_F_FASTSCSI) {
605130293Sscottl			/*
606130293Sscottl			 * If the period is 200ns or less (ti->period <= 50),
607130293Sscottl			 * put the chip in Fast SCSI mode.
608130293Sscottl			 */
609130293Sscottl			if (ti->period <= 50)
610130293Sscottl				/*
611130293Sscottl				 * There are (at least) 4 variations of the
612130293Sscottl				 * configuration 3 register.  The drive attach
613130293Sscottl				 * routine sets the appropriate bit to put the
614130293Sscottl				 * chip into Fast SCSI mode so that it doesn't
615130293Sscottl				 * have to be figured out here each time.
616130293Sscottl				 */
617130293Sscottl				cfg3 |= sc->sc_cfg3_fscsi;
618130293Sscottl		}
619130293Sscottl
620130293Sscottl		/*
621130293Sscottl		 * Am53c974 requires different SYNCTP values when the
622130293Sscottl		 * FSCSI bit is off.
623130293Sscottl		 */
624130293Sscottl		if (sc->sc_rev == NCR_VARIANT_AM53C974 &&
625130293Sscottl		    (cfg3 & NCRAMDCFG3_FSCSI) == 0)
626130293Sscottl			synctp--;
627130293Sscottl	} else {
628130293Sscottl		syncoff = 0;
629130293Sscottl		synctp = 0;
630130293Sscottl	}
631130293Sscottl
632130293Sscottl	if (sc->sc_features & NCR_F_HASCFG3)
633130293Sscottl		NCR_WRITE_REG(sc, NCR_CFG3, cfg3);
634130293Sscottl
635130293Sscottl	NCR_WRITE_REG(sc, NCR_SYNCOFF, syncoff);
636130293Sscottl	NCR_WRITE_REG(sc, NCR_SYNCTP, synctp);
637130293Sscottl}
638130293Sscottl
639130293Sscottl/*
640130293Sscottl * Send a command to a target, set the driver state to NCR_SELECTING
641130293Sscottl * and let the caller take care of the rest.
642130293Sscottl *
643130293Sscottl * Keeping this as a function allows me to say that this may be done
644130293Sscottl * by DMA instead of programmed I/O soon.
645130293Sscottl */
646130293Sscottlstatic void
647130293Sscottlncr53c9x_select(struct ncr53c9x_softc *sc, struct ncr53c9x_ecb *ecb)
648130293Sscottl{
649130293Sscottl	int target = ecb->ccb->ccb_h.target_id;
650130293Sscottl	int lun = ecb->ccb->ccb_h.target_lun;
651130293Sscottl	struct ncr53c9x_tinfo *ti;
652130293Sscottl	int tiflags;
653130293Sscottl	u_char *cmd;
654130293Sscottl	int clen;
655130293Sscottl	int selatn3, selatns;
656130293Sscottl	size_t dmasize;
657130293Sscottl
658130293Sscottl	NCR_TRACE(("[ncr53c9x_select(t%d,l%d,cmd:%x,tag:%x,%x)] ",
659130293Sscottl	    target, lun, ecb->cmd.cmd.opcode, ecb->tag[0], ecb->tag[1]));
660130293Sscottl
661130293Sscottl	ti = &sc->sc_tinfo[target];
662130293Sscottl	tiflags = ti->flags;
663130293Sscottl	sc->sc_state = NCR_SELECTING;
664130293Sscottl	/*
665130293Sscottl	 * Schedule the timeout now, the first time we will go away
666130293Sscottl	 * expecting to come back due to an interrupt, because it is
667130293Sscottl	 * always possible that the interrupt may never happen.
668130293Sscottl	 */
669130293Sscottl	ecb->ccb->ccb_h.timeout_ch =
670130424Sscottl	    timeout(ncr53c9x_timeout, ecb, mstohz(ecb->timeout));
671130293Sscottl
672130293Sscottl	/*
673130293Sscottl	 * The docs say the target register is never reset, and I
674130293Sscottl	 * can't think of a better place to set it
675130293Sscottl	 */
676130293Sscottl	if (sc->sc_rev == NCR_VARIANT_FAS366) {
677130293Sscottl		NCRCMD(sc, NCRCMD_FLUSH);
678130293Sscottl		NCR_WRITE_REG(sc, NCR_SELID, target | NCR_BUSID_HME);
679130293Sscottl	} else {
680130293Sscottl		NCR_WRITE_REG(sc, NCR_SELID, target);
681130293Sscottl	}
682130293Sscottl	ncr53c9x_setsync(sc, ti);
683130293Sscottl
684130293Sscottl	if ((ecb->flags & ECB_SENSE) != 0) {
685130293Sscottl		/*
686130293Sscottl		 * For REQUEST SENSE, we should not send an IDENTIFY or
687130293Sscottl		 * otherwise mangle the target.  There should be no MESSAGE IN
688130293Sscottl		 * phase.
689130293Sscottl		 */
690130293Sscottl		if (sc->sc_features & NCR_F_DMASELECT) {
691130293Sscottl			/* setup DMA transfer for command */
692130293Sscottl			dmasize = clen = ecb->clen;
693130293Sscottl			sc->sc_cmdlen = clen;
694130293Sscottl			sc->sc_cmdp = (caddr_t)&ecb->cmd.cmd;
695130293Sscottl
696130293Sscottl			/* Program the SCSI counter */
697130293Sscottl			NCR_SET_COUNT(sc, dmasize);
698130293Sscottl
699130293Sscottl			if (sc->sc_rev != NCR_VARIANT_FAS366)
700130293Sscottl				NCRCMD(sc, NCRCMD_NOP|NCRCMD_DMA);
701130293Sscottl
702130293Sscottl			/* And get the targets attention */
703130293Sscottl			NCRCMD(sc, NCRCMD_SELNATN | NCRCMD_DMA);
704130293Sscottl			NCRDMA_SETUP(sc, &sc->sc_cmdp, &sc->sc_cmdlen, 0,
705130293Sscottl			    &dmasize);
706130293Sscottl			NCRDMA_GO(sc);
707130293Sscottl		} else {
708130293Sscottl			ncr53c9x_wrfifo(sc, (u_char *)&ecb->cmd.cmd, ecb->clen);
709130293Sscottl			NCRCMD(sc, NCRCMD_SELNATN);
710130293Sscottl		}
711130293Sscottl		return;
712130293Sscottl	}
713130293Sscottl
714130293Sscottl	selatn3 = selatns = 0;
715130293Sscottl	if (ecb->tag[0] != 0) {
716130293Sscottl		if (sc->sc_features & NCR_F_SELATN3)
717130293Sscottl			/* use SELATN3 to send tag messages */
718130293Sscottl			selatn3 = 1;
719130293Sscottl		else
720130293Sscottl			/* We don't have SELATN3; use SELATNS to send tags */
721130293Sscottl			selatns = 1;
722130293Sscottl	}
723130293Sscottl
724130293Sscottl	if (ti->flags & T_NEGOTIATE) {
725130293Sscottl		/* We have to use SELATNS to send sync/wide messages */
726130293Sscottl		selatn3 = 0;
727130293Sscottl		selatns = 1;
728130293Sscottl	}
729130293Sscottl
730130293Sscottl	cmd = (u_char *)&ecb->cmd.cmd;
731130293Sscottl
732130293Sscottl	if (selatn3) {
733130293Sscottl		/* We'll use tags with SELATN3 */
734130293Sscottl		clen = ecb->clen + 3;
735130293Sscottl		cmd -= 3;
736130293Sscottl		cmd[0] = MSG_IDENTIFY(lun, 1);	/* msg[0] */
737130293Sscottl		cmd[1] = ecb->tag[0];		/* msg[1] */
738130293Sscottl		cmd[2] = ecb->tag[1];		/* msg[2] */
739130293Sscottl	} else {
740130293Sscottl		/* We don't have tags, or will send messages with SELATNS */
741130293Sscottl		clen = ecb->clen + 1;
742130293Sscottl		cmd -= 1;
743130293Sscottl		cmd[0] = MSG_IDENTIFY(lun, (tiflags & T_RSELECTOFF) == 0);
744130293Sscottl	}
745130293Sscottl
746130293Sscottl	if ((sc->sc_features & NCR_F_DMASELECT) && !selatns) {
747130293Sscottl
748130293Sscottl		/* setup DMA transfer for command */
749130293Sscottl		dmasize = clen;
750130293Sscottl		sc->sc_cmdlen = clen;
751130293Sscottl		sc->sc_cmdp = cmd;
752130293Sscottl
753130293Sscottl		/* Program the SCSI counter */
754130293Sscottl		NCR_SET_COUNT(sc, dmasize);
755130293Sscottl
756130293Sscottl		/* load the count in */
757130293Sscottl		/* if (sc->sc_rev != NCR_VARIANT_FAS366) */
758130293Sscottl			NCRCMD(sc, NCRCMD_NOP|NCRCMD_DMA);
759130293Sscottl
760130293Sscottl		/* And get the targets attention */
761130293Sscottl		if (selatn3) {
762130293Sscottl			sc->sc_msgout = SEND_TAG;
763130293Sscottl			sc->sc_flags |= NCR_ATN;
764130293Sscottl			NCRCMD(sc, NCRCMD_SELATN3 | NCRCMD_DMA);
765130293Sscottl		} else
766130293Sscottl			NCRCMD(sc, NCRCMD_SELATN | NCRCMD_DMA);
767130293Sscottl		NCRDMA_SETUP(sc, &sc->sc_cmdp, &sc->sc_cmdlen, 0, &dmasize);
768130293Sscottl		NCRDMA_GO(sc);
769130293Sscottl		return;
770130293Sscottl	}
771130293Sscottl
772130293Sscottl	/*
773133039Strhodes	 * Who am I?  This is where we tell the target that we are
774130293Sscottl	 * happy for it to disconnect etc.
775130293Sscottl	 */
776130293Sscottl
777130293Sscottl	/* Now get the command into the FIFO */
778130293Sscottl	ncr53c9x_wrfifo(sc, cmd, clen);
779130293Sscottl
780130293Sscottl	/* And get the targets attention */
781130293Sscottl	if (selatns) {
782130293Sscottl		NCR_MSGS(("SELATNS \n"));
783130293Sscottl		/* Arbitrate, select and stop after IDENTIFY message */
784130293Sscottl		NCRCMD(sc, NCRCMD_SELATNS);
785130293Sscottl	} else if (selatn3) {
786130293Sscottl		sc->sc_msgout = SEND_TAG;
787130293Sscottl		sc->sc_flags |= NCR_ATN;
788130293Sscottl		NCRCMD(sc, NCRCMD_SELATN3);
789130293Sscottl	} else
790130293Sscottl		NCRCMD(sc, NCRCMD_SELATN);
791130293Sscottl}
792130293Sscottl
793130293Sscottlstatic void
794130293Sscottlncr53c9x_free_ecb(struct ncr53c9x_softc *sc, struct ncr53c9x_ecb *ecb)
795130293Sscottl{
796130293Sscottl
797130293Sscottl	ecb->flags = 0;
798130406Sscottl	TAILQ_INSERT_TAIL(&sc->free_list, ecb, free_links);
799130293Sscottl	return;
800130293Sscottl}
801130293Sscottl
802130293Sscottlstatic struct ncr53c9x_ecb *
803130293Sscottlncr53c9x_get_ecb(struct ncr53c9x_softc *sc)
804130293Sscottl{
805130293Sscottl	struct ncr53c9x_ecb *ecb;
806130293Sscottl
807130406Sscottl	ecb = TAILQ_FIRST(&sc->free_list);
808130293Sscottl	if (ecb) {
809130406Sscottl		if (ecb->flags != 0)
810130406Sscottl			panic("ecb flags not cleared\n");
811130406Sscottl		TAILQ_REMOVE(&sc->free_list, ecb, free_links);
812130406Sscottl		ecb->flags = ECB_ALLOC;
813130406Sscottl		bzero(&ecb->ccb, sizeof(struct ncr53c9x_ecb) -
814130406Sscottl		      offsetof(struct ncr53c9x_ecb, ccb));
815130293Sscottl	}
816130293Sscottl	return (ecb);
817130293Sscottl}
818130293Sscottl
819130293Sscottl/*
820133039Strhodes * DRIVER FUNCTIONS CALLABLE FROM HIGHER LEVEL DRIVERS:
821130293Sscottl */
822130293Sscottl
823130293Sscottl/*
824130293Sscottl * Start a SCSI-command
825130293Sscottl * This function is called by the higher level SCSI-driver to queue/run
826130293Sscottl * SCSI-commands.
827130293Sscottl */
828130293Sscottl
829130293Sscottlvoid
830130293Sscottlncr53c9x_action(struct cam_sim *sim, union ccb *ccb)
831130293Sscottl{
832130293Sscottl	struct ncr53c9x_softc *sc;
833130293Sscottl	struct ncr53c9x_ecb *ecb;
834130293Sscottl
835130293Sscottl	NCR_TRACE(("[ncr53c9x_action %d]", ccb->ccb_h.func_code));
836130293Sscottl
837130293Sscottl	sc = cam_sim_softc(sim);
838130293Sscottl	mtx_lock(&sc->sc_lock);
839130293Sscottl
840130293Sscottl	switch (ccb->ccb_h.func_code) {
841130293Sscottl	case XPT_RESET_BUS:
842130293Sscottl		ncr53c9x_scsi_reset(sc);
843130293Sscottl		ccb->ccb_h.status = CAM_REQ_CMP;
844130293Sscottl		mtx_unlock(&sc->sc_lock);
845130293Sscottl		xpt_done(ccb);
846130293Sscottl		return;
847130293Sscottl	case XPT_CALC_GEOMETRY:
848130293Sscottl		mtx_unlock(&sc->sc_lock);
849130349Sscottl		cam_calc_geometry(&ccb->ccg, sc->sc_extended_geom);
850130293Sscottl		xpt_done(ccb);
851130293Sscottl		return;
852130293Sscottl	case XPT_PATH_INQ:
853130293Sscottl	{
854130293Sscottl		struct ccb_pathinq *cpi = &ccb->cpi;
855130293Sscottl
856130293Sscottl		cpi->version_num = 1;
857130406Sscottl		cpi->hba_inquiry = PI_SDTR_ABLE|PI_TAG_ABLE;
858130293Sscottl		cpi->hba_inquiry |=
859130293Sscottl		    (sc->sc_rev == NCR_VARIANT_FAS366) ? PI_WIDE_16 : 0;
860130293Sscottl		cpi->target_sprt = 0;
861130293Sscottl		cpi->hba_misc = 0;
862130293Sscottl		cpi->hba_eng_cnt = 0;
863130293Sscottl		cpi->max_target = sc->sc_ntarg - 1;
864130293Sscottl		cpi->max_lun = 8;
865130293Sscottl		cpi->initiator_id = sc->sc_id;
866130293Sscottl		cpi->bus_id = 0;
867130293Sscottl		cpi->base_transfer_speed = 3300;
868130293Sscottl		strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
869130293Sscottl		strncpy(cpi->hba_vid, "Sun", HBA_IDLEN);
870130293Sscottl		strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
871130293Sscottl		cpi->unit_number = cam_sim_unit(sim);
872130293Sscottl		ccb->ccb_h.status = CAM_REQ_CMP;
873130293Sscottl		mtx_unlock(&sc->sc_lock);
874130293Sscottl		xpt_done(ccb);
875130293Sscottl		return;
876130293Sscottl	}
877130293Sscottl	case XPT_GET_TRAN_SETTINGS:
878130293Sscottl	{
879130293Sscottl		struct ccb_trans_settings *cts = &ccb->cts;
880130293Sscottl		struct ncr53c9x_tinfo *ti;
881130293Sscottl
882130293Sscottl		ti = &sc->sc_tinfo[ccb->ccb_h.target_id];
883130293Sscottl
884130293Sscottl		if ((cts->flags & CCB_TRANS_CURRENT_SETTINGS) != 0) {
885130293Sscottl			cts->sync_period = ti->period;
886130293Sscottl			cts->sync_offset = ti->offset;
887130293Sscottl			cts->bus_width = ti->width;
888130293Sscottl			if ((ti->flags & T_TAG) != 0)
889130293Sscottl				cts->flags |=
890130293Sscottl				    (CCB_TRANS_DISC_ENB | CCB_TRANS_TAG_ENB);
891130293Sscottl			else
892130293Sscottl				cts->flags &=
893130293Sscottl				    ~(CCB_TRANS_DISC_ENB | CCB_TRANS_TAG_ENB);
894130293Sscottl		} else {
895130293Sscottl			cts->sync_period = sc->sc_maxsync;
896130293Sscottl			cts->sync_offset = sc->sc_maxoffset;
897130293Sscottl			cts->bus_width = sc->sc_maxwidth;
898130293Sscottl			cts->flags |= (CCB_TRANS_DISC_ENB | CCB_TRANS_TAG_ENB);
899130293Sscottl		}
900130293Sscottl		cts->valid = CCB_TRANS_BUS_WIDTH_VALID |
901130293Sscottl			     CCB_TRANS_SYNC_RATE_VALID |
902130293Sscottl			     CCB_TRANS_SYNC_OFFSET_VALID |
903130293Sscottl			     CCB_TRANS_DISC_VALID |
904130293Sscottl			     CCB_TRANS_TQ_VALID;
905130293Sscottl		ccb->ccb_h.status = CAM_REQ_CMP;
906130293Sscottl		mtx_unlock(&sc->sc_lock);
907130293Sscottl		xpt_done(ccb);
908130293Sscottl		return;
909130293Sscottl	}
910130293Sscottl	case XPT_ABORT:
911130293Sscottl		printf("XPT_ABORT called\n");
912130293Sscottl		ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
913130293Sscottl		mtx_unlock(&sc->sc_lock);
914130293Sscottl		xpt_done(ccb);
915130293Sscottl		return;
916130293Sscottl	case XPT_TERM_IO:
917130293Sscottl		printf("XPT_TERM_IO called\n");
918130293Sscottl		ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
919130293Sscottl		mtx_unlock(&sc->sc_lock);
920130293Sscottl		xpt_done(ccb);
921130293Sscottl		return;
922130293Sscottl	case XPT_RESET_DEV:
923130293Sscottl		printf("XPT_RESET_DEV called\n");
924130293Sscottl	case XPT_SCSI_IO:
925130293Sscottl	{
926130293Sscottl		struct ccb_scsiio *csio;
927130293Sscottl
928130293Sscottl		if (ccb->ccb_h.target_id < 0 ||
929130293Sscottl		    ccb->ccb_h.target_id >= sc->sc_ntarg) {
930130293Sscottl			ccb->ccb_h.status = CAM_PATH_INVALID;
931130293Sscottl			mtx_unlock(&sc->sc_lock);
932130293Sscottl			xpt_done(ccb);
933130293Sscottl			return;
934130293Sscottl		}
935130293Sscottl		/* Get an ECB to use. */
936130293Sscottl		ecb = ncr53c9x_get_ecb(sc);
937130293Sscottl		/*
938130293Sscottl		 * This should never happen as we track resources
939130293Sscottl		 * in the mid-layer.
940130293Sscottl		 */
941130293Sscottl		if (ecb == NULL) {
942130293Sscottl			xpt_freeze_simq(sim, 1);
943130293Sscottl			ccb->ccb_h.status = CAM_REQUEUE_REQ;
944130293Sscottl			printf("unable to allocate ecb\n");
945130293Sscottl			mtx_unlock(&sc->sc_lock);
946130293Sscottl			xpt_done(ccb);
947130293Sscottl			return;
948130293Sscottl		}
949130293Sscottl
950130293Sscottl		/* Initialize ecb */
951130293Sscottl		ecb->ccb = ccb;
952130293Sscottl		ecb->timeout = ccb->ccb_h.timeout;
953130293Sscottl
954130372Sscottl		if (ccb->ccb_h.func_code == XPT_RESET_DEV) {
955130293Sscottl			ecb->flags |= ECB_RESET;
956130293Sscottl			ecb->clen = 0;
957130293Sscottl			ecb->dleft = 0;
958130293Sscottl		} else {
959130293Sscottl			csio = &ccb->csio;
960130293Sscottl			if ((ccb->ccb_h.flags & CAM_CDB_POINTER) != 0)
961130293Sscottl				bcopy(csio->cdb_io.cdb_ptr, &ecb->cmd.cmd,
962130293Sscottl				      csio->cdb_len);
963130293Sscottl			else
964130293Sscottl				bcopy(csio->cdb_io.cdb_bytes, &ecb->cmd.cmd,
965130293Sscottl				      csio->cdb_len);
966130293Sscottl			ecb->clen = csio->cdb_len;
967130293Sscottl			ecb->daddr = csio->data_ptr;
968130293Sscottl			ecb->dleft = csio->dxfer_len;
969130293Sscottl		}
970130293Sscottl		ecb->stat = 0;
971130293Sscottl
972130293Sscottl		TAILQ_INSERT_TAIL(&sc->ready_list, ecb, chain);
973130293Sscottl		ecb->flags |= ECB_READY;
974130293Sscottl		if (sc->sc_state == NCR_IDLE)
975130293Sscottl			ncr53c9x_sched(sc);
976130293Sscottl
977130293Sscottl		break;
978130293Sscottl	}
979130293Sscottl
980130293Sscottl	case XPT_SET_TRAN_SETTINGS:
981130293Sscottl	{
982130293Sscottl		struct ncr53c9x_tinfo *ti;
983130293Sscottl		struct ccb_trans_settings *cts = &ccb->cts;
984130293Sscottl		int target = ccb->ccb_h.target_id;
985130293Sscottl
986130293Sscottl		ti = &sc->sc_tinfo[target];
987130293Sscottl
988130293Sscottl		if ((cts->valid & CCB_TRANS_TQ_VALID) != 0) {
989130293Sscottl			if ((sc->sc_cfflags & (1<<((target & 7) + 16))) == 0 &&
990130293Sscottl			    (cts->flags & CCB_TRANS_TAG_ENB)) {
991130293Sscottl				NCR_MISC(("%s: target %d: tagged queuing\n",
992130293Sscottl				    device_get_nameunit(sc->sc_dev), target));
993130293Sscottl				ti->flags |= T_TAG;
994130293Sscottl			} else
995130293Sscottl				ti->flags &= ~T_TAG;
996130293Sscottl		}
997130293Sscottl
998130293Sscottl		if ((cts->valid & CCB_TRANS_BUS_WIDTH_VALID) != 0) {
999130293Sscottl			if (cts->bus_width != 0) {
1000130293Sscottl				NCR_MISC(("%s: target %d: wide negotiation\n",
1001130293Sscottl				    device_get_nameunit(sc->sc_dev), target));
1002130293Sscottl				if (sc->sc_rev == NCR_VARIANT_FAS366) {
1003130293Sscottl					ti->flags |= T_WIDE;
1004130293Sscottl					ti->width = 1;
1005130293Sscottl				}
1006130293Sscottl			} else {
1007130293Sscottl				ti->flags &= ~T_WIDE;
1008130293Sscottl				ti->width = 0;
1009130293Sscottl			}
1010130406Sscottl			ti->flags |= T_NEGOTIATE;
1011130293Sscottl		}
1012130293Sscottl
1013130293Sscottl		if ((cts->valid & CCB_TRANS_SYNC_RATE_VALID) != 0) {
1014130293Sscottl			NCR_MISC(("%s: target %d: sync period negotiation\n",
1015130293Sscottl			    device_get_nameunit(sc->sc_dev), target));
1016130293Sscottl			ti->flags |= T_NEGOTIATE;
1017130293Sscottl			ti->period = cts->sync_period;
1018130293Sscottl		}
1019130293Sscottl
1020130293Sscottl		if ((cts->valid & CCB_TRANS_SYNC_OFFSET_VALID) != 0) {
1021130293Sscottl			NCR_MISC(("%s: target %d: sync offset negotiation\n",
1022130293Sscottl			    device_get_nameunit(sc->sc_dev), target));
1023130293Sscottl			ti->flags |= T_NEGOTIATE;
1024130293Sscottl			ti->offset = cts->sync_offset;
1025130293Sscottl		}
1026130293Sscottl
1027130293Sscottl		mtx_unlock(&sc->sc_lock);
1028130293Sscottl		ccb->ccb_h.status = CAM_REQ_CMP;
1029130293Sscottl		xpt_done(ccb);
1030130293Sscottl		return;
1031130293Sscottl	}
1032130293Sscottl
1033130293Sscottl	default:
1034130293Sscottl		device_printf(sc->sc_dev, "Unhandled function code %d\n",
1035130293Sscottl		       ccb->ccb_h.func_code);
1036130293Sscottl		ccb->ccb_h.status = CAM_PROVIDE_FAIL;
1037130293Sscottl		mtx_unlock(&sc->sc_lock);
1038130293Sscottl		xpt_done(ccb);
1039130293Sscottl		return;
1040130293Sscottl	}
1041130293Sscottl
1042130293Sscottl	mtx_unlock(&sc->sc_lock);
1043130293Sscottl}
1044130293Sscottl
1045130293Sscottl/*
1046133039Strhodes * Used when interrupt driven I/O is not allowed, e.g. during boot.
1047130293Sscottl */
1048130293Sscottlstatic void
1049130293Sscottlncr53c9x_poll(struct cam_sim *sim)
1050130293Sscottl{
1051130293Sscottl	struct ncr53c9x_softc *sc;
1052130293Sscottl
1053130293Sscottl	NCR_TRACE(("[ncr53c9x_poll] "));
1054130293Sscottl	sc = cam_sim_softc(sim);
1055130293Sscottl	if (NCRDMA_ISINTR(sc)) {
1056130293Sscottl		ncr53c9x_intr(sc);
1057130293Sscottl	}
1058130293Sscottl}
1059130293Sscottl
1060130293Sscottl/*
1061130293Sscottl * LOW LEVEL SCSI UTILITIES
1062130293Sscottl */
1063130293Sscottl
1064130293Sscottl/*
1065130293Sscottl * Schedule a scsi operation.  This has now been pulled out of the interrupt
1066130293Sscottl * handler so that we may call it from ncr53c9x_scsipi_request and
1067145202Smarius * ncr53c9x_done.  This may save us an unnecessary interrupt just to get
1068130293Sscottl * things going.  Should only be called when state == NCR_IDLE and at bio pl.
1069130293Sscottl */
1070130293Sscottlstatic void
1071130293Sscottlncr53c9x_sched(struct ncr53c9x_softc *sc)
1072130293Sscottl{
1073130293Sscottl	struct ncr53c9x_ecb *ecb;
1074130293Sscottl	struct ncr53c9x_tinfo *ti;
1075130293Sscottl	struct ncr53c9x_linfo *li;
1076130293Sscottl	int lun;
1077130293Sscottl	int tag;
1078130293Sscottl
1079130293Sscottl	NCR_TRACE(("[ncr53c9x_sched] "));
1080130293Sscottl	if (sc->sc_state != NCR_IDLE)
1081130293Sscottl		panic("ncr53c9x_sched: not IDLE (state=%d)", sc->sc_state);
1082130293Sscottl
1083130293Sscottl	/*
1084130293Sscottl	 * Find first ecb in ready queue that is for a target/lunit
1085130293Sscottl	 * combinations that is not busy.
1086130293Sscottl	 */
1087130293Sscottl	for (ecb = TAILQ_FIRST(&sc->ready_list); ecb != NULL;
1088130293Sscottl	    ecb = TAILQ_NEXT(ecb, chain)) {
1089130293Sscottl		ti = &sc->sc_tinfo[ecb->ccb->ccb_h.target_id];
1090130293Sscottl		lun = ecb->ccb->ccb_h.target_lun;
1091130293Sscottl
1092130293Sscottl		/* Select type of tag for this command */
1093130293Sscottl		if ((ti->flags & (T_RSELECTOFF)) != 0)
1094130293Sscottl			tag = 0;
1095130293Sscottl		else if ((ti->flags & (T_TAG)) == 0)
1096130293Sscottl			tag = 0;
1097130293Sscottl		else if ((ecb->flags & ECB_SENSE) != 0)
1098130293Sscottl			tag = 0;
1099130406Sscottl		else if ((ecb->ccb->ccb_h.flags & CAM_TAG_ACTION_VALID) == 0)
1100130406Sscottl			tag = 0;
1101130406Sscottl		else if (ecb->ccb->csio.tag_action == CAM_TAG_ACTION_NONE)
1102130406Sscottl			tag = 0;
1103130293Sscottl		else
1104130293Sscottl			tag = ecb->ccb->csio.tag_action;
1105130293Sscottl
1106130293Sscottl		li = TINFO_LUN(ti, lun);
1107130293Sscottl		if (li == NULL) {
1108130293Sscottl			/* Initialize LUN info and add to list. */
1109130293Sscottl			if ((li = malloc(sizeof(*li),
1110130293Sscottl			    M_DEVBUF, M_NOWAIT|M_ZERO)) == NULL) {
1111130293Sscottl				continue;
1112130293Sscottl			}
1113130293Sscottl			li->lun = lun;
1114130293Sscottl
1115130293Sscottl			LIST_INSERT_HEAD(&ti->luns, li, link);
1116130293Sscottl			if (lun < NCR_NLUN)
1117130293Sscottl				ti->lun[lun] = li;
1118130293Sscottl		}
1119130293Sscottl		li->last_used = time_second;
1120130293Sscottl		if (tag == 0) {
1121130293Sscottl			/* Try to issue this as an un-tagged command */
1122130293Sscottl			if (li->untagged == NULL)
1123130293Sscottl				li->untagged = ecb;
1124130293Sscottl		}
1125130293Sscottl		if (li->untagged != NULL) {
1126130293Sscottl			tag = 0;
1127130293Sscottl			if ((li->busy != 1) && li->used == 0) {
1128130293Sscottl				/* We need to issue this untagged command now */
1129130293Sscottl				ecb = li->untagged;
1130130293Sscottl			} else {
1131130293Sscottl				/* Not ready yet */
1132130293Sscottl				continue;
1133130293Sscottl			}
1134130293Sscottl		}
1135130293Sscottl		ecb->tag[0] = tag;
1136130293Sscottl		if (tag != 0) {
1137130406Sscottl			li->queued[ecb->tag_id] = ecb;
1138130406Sscottl			ecb->tag[1] = ecb->tag_id;
1139130293Sscottl			li->used++;
1140130293Sscottl		}
1141130293Sscottl		if (li->untagged != NULL && (li->busy != 1)) {
1142130293Sscottl			li->busy = 1;
1143130293Sscottl			TAILQ_REMOVE(&sc->ready_list, ecb, chain);
1144130293Sscottl			ecb->flags &= ~ECB_READY;
1145130293Sscottl			sc->sc_nexus = ecb;
1146130293Sscottl			ncr53c9x_select(sc, ecb);
1147130293Sscottl			break;
1148130293Sscottl		}
1149130293Sscottl		if (li->untagged == NULL && tag != 0) {
1150130293Sscottl			TAILQ_REMOVE(&sc->ready_list, ecb, chain);
1151130293Sscottl			ecb->flags &= ~ECB_READY;
1152130293Sscottl			sc->sc_nexus = ecb;
1153130293Sscottl			ncr53c9x_select(sc, ecb);
1154130293Sscottl			break;
1155130293Sscottl		} else
1156130293Sscottl			NCR_TRACE(("%d:%d busy\n",
1157130293Sscottl			    ecb->ccb->ccb_h.target_id,
1158130293Sscottl			    ecb->ccb->ccb_h.target_lun));
1159130293Sscottl	}
1160130293Sscottl}
1161130293Sscottl
1162130293Sscottlstatic void
1163130293Sscottlncr53c9x_sense(struct ncr53c9x_softc *sc, struct ncr53c9x_ecb *ecb)
1164130293Sscottl{
1165130293Sscottl	union ccb *ccb = ecb->ccb;
1166130293Sscottl	struct ncr53c9x_tinfo *ti;
1167130293Sscottl	struct scsi_request_sense *ss = (void *)&ecb->cmd.cmd;
1168130293Sscottl	struct ncr53c9x_linfo *li;
1169130293Sscottl	int lun;
1170130293Sscottl
1171130293Sscottl	NCR_TRACE(("requesting sense "));
1172130293Sscottl
1173130293Sscottl	lun = ccb->ccb_h.target_lun;
1174130293Sscottl	ti = &sc->sc_tinfo[ccb->ccb_h.target_id];
1175130293Sscottl
1176130293Sscottl	/* Next, setup a request sense command block */
1177130293Sscottl	memset(ss, 0, sizeof(*ss));
1178130293Sscottl	ss->opcode = REQUEST_SENSE;
1179130293Sscottl	ss->byte2 = ccb->ccb_h.target_lun << SCSI_CMD_LUN_SHIFT;
1180130293Sscottl	ss->length = sizeof(struct scsi_sense_data);
1181130293Sscottl	ecb->clen = sizeof(*ss);
1182130293Sscottl	ecb->daddr = (char *)&ecb->ccb->csio.sense_data;
1183130293Sscottl	ecb->dleft = sizeof(struct scsi_sense_data);
1184130293Sscottl	ecb->flags |= ECB_SENSE;
1185130293Sscottl	ecb->timeout = NCR_SENSE_TIMEOUT;
1186130293Sscottl	ti->senses++;
1187130293Sscottl	li = TINFO_LUN(ti, lun);
1188130293Sscottl	if (li->busy)
1189130293Sscottl		li->busy = 0;
1190130293Sscottl	ncr53c9x_dequeue(sc, ecb);
1191130293Sscottl	li->untagged = ecb; /* must be executed first to fix C/A */
1192130293Sscottl	li->busy = 2;
1193130293Sscottl	if (ecb == sc->sc_nexus) {
1194130293Sscottl		ncr53c9x_select(sc, ecb);
1195130293Sscottl	} else {
1196130293Sscottl		TAILQ_INSERT_HEAD(&sc->ready_list, ecb, chain);
1197130293Sscottl		ecb->flags |= ECB_READY;
1198130293Sscottl		if (sc->sc_state == NCR_IDLE)
1199130293Sscottl			ncr53c9x_sched(sc);
1200130293Sscottl	}
1201130293Sscottl}
1202130293Sscottl
1203130293Sscottl/*
1204130293Sscottl * POST PROCESSING OF SCSI_CMD (usually current)
1205130293Sscottl */
1206130293Sscottlstatic void
1207130293Sscottlncr53c9x_done(struct ncr53c9x_softc *sc, struct ncr53c9x_ecb *ecb)
1208130293Sscottl{
1209130293Sscottl	union ccb *ccb = ecb->ccb;
1210130293Sscottl	struct ncr53c9x_tinfo *ti;
1211130293Sscottl	struct ncr53c9x_linfo *li;
1212130293Sscottl	int lun;
1213130293Sscottl
1214130293Sscottl	NCR_TRACE(("[ncr53c9x_done(status:%x)] ", ccb->ccb_h.status));
1215130293Sscottl
1216130293Sscottl	ti = &sc->sc_tinfo[ccb->ccb_h.target_id];
1217130293Sscottl	lun = ccb->ccb_h.target_lun;
1218130293Sscottl	li  = TINFO_LUN(ti, lun);
1219130293Sscottl
1220130424Sscottl	untimeout(ncr53c9x_timeout, ecb, ccb->ccb_h.timeout_ch);
1221130293Sscottl
1222130293Sscottl	/*
1223130293Sscottl	 * Now, if we've come here with no error code, i.e. we've kept the
1224130293Sscottl	 * initial XS_NOERROR, and the status code signals that we should
1225130293Sscottl	 * check sense, we'll need to set up a request sense cmd block and
1226130293Sscottl	 * push the command back into the ready queue *before* any other
1227130293Sscottl	 * commands for this target/lunit, else we lose the sense info.
1228130293Sscottl	 * We don't support chk sense conditions for the request sense cmd.
1229130293Sscottl	 */
1230130293Sscottl	if (ccb->ccb_h.status == CAM_REQ_CMP) {
1231130293Sscottl		if ((ecb->flags & ECB_ABORT) != 0) {
1232130293Sscottl			ccb->ccb_h.status = CAM_CMD_TIMEOUT;
1233130406Sscottl		} else if ((ecb->flags & ECB_SENSE) != 0 &&
1234130406Sscottl			   (ecb->stat != SCSI_STATUS_CHECK_COND)) {
1235130372Sscottl			ccb->ccb_h.status = CAM_AUTOSNS_VALID;
1236130293Sscottl		} else if (ecb->stat == SCSI_STATUS_CHECK_COND) {
1237130293Sscottl			if ((ecb->flags & ECB_SENSE) != 0)
1238130293Sscottl				ccb->ccb_h.status = CAM_AUTOSENSE_FAIL;
1239130293Sscottl			else {
1240130293Sscottl				/* First, save the return values */
1241130293Sscottl				ccb->csio.resid = ecb->dleft;
1242130293Sscottl				ncr53c9x_sense(sc, ecb);
1243130293Sscottl				return;
1244130293Sscottl			}
1245130293Sscottl		} else {
1246130293Sscottl			ccb->csio.resid = ecb->dleft;
1247130293Sscottl		}
1248130293Sscottl#if 0
1249130293Sscottl		if (xs->status == SCSI_QUEUE_FULL || xs->status == XS_BUSY)
1250130293Sscottl			xs->error = XS_BUSY;
1251130293Sscottl#endif
1252130293Sscottl	}
1253130293Sscottl
1254130293Sscottl#ifdef NCR53C9X_DEBUG
1255130293Sscottl	if (ncr53c9x_debug & NCR_SHOWTRAC) {
1256130293Sscottl		if (ccb->csio.resid != 0)
1257130293Sscottl			printf("resid=%d ", ccb->csio.resid);
1258130293Sscottl#if 0
1259130293Sscottl		if (xs->error == XS_SENSE)
1260130293Sscottl			printf("sense=0x%02x\n",
1261130293Sscottl			    xs->sense.scsi_sense.error_code);
1262130293Sscottl		else
1263130293Sscottl			printf("error=%d\n", xs->error);
1264130293Sscottl#endif
1265130293Sscottl	}
1266130293Sscottl#endif
1267130293Sscottl
1268130293Sscottl	/*
1269130293Sscottl	 * Remove the ECB from whatever queue it's on.
1270130293Sscottl	 */
1271130293Sscottl	ncr53c9x_dequeue(sc, ecb);
1272130293Sscottl	if (ecb == sc->sc_nexus) {
1273130293Sscottl		sc->sc_nexus = NULL;
1274130293Sscottl		if (sc->sc_state != NCR_CLEANING) {
1275130293Sscottl			sc->sc_state = NCR_IDLE;
1276130293Sscottl			ncr53c9x_sched(sc);
1277130293Sscottl		}
1278130293Sscottl	}
1279130293Sscottl
1280130293Sscottl	if (ccb->ccb_h.status == CAM_SEL_TIMEOUT) {
1281130293Sscottl		/* Selection timeout -- discard this LUN if empty */
1282130293Sscottl		if (li->untagged == NULL && li->used == 0) {
1283130293Sscottl			if (lun < NCR_NLUN)
1284130293Sscottl				ti->lun[lun] = NULL;
1285130293Sscottl			LIST_REMOVE(li, link);
1286130293Sscottl			free(li, M_DEVBUF);
1287130293Sscottl		}
1288130293Sscottl	}
1289130293Sscottl
1290130293Sscottl	ncr53c9x_free_ecb(sc, ecb);
1291130293Sscottl	ti->cmds++;
1292130293Sscottl	xpt_done(ccb);
1293130293Sscottl}
1294130293Sscottl
1295130293Sscottlstatic void
1296130293Sscottlncr53c9x_dequeue(struct ncr53c9x_softc *sc, struct ncr53c9x_ecb *ecb)
1297130293Sscottl{
1298130293Sscottl	struct ncr53c9x_tinfo *ti;
1299130293Sscottl	struct ncr53c9x_linfo *li;
1300130293Sscottl	int64_t lun;
1301130293Sscottl
1302130293Sscottl	ti = &sc->sc_tinfo[ecb->ccb->ccb_h.target_id];
1303130293Sscottl	lun = ecb->ccb->ccb_h.target_lun;
1304130293Sscottl	li = TINFO_LUN(ti, lun);
1305130293Sscottl#ifdef DIAGNOSTIC
1306130293Sscottl	if (li == NULL || li->lun != lun)
1307130293Sscottl		panic("ncr53c9x_dequeue: lun %qx for ecb %p does not exist",
1308130293Sscottl		      (long long) lun, ecb);
1309130293Sscottl#endif
1310130293Sscottl	if (li->untagged == ecb) {
1311130293Sscottl		li->busy = 0;
1312130293Sscottl		li->untagged = NULL;
1313130293Sscottl	}
1314130293Sscottl	if (ecb->tag[0] && li->queued[ecb->tag[1]] != NULL) {
1315130293Sscottl#ifdef DIAGNOSTIC
1316130293Sscottl		if (li->queued[ecb->tag[1]] != NULL &&
1317130293Sscottl		    (li->queued[ecb->tag[1]] != ecb))
1318130293Sscottl			panic("ncr53c9x_dequeue: slot %d for lun %qx has %p "
1319130293Sscottl			    "instead of ecb %p\n", ecb->tag[1],
1320130293Sscottl			    (long long) lun,
1321130293Sscottl			    li->queued[ecb->tag[1]], ecb);
1322130293Sscottl#endif
1323130293Sscottl		li->queued[ecb->tag[1]] = NULL;
1324130293Sscottl		li->used--;
1325130293Sscottl	}
1326130293Sscottl
1327130293Sscottl	if ((ecb->flags & ECB_READY) != 0) {
1328130293Sscottl		ecb->flags &= ~ECB_READY;
1329130293Sscottl		TAILQ_REMOVE(&sc->ready_list, ecb, chain);
1330130293Sscottl	}
1331130293Sscottl}
1332130293Sscottl
1333130293Sscottl/*
1334130293Sscottl * INTERRUPT/PROTOCOL ENGINE
1335130293Sscottl */
1336130293Sscottl
1337130293Sscottl/*
1338130293Sscottl * Schedule an outgoing message by prioritizing it, and asserting
1339130293Sscottl * attention on the bus. We can only do this when we are the initiator
1340130293Sscottl * else there will be an illegal command interrupt.
1341130293Sscottl */
1342130293Sscottl#define ncr53c9x_sched_msgout(m) \
1343130293Sscottl	do {							\
1344130293Sscottl		NCR_MSGS(("ncr53c9x_sched_msgout %x %d", m, __LINE__));	\
1345130293Sscottl		NCRCMD(sc, NCRCMD_SETATN);			\
1346130293Sscottl		sc->sc_flags |= NCR_ATN;			\
1347130293Sscottl		sc->sc_msgpriq |= (m);				\
1348130293Sscottl	} while (0)
1349130293Sscottl
1350130293Sscottlstatic void
1351130293Sscottlncr53c9x_flushfifo(struct ncr53c9x_softc *sc)
1352130293Sscottl{
1353130293Sscottl	NCR_TRACE(("[flushfifo] "));
1354130293Sscottl
1355130293Sscottl	NCRCMD(sc, NCRCMD_FLUSH);
1356130293Sscottl
1357130293Sscottl	if (sc->sc_phase == COMMAND_PHASE ||
1358130293Sscottl	    sc->sc_phase == MESSAGE_OUT_PHASE)
1359130293Sscottl		DELAY(2);
1360130293Sscottl}
1361130293Sscottl
1362130293Sscottlstatic int
1363130293Sscottlncr53c9x_rdfifo(struct ncr53c9x_softc *sc, int how)
1364130293Sscottl{
1365130293Sscottl	int i, n;
1366130293Sscottl	u_char *buf;
1367130293Sscottl
1368130293Sscottl	switch(how) {
1369130293Sscottl	case NCR_RDFIFO_START:
1370130293Sscottl		buf = sc->sc_imess;
1371130293Sscottl		sc->sc_imlen = 0;
1372130293Sscottl		break;
1373130293Sscottl	case NCR_RDFIFO_CONTINUE:
1374130293Sscottl		buf = sc->sc_imess + sc->sc_imlen;
1375130293Sscottl		break;
1376130293Sscottl	default:
1377130293Sscottl		panic("ncr53c9x_rdfifo: bad flag");
1378130293Sscottl		break;
1379130293Sscottl	}
1380130293Sscottl
1381130293Sscottl	/*
1382130293Sscottl	 * XXX buffer (sc_imess) size for message
1383130293Sscottl	 */
1384130293Sscottl
1385130293Sscottl	n = NCR_READ_REG(sc, NCR_FFLAG) & NCRFIFO_FF;
1386130293Sscottl
1387130293Sscottl	if (sc->sc_rev == NCR_VARIANT_FAS366) {
1388130293Sscottl		n *= 2;
1389130293Sscottl
1390130293Sscottl		for (i = 0; i < n; i++)
1391130293Sscottl			buf[i] = NCR_READ_REG(sc, NCR_FIFO);
1392130293Sscottl
1393130293Sscottl		if (sc->sc_espstat2 & NCRFAS_STAT2_ISHUTTLE) {
1394130293Sscottl
1395130293Sscottl			NCR_WRITE_REG(sc, NCR_FIFO, 0);
1396130293Sscottl			buf[i++] = NCR_READ_REG(sc, NCR_FIFO);
1397130293Sscottl
1398130293Sscottl			NCR_READ_REG(sc, NCR_FIFO);
1399130293Sscottl
1400130293Sscottl			ncr53c9x_flushfifo(sc);
1401130293Sscottl		}
1402130293Sscottl	} else {
1403130293Sscottl		for (i = 0; i < n; i++)
1404130293Sscottl			buf[i] = NCR_READ_REG(sc, NCR_FIFO);
1405130293Sscottl	}
1406130293Sscottl
1407130293Sscottl	sc->sc_imlen += i;
1408130293Sscottl
1409130293Sscottl#if 0
1410130293Sscottl#ifdef NCR53C9X_DEBUG
1411130293Sscottl 	{
1412130293Sscottl		int j;
1413130293Sscottl
1414130293Sscottl		NCR_TRACE(("\n[rdfifo %s (%d):",
1415130293Sscottl		    (how == NCR_RDFIFO_START) ? "start" : "cont",
1416130293Sscottl		    (int)sc->sc_imlen));
1417130293Sscottl		if (ncr53c9x_debug & NCR_SHOWTRAC) {
1418130293Sscottl			for (j = 0; j < sc->sc_imlen; j++)
1419130293Sscottl				printf(" %02x", sc->sc_imess[j]);
1420130293Sscottl			printf("]\n");
1421130293Sscottl		}
1422130293Sscottl	}
1423130293Sscottl#endif
1424130293Sscottl#endif
1425130293Sscottl	return sc->sc_imlen;
1426130293Sscottl}
1427130293Sscottl
1428130293Sscottlstatic void
1429130293Sscottlncr53c9x_wrfifo(struct ncr53c9x_softc *sc, u_char *p, int len)
1430130293Sscottl{
1431130293Sscottl	int i;
1432130293Sscottl
1433130293Sscottl#ifdef NCR53C9X_DEBUG
1434130293Sscottl	NCR_MSGS(("[wrfifo(%d):", len));
1435130293Sscottl	if (ncr53c9x_debug & NCR_SHOWMSGS) {
1436130293Sscottl		for (i = 0; i < len; i++)
1437130293Sscottl			printf(" %02x", p[i]);
1438130293Sscottl		printf("]\n");
1439130293Sscottl	}
1440130293Sscottl#endif
1441130293Sscottl
1442130293Sscottl	for (i = 0; i < len; i++) {
1443130293Sscottl		NCR_WRITE_REG(sc, NCR_FIFO, p[i]);
1444130293Sscottl
1445130293Sscottl		if (sc->sc_rev == NCR_VARIANT_FAS366)
1446130293Sscottl			NCR_WRITE_REG(sc, NCR_FIFO, 0);
1447130293Sscottl	}
1448130293Sscottl}
1449130293Sscottl
1450130293Sscottlstatic int
1451130293Sscottlncr53c9x_reselect(struct ncr53c9x_softc *sc, int message, int tagtype,
1452130293Sscottl		  int tagid)
1453130293Sscottl{
1454130293Sscottl	u_char selid, target, lun;
1455130293Sscottl	struct ncr53c9x_ecb *ecb = NULL;
1456130293Sscottl	struct ncr53c9x_tinfo *ti;
1457130293Sscottl	struct ncr53c9x_linfo *li;
1458130293Sscottl
1459130293Sscottl
1460130293Sscottl	if (sc->sc_rev == NCR_VARIANT_FAS366) {
1461130293Sscottl		target = sc->sc_selid;
1462130293Sscottl	} else {
1463130293Sscottl		/*
1464130293Sscottl		 * The SCSI chip made a snapshot of the data bus
1465130293Sscottl		 * while the reselection was being negotiated.
1466130293Sscottl		 * This enables us to determine which target did
1467130293Sscottl		 * the reselect.
1468130293Sscottl		 */
1469130293Sscottl		selid = sc->sc_selid & ~(1 << sc->sc_id);
1470130293Sscottl		if (selid & (selid - 1)) {
1471130293Sscottl			device_printf(sc->sc_dev, "reselect with invalid "
1472130293Sscottl			    "selid %02x; sending DEVICE RESET\n", selid);
1473130293Sscottl			goto reset;
1474130293Sscottl		}
1475130293Sscottl
1476130293Sscottl		target = ffs(selid) - 1;
1477130293Sscottl	}
1478130293Sscottl	lun = message & 0x07;
1479130293Sscottl
1480130293Sscottl	/*
1481130293Sscottl	 * Search wait queue for disconnected cmd
1482130293Sscottl	 * The list should be short, so I haven't bothered with
1483130293Sscottl	 * any more sophisticated structures than a simple
1484130293Sscottl	 * singly linked list.
1485130293Sscottl	 */
1486130293Sscottl	ti = &sc->sc_tinfo[target];
1487130293Sscottl	li = TINFO_LUN(ti, lun);
1488130293Sscottl
1489130293Sscottl	/*
1490130293Sscottl	 * We can get as far as the LUN with the IDENTIFY
1491130293Sscottl	 * message.  Check to see if we're running an
1492130293Sscottl	 * un-tagged command.  Otherwise ack the IDENTIFY
1493130293Sscottl	 * and wait for a tag message.
1494130293Sscottl	 */
1495130293Sscottl	if (li != NULL) {
1496130293Sscottl		if (li->untagged != NULL && li->busy)
1497130293Sscottl			ecb = li->untagged;
1498130293Sscottl		else if (tagtype != MSG_SIMPLE_Q_TAG) {
1499130293Sscottl			/* Wait for tag to come by */
1500130293Sscottl			sc->sc_state = NCR_IDENTIFIED;
1501130293Sscottl			return (0);
1502130293Sscottl		} else if (tagtype)
1503130293Sscottl			ecb = li->queued[tagid];
1504130293Sscottl	}
1505130293Sscottl	if (ecb == NULL) {
1506130293Sscottl		device_printf(sc->sc_dev, "reselect from target %d lun %d "
1507130293Sscottl		    "tag %x:%x with no nexus; sending ABORT\n",
1508130293Sscottl		    target, lun, tagtype, tagid);
1509130293Sscottl		goto abort;
1510130293Sscottl	}
1511130293Sscottl
1512130293Sscottl	/* Make this nexus active again. */
1513130293Sscottl	sc->sc_state = NCR_CONNECTED;
1514130293Sscottl	sc->sc_nexus = ecb;
1515130293Sscottl	ncr53c9x_setsync(sc, ti);
1516130293Sscottl
1517130293Sscottl	if (ecb->flags & ECB_RESET)
1518130293Sscottl		ncr53c9x_sched_msgout(SEND_DEV_RESET);
1519130293Sscottl	else if (ecb->flags & ECB_ABORT)
1520130293Sscottl		ncr53c9x_sched_msgout(SEND_ABORT);
1521130293Sscottl
1522130293Sscottl	/* Do an implicit RESTORE POINTERS. */
1523130293Sscottl	sc->sc_dp = ecb->daddr;
1524130293Sscottl	sc->sc_dleft = ecb->dleft;
1525130293Sscottl
1526130293Sscottl	return (0);
1527130293Sscottl
1528130293Sscottlreset:
1529130293Sscottl	ncr53c9x_sched_msgout(SEND_DEV_RESET);
1530130293Sscottl	return (1);
1531130293Sscottl
1532130293Sscottlabort:
1533130293Sscottl	ncr53c9x_sched_msgout(SEND_ABORT);
1534130293Sscottl	return (1);
1535130293Sscottl}
1536130293Sscottl
1537130293Sscottl/* From NetBSD.  These should go into CAM at some point */
1538130293Sscottl#define MSG_ISEXTENDED(m)	((m) == MSG_EXTENDED)
1539130293Sscottl#define MSG_IS1BYTE(m) \
1540130293Sscottl	((!MSG_ISEXTENDED(m) && (m) < 0x20) || MSG_ISIDENTIFY(m))
1541130293Sscottl#define MSG_IS2BYTE(m)		(((m) & 0xf0) == 0x20)
1542130293Sscottl
1543130293Sscottlstatic inline int
1544130293Sscottl__verify_msg_format(u_char *p, int len)
1545130293Sscottl{
1546130293Sscottl
1547130293Sscottl	if (len == 1 && MSG_IS1BYTE(p[0]))
1548130293Sscottl		return 1;
1549130293Sscottl	if (len == 2 && MSG_IS2BYTE(p[0]))
1550130293Sscottl		return 1;
1551130293Sscottl	if (len >= 3 && MSG_ISEXTENDED(p[0]) &&
1552130293Sscottl	    len == p[1] + 2)
1553130293Sscottl		return 1;
1554130293Sscottl
1555130293Sscottl	return 0;
1556130293Sscottl}
1557130293Sscottl
1558130293Sscottl/*
1559130293Sscottl * Get an incoming message as initiator.
1560130293Sscottl *
1561130293Sscottl * The SCSI bus must already be in MESSAGE_IN_PHASE and there is a
1562130293Sscottl * byte in the FIFO
1563130293Sscottl */
1564130293Sscottlstatic void
1565130293Sscottlncr53c9x_msgin(struct ncr53c9x_softc *sc)
1566130293Sscottl{
1567130293Sscottl
1568130293Sscottl	NCR_TRACE(("[ncr53c9x_msgin(curmsglen:%ld)] ", (long)sc->sc_imlen));
1569130293Sscottl
1570130293Sscottl	if (sc->sc_imlen == 0) {
1571130293Sscottl		device_printf(sc->sc_dev, "msgin: no msg byte available\n");
1572130293Sscottl		return;
1573130293Sscottl	}
1574130293Sscottl
1575130293Sscottl	/*
1576130293Sscottl	 * Prepare for a new message.  A message should (according
1577130293Sscottl	 * to the SCSI standard) be transmitted in one single
1578130293Sscottl	 * MESSAGE_IN_PHASE. If we have been in some other phase,
1579130293Sscottl	 * then this is a new message.
1580130293Sscottl	 */
1581130293Sscottl	if (sc->sc_prevphase != MESSAGE_IN_PHASE &&
1582130293Sscottl	    sc->sc_state != NCR_RESELECTED) {
1583130293Sscottl		device_printf(sc->sc_dev, "phase change, dropping message, "
1584130293Sscottl		    "prev %d, state %d\n", sc->sc_prevphase, sc->sc_state);
1585130293Sscottl		sc->sc_flags &= ~NCR_DROP_MSGI;
1586130293Sscottl		sc->sc_imlen = 0;
1587130293Sscottl	}
1588130293Sscottl
1589130293Sscottl	/*
1590130293Sscottl	 * If we're going to reject the message, don't bother storing
1591130293Sscottl	 * the incoming bytes.  But still, we need to ACK them.
1592130293Sscottl	 */
1593130293Sscottl	if ((sc->sc_flags & NCR_DROP_MSGI) != 0) {
1594130293Sscottl		NCRCMD(sc, NCRCMD_MSGOK);
1595130293Sscottl		printf("<dropping msg byte %x>", sc->sc_imess[sc->sc_imlen]);
1596130293Sscottl		return;
1597130293Sscottl	}
1598130293Sscottl
1599130293Sscottl	if (sc->sc_imlen >= NCR_MAX_MSG_LEN) {
1600130293Sscottl		ncr53c9x_sched_msgout(SEND_REJECT);
1601130293Sscottl		sc->sc_flags |= NCR_DROP_MSGI;
1602130293Sscottl	} else {
1603130293Sscottl		u_char *pb;
1604130293Sscottl		int plen;
1605130293Sscottl
1606130293Sscottl		switch (sc->sc_state) {
1607130293Sscottl		/*
1608130293Sscottl		 * if received message is the first of reselection
1609130293Sscottl		 * then first byte is selid, and then message
1610130293Sscottl		 */
1611130293Sscottl		case NCR_RESELECTED:
1612130293Sscottl			pb = sc->sc_imess + 1;
1613130293Sscottl			plen = sc->sc_imlen - 1;
1614130293Sscottl			break;
1615130293Sscottl		default:
1616130293Sscottl			pb = sc->sc_imess;
1617130293Sscottl			plen = sc->sc_imlen;
1618130293Sscottl			break;
1619130293Sscottl		}
1620130293Sscottl
1621130293Sscottl		if (__verify_msg_format(pb, plen))
1622130293Sscottl			goto gotit;
1623130293Sscottl	}
1624130293Sscottl
1625130293Sscottl	/* Ack what we have so far */
1626130293Sscottl	NCRCMD(sc, NCRCMD_MSGOK);
1627130293Sscottl	return;
1628130293Sscottl
1629130293Sscottlgotit:
1630130293Sscottl	NCR_MSGS(("gotmsg(%x) state %d", sc->sc_imess[0], sc->sc_state));
1631133039Strhodes	/* We got a complete message, flush the imess, */
1632130293Sscottl	/* XXX nobody uses imlen below */
1633130293Sscottl	sc->sc_imlen = 0;
1634130293Sscottl	/*
1635130293Sscottl	 * Now we should have a complete message (1 byte, 2 byte
1636130293Sscottl	 * and moderately long extended messages).  We only handle
1637130293Sscottl	 * extended messages which total length is shorter than
1638130293Sscottl	 * NCR_MAX_MSG_LEN.  Longer messages will be amputated.
1639130293Sscottl	 */
1640130293Sscottl	switch (sc->sc_state) {
1641130293Sscottl		struct ncr53c9x_ecb *ecb;
1642130293Sscottl		struct ncr53c9x_tinfo *ti;
1643130293Sscottl		struct ncr53c9x_linfo *li;
1644130293Sscottl		int lun;
1645130293Sscottl
1646130293Sscottl	case NCR_CONNECTED:
1647130293Sscottl		ecb = sc->sc_nexus;
1648130293Sscottl		ti = &sc->sc_tinfo[ecb->ccb->ccb_h.target_id];
1649130293Sscottl
1650130293Sscottl		switch (sc->sc_imess[0]) {
1651130293Sscottl		case MSG_CMDCOMPLETE:
1652130293Sscottl			NCR_MSGS(("cmdcomplete "));
1653130293Sscottl			if (sc->sc_dleft < 0) {
1654130293Sscottl				xpt_print_path(ecb->ccb->ccb_h.path);
1655130293Sscottl				printf("got %ld extra bytes\n",
1656130293Sscottl				    -(long)sc->sc_dleft);
1657130293Sscottl				sc->sc_dleft = 0;
1658130293Sscottl			}
1659130293Sscottl			ecb->dleft = (ecb->flags & ECB_TENTATIVE_DONE) ?
1660130293Sscottl			    0 : sc->sc_dleft;
1661130293Sscottl			if ((ecb->flags & ECB_SENSE) == 0)
1662130293Sscottl				ecb->ccb->csio.resid = ecb->dleft;
1663130293Sscottl			sc->sc_state = NCR_CMDCOMPLETE;
1664130293Sscottl			break;
1665130293Sscottl
1666130293Sscottl		case MSG_MESSAGE_REJECT:
1667130293Sscottl			NCR_MSGS(("msg reject (msgout=%x) ", sc->sc_msgout));
1668130293Sscottl			switch (sc->sc_msgout) {
1669130293Sscottl			case SEND_TAG:
1670130293Sscottl				/*
1671130293Sscottl				 * Target does not like tagged queuing.
1672130293Sscottl				 *  - Flush the command queue
1673130293Sscottl				 *  - Disable tagged queuing for the target
1674130293Sscottl				 *  - Dequeue ecb from the queued array.
1675130293Sscottl				 */
1676130293Sscottl				device_printf(sc->sc_dev, "tagged queuing "
1677130293Sscottl				    "rejected: target %d\n",
1678130293Sscottl				    ecb->ccb->ccb_h.target_id);
1679130293Sscottl
1680130293Sscottl				NCR_MSGS(("(rejected sent tag)"));
1681130293Sscottl				NCRCMD(sc, NCRCMD_FLUSH);
1682130293Sscottl				DELAY(1);
1683130293Sscottl				ti->flags &= ~T_TAG;
1684130293Sscottl				lun = ecb->ccb->ccb_h.target_lun;
1685130293Sscottl				li = TINFO_LUN(ti, lun);
1686130293Sscottl				if (ecb->tag[0] &&
1687130293Sscottl				    li->queued[ecb->tag[1]] != NULL) {
1688130293Sscottl					li->queued[ecb->tag[1]] = NULL;
1689130293Sscottl					li->used--;
1690130293Sscottl				}
1691130293Sscottl				ecb->tag[0] = ecb->tag[1] = 0;
1692130293Sscottl				li->untagged = ecb;
1693130293Sscottl				li->busy = 1;
1694130293Sscottl				break;
1695130293Sscottl
1696130293Sscottl			case SEND_SDTR:
1697130293Sscottl				device_printf(sc->sc_dev, "sync transfer "
1698130293Sscottl				    "rejected: target %d\n",
1699130293Sscottl				    ecb->ccb->ccb_h.target_id);
1700130293Sscottl
1701130293Sscottl				sc->sc_flags &= ~NCR_SYNCHNEGO;
1702130293Sscottl				ti->flags &= ~(T_NEGOTIATE | T_SYNCMODE);
1703130293Sscottl				ncr53c9x_setsync(sc, ti);
1704130293Sscottl				break;
1705130293Sscottl
1706130293Sscottl			case SEND_WDTR:
1707130293Sscottl				device_printf(sc->sc_dev, "wide transfer "
1708130293Sscottl				    "rejected: target %d\n",
1709130293Sscottl				    ecb->ccb->ccb_h.target_id);
1710130293Sscottl				ti->flags &= ~(T_WIDE | T_WDTRSENT);
1711130293Sscottl				ti->width = 0;
1712130293Sscottl				break;
1713130293Sscottl
1714130293Sscottl			case SEND_INIT_DET_ERR:
1715130293Sscottl				goto abort;
1716130293Sscottl			}
1717130293Sscottl			break;
1718130293Sscottl
1719130293Sscottl		case MSG_NOOP:
1720130293Sscottl			NCR_MSGS(("noop "));
1721130293Sscottl			break;
1722130293Sscottl
1723130293Sscottl		case MSG_HEAD_OF_Q_TAG:
1724130293Sscottl		case MSG_SIMPLE_Q_TAG:
1725130293Sscottl		case MSG_ORDERED_Q_TAG:
1726130293Sscottl			NCR_MSGS(("TAG %x:%x",
1727130293Sscottl			    sc->sc_imess[0], sc->sc_imess[1]));
1728130293Sscottl			break;
1729130293Sscottl
1730130293Sscottl		case MSG_DISCONNECT:
1731130293Sscottl			NCR_MSGS(("disconnect "));
1732130293Sscottl			ti->dconns++;
1733130293Sscottl			sc->sc_state = NCR_DISCONNECT;
1734130293Sscottl
1735130293Sscottl			/*
1736130293Sscottl			 * Mark the fact that all bytes have moved. The
1737130293Sscottl			 * target may not bother to do a SAVE POINTERS
1738130293Sscottl			 * at this stage. This flag will set the residual
1739130293Sscottl			 * count to zero on MSG COMPLETE.
1740130293Sscottl			 */
1741130293Sscottl			if (sc->sc_dleft == 0)
1742130293Sscottl				ecb->flags |= ECB_TENTATIVE_DONE;
1743130293Sscottl
1744130293Sscottl			break;
1745130293Sscottl
1746130293Sscottl		case MSG_SAVEDATAPOINTER:
1747130293Sscottl			NCR_MSGS(("save datapointer "));
1748130293Sscottl			ecb->daddr = sc->sc_dp;
1749130293Sscottl			ecb->dleft = sc->sc_dleft;
1750130293Sscottl			break;
1751130293Sscottl
1752130293Sscottl		case MSG_RESTOREPOINTERS:
1753130293Sscottl			NCR_MSGS(("restore datapointer "));
1754130293Sscottl			sc->sc_dp = ecb->daddr;
1755130293Sscottl			sc->sc_dleft = ecb->dleft;
1756130293Sscottl			break;
1757130293Sscottl
1758130293Sscottl		case MSG_EXTENDED:
1759130293Sscottl			NCR_MSGS(("extended(%x) ", sc->sc_imess[2]));
1760130293Sscottl			switch (sc->sc_imess[2]) {
1761130293Sscottl			case MSG_EXT_SDTR:
1762130293Sscottl				NCR_MSGS(("SDTR period %d, offset %d ",
1763130293Sscottl				    sc->sc_imess[3], sc->sc_imess[4]));
1764130293Sscottl				if (sc->sc_imess[1] != 3)
1765130293Sscottl					goto reject;
1766130293Sscottl				ti->period = sc->sc_imess[3];
1767130293Sscottl				ti->offset = sc->sc_imess[4];
1768130293Sscottl				ti->flags &= ~T_NEGOTIATE;
1769130293Sscottl				if (sc->sc_minsync == 0 ||
1770130293Sscottl				    ti->offset == 0 ||
1771130293Sscottl				    ti->period > 124) {
1772130293Sscottl#if 0
1773130293Sscottl#ifdef NCR53C9X_DEBUG
1774130293Sscottl					xpt_print_path(ecb->ccb->ccb_h.path);
1775130293Sscottl					printf("async mode\n");
1776130293Sscottl#endif
1777130293Sscottl#endif
1778130293Sscottl					ti->flags &= ~T_SYNCMODE;
1779130293Sscottl					if ((sc->sc_flags&NCR_SYNCHNEGO) == 0) {
1780130293Sscottl						/*
1781130293Sscottl						 * target initiated negotiation
1782130293Sscottl						 */
1783130293Sscottl						ti->offset = 0;
1784130293Sscottl						ncr53c9x_sched_msgout(
1785130293Sscottl						    SEND_SDTR);
1786130293Sscottl					}
1787130293Sscottl				} else {
1788130293Sscottl					int p;
1789130293Sscottl
1790130293Sscottl					p = ncr53c9x_stp2cpb(sc, ti->period);
1791130293Sscottl					ti->period = ncr53c9x_cpb2stp(sc, p);
1792130293Sscottl					if ((sc->sc_flags&NCR_SYNCHNEGO) == 0) {
1793130293Sscottl						/*
1794130293Sscottl						 * target initiated negotiation
1795130293Sscottl						 */
1796130293Sscottl						if (ti->period <
1797130293Sscottl						    sc->sc_minsync)
1798130293Sscottl							ti->period =
1799130293Sscottl							    sc->sc_minsync;
1800130293Sscottl						if (ti->offset > 15)
1801130293Sscottl							ti->offset = 15;
1802130293Sscottl						ti->flags &= ~T_SYNCMODE;
1803130293Sscottl						ncr53c9x_sched_msgout(
1804130293Sscottl						    SEND_SDTR);
1805130293Sscottl					} else {
1806130293Sscottl						/* we are sync */
1807130293Sscottl						ti->flags |= T_SYNCMODE;
1808130293Sscottl					}
1809130293Sscottl				}
1810130293Sscottl				sc->sc_flags &= ~NCR_SYNCHNEGO;
1811130293Sscottl				ncr53c9x_setsync(sc, ti);
1812130293Sscottl				break;
1813130293Sscottl
1814130293Sscottl			case MSG_EXT_WDTR:
1815130293Sscottl#ifdef NCR53C9X_DEBUG
1816130293Sscottl				device_printf(sc->sc_dev, "wide mode %d\n",
1817130293Sscottl				    sc->sc_imess[3]);
1818130293Sscottl#endif
1819130293Sscottl				if (sc->sc_imess[3] == 1) {
1820130293Sscottl					ti->cfg3 |= NCRFASCFG3_EWIDE;
1821130293Sscottl					ncr53c9x_setsync(sc, ti);
1822130293Sscottl				} else
1823130293Sscottl					ti->width = 0;
1824130293Sscottl				/*
1825130293Sscottl				 * Device started width negotiation.
1826130293Sscottl				 */
1827130293Sscottl				if (!(ti->flags & T_WDTRSENT))
1828130293Sscottl					ncr53c9x_sched_msgout(SEND_WDTR);
1829130293Sscottl				ti->flags &= ~(T_WIDE | T_WDTRSENT);
1830130293Sscottl				break;
1831130293Sscottl			default:
1832130293Sscottl				xpt_print_path(ecb->ccb->ccb_h.path);
1833130293Sscottl				printf("unrecognized MESSAGE EXTENDED;"
1834130293Sscottl				    " sending REJECT\n");
1835130293Sscottl				goto reject;
1836130293Sscottl			}
1837130293Sscottl			break;
1838130293Sscottl
1839130293Sscottl		default:
1840130293Sscottl			NCR_MSGS(("ident "));
1841130293Sscottl			xpt_print_path(ecb->ccb->ccb_h.path);
1842130293Sscottl			printf("unrecognized MESSAGE; sending REJECT\n");
1843130293Sscottl		reject:
1844130293Sscottl			ncr53c9x_sched_msgout(SEND_REJECT);
1845130293Sscottl			break;
1846130293Sscottl		}
1847130293Sscottl		break;
1848130293Sscottl
1849130293Sscottl	case NCR_IDENTIFIED:
1850130293Sscottl		/*
1851130293Sscottl		 * IDENTIFY message was received and queue tag is expected now
1852145202Smarius		 */
1853130293Sscottl		if ((sc->sc_imess[0] != MSG_SIMPLE_Q_TAG) ||
1854130293Sscottl		    (sc->sc_msgify == 0)) {
1855130293Sscottl			device_printf(sc->sc_dev, "TAG reselect without "
1856130293Sscottl			    "IDENTIFY; MSG %x; sending DEVICE RESET\n",
1857130293Sscottl			     sc->sc_imess[0]);
1858130293Sscottl			goto reset;
1859130293Sscottl		}
1860130293Sscottl		(void) ncr53c9x_reselect(sc, sc->sc_msgify,
1861130293Sscottl		    sc->sc_imess[0], sc->sc_imess[1]);
1862130293Sscottl		break;
1863130293Sscottl
1864130293Sscottl	case NCR_RESELECTED:
1865130293Sscottl		if (MSG_ISIDENTIFY(sc->sc_imess[1])) {
1866130293Sscottl			sc->sc_msgify = sc->sc_imess[1];
1867130293Sscottl		} else {
1868130293Sscottl			device_printf(sc->sc_dev, "reselect without IDENTIFY;"
1869130293Sscottl			    " MSG %x; sending DEVICE RESET\n", sc->sc_imess[1]);
1870130293Sscottl			goto reset;
1871130293Sscottl		}
1872130293Sscottl		(void) ncr53c9x_reselect(sc, sc->sc_msgify, 0, 0);
1873130293Sscottl		break;
1874130293Sscottl
1875130293Sscottl	default:
1876130293Sscottl		device_printf(sc->sc_dev, "unexpected MESSAGE IN; "
1877130293Sscottl		    "sending DEVICE RESET\n");
1878130293Sscottl	reset:
1879130293Sscottl		ncr53c9x_sched_msgout(SEND_DEV_RESET);
1880130293Sscottl		break;
1881130293Sscottl
1882130293Sscottl	abort:
1883130293Sscottl		ncr53c9x_sched_msgout(SEND_ABORT);
1884130293Sscottl		break;
1885130293Sscottl	}
1886130293Sscottl
1887130293Sscottl	/* if we have more messages to send set ATN */
1888130293Sscottl	if (sc->sc_msgpriq)
1889130293Sscottl		NCRCMD(sc, NCRCMD_SETATN);
1890130293Sscottl
1891130293Sscottl	/* Ack last message byte */
1892130293Sscottl	NCRCMD(sc, NCRCMD_MSGOK);
1893130293Sscottl
1894130293Sscottl	/* Done, reset message pointer. */
1895130293Sscottl	sc->sc_flags &= ~NCR_DROP_MSGI;
1896130293Sscottl	sc->sc_imlen = 0;
1897130293Sscottl}
1898130293Sscottl
1899130293Sscottl
1900130293Sscottl/*
1901130293Sscottl * Send the highest priority, scheduled message
1902130293Sscottl */
1903130293Sscottlstatic void
1904130293Sscottlncr53c9x_msgout(struct ncr53c9x_softc *sc)
1905130293Sscottl{
1906130293Sscottl	struct ncr53c9x_tinfo *ti;
1907130293Sscottl	struct ncr53c9x_ecb *ecb;
1908130293Sscottl	size_t size;
1909130293Sscottl
1910130293Sscottl	NCR_TRACE(("[ncr53c9x_msgout(priq:%x, prevphase:%x)]",
1911130293Sscottl	    sc->sc_msgpriq, sc->sc_prevphase));
1912130293Sscottl
1913130293Sscottl	/*
1914130293Sscottl	 * XXX - the NCR_ATN flag is not in sync with the actual ATN
1915130293Sscottl	 *	 condition on the SCSI bus. The 53c9x chip
1916130293Sscottl	 *	 automatically turns off ATN before sending the
1917133039Strhodes	 *	 message byte.  (See also the comment below in the
1918133039Strhodes	 *	 default case when picking out a message to send.)
1919130293Sscottl	 */
1920130293Sscottl	if (sc->sc_flags & NCR_ATN) {
1921130293Sscottl		if (sc->sc_prevphase != MESSAGE_OUT_PHASE) {
1922130293Sscottl		new:
1923130293Sscottl			NCRCMD(sc, NCRCMD_FLUSH);
1924130293Sscottl/*			DELAY(1); */
1925130293Sscottl			sc->sc_msgoutq = 0;
1926130293Sscottl			sc->sc_omlen = 0;
1927130293Sscottl		}
1928130293Sscottl	} else {
1929130293Sscottl		if (sc->sc_prevphase == MESSAGE_OUT_PHASE) {
1930130293Sscottl			ncr53c9x_sched_msgout(sc->sc_msgoutq);
1931130293Sscottl			goto new;
1932130293Sscottl		} else {
1933130293Sscottl			device_printf(sc->sc_dev, "at line %d: unexpected "
1934130293Sscottl			    "MESSAGE OUT phase\n", __LINE__);
1935130293Sscottl		}
1936130293Sscottl	}
1937130293Sscottl
1938130293Sscottl	if (sc->sc_omlen == 0) {
1939130293Sscottl		/* Pick up highest priority message */
1940130293Sscottl		sc->sc_msgout = sc->sc_msgpriq & -sc->sc_msgpriq;
1941130293Sscottl		sc->sc_msgoutq |= sc->sc_msgout;
1942130293Sscottl		sc->sc_msgpriq &= ~sc->sc_msgout;
1943130293Sscottl		sc->sc_omlen = 1;		/* "Default" message len */
1944130293Sscottl		switch (sc->sc_msgout) {
1945130293Sscottl		case SEND_SDTR:
1946130293Sscottl			ecb = sc->sc_nexus;
1947130293Sscottl			ti = &sc->sc_tinfo[ecb->ccb->ccb_h.target_id];
1948130293Sscottl			sc->sc_omess[0] = MSG_EXTENDED;
1949130293Sscottl			sc->sc_omess[1] = MSG_EXT_SDTR_LEN;
1950130293Sscottl			sc->sc_omess[2] = MSG_EXT_SDTR;
1951130293Sscottl			sc->sc_omess[3] = ti->period;
1952130293Sscottl			sc->sc_omess[4] = ti->offset;
1953130293Sscottl			sc->sc_omlen = 5;
1954130293Sscottl			if ((sc->sc_flags & NCR_SYNCHNEGO) == 0) {
1955130293Sscottl				ti->flags |= T_SYNCMODE;
1956130293Sscottl				ncr53c9x_setsync(sc, ti);
1957130293Sscottl			}
1958130293Sscottl			break;
1959130293Sscottl		case SEND_WDTR:
1960130293Sscottl			ecb = sc->sc_nexus;
1961130293Sscottl			ti = &sc->sc_tinfo[ecb->ccb->ccb_h.target_id];
1962130293Sscottl			sc->sc_omess[0] = MSG_EXTENDED;
1963130293Sscottl			sc->sc_omess[1] = MSG_EXT_WDTR_LEN;
1964130293Sscottl			sc->sc_omess[2] = MSG_EXT_WDTR;
1965130293Sscottl			sc->sc_omess[3] = ti->width;
1966130293Sscottl			sc->sc_omlen = 4;
1967130293Sscottl			break;
1968130293Sscottl                case SEND_IDENTIFY:
1969130293Sscottl                        if (sc->sc_state != NCR_CONNECTED) {
1970130293Sscottl                                device_printf(sc->sc_dev, "at line %d: no "
1971130293Sscottl				    "nexus\n", __LINE__);
1972130293Sscottl                        }
1973130293Sscottl                        ecb = sc->sc_nexus;
1974130293Sscottl                        sc->sc_omess[0] =
1975130293Sscottl                            MSG_IDENTIFY(ecb->ccb->ccb_h.target_lun, 0);
1976130293Sscottl                        break;
1977130293Sscottl		case SEND_TAG:
1978130293Sscottl			if (sc->sc_state != NCR_CONNECTED) {
1979130293Sscottl				device_printf(sc->sc_dev, "at line %d: no "
1980130293Sscottl				    "nexus\n", __LINE__);
1981130293Sscottl			}
1982130293Sscottl			ecb = sc->sc_nexus;
1983130293Sscottl			sc->sc_omess[0] = ecb->tag[0];
1984130293Sscottl			sc->sc_omess[1] = ecb->tag[1];
1985130293Sscottl			sc->sc_omlen = 2;
1986130293Sscottl			break;
1987130293Sscottl		case SEND_DEV_RESET:
1988130293Sscottl			sc->sc_flags |= NCR_ABORTING;
1989130293Sscottl			sc->sc_omess[0] = MSG_BUS_DEV_RESET;
1990130293Sscottl			ecb = sc->sc_nexus;
1991130293Sscottl			ti = &sc->sc_tinfo[ecb->ccb->ccb_h.target_id];
1992130293Sscottl			ti->flags &= ~T_SYNCMODE;
1993130293Sscottl			if ((ti->flags & T_SYNCHOFF) == 0)
1994130293Sscottl				/* We can re-start sync negotiation */
1995130293Sscottl				ti->flags |= T_NEGOTIATE;
1996130293Sscottl			break;
1997130293Sscottl		case SEND_PARITY_ERROR:
1998130293Sscottl			sc->sc_omess[0] = MSG_PARITY_ERROR;
1999130293Sscottl			break;
2000130293Sscottl		case SEND_ABORT:
2001130293Sscottl			sc->sc_flags |= NCR_ABORTING;
2002130293Sscottl			sc->sc_omess[0] = MSG_ABORT;
2003130293Sscottl			break;
2004130293Sscottl		case SEND_INIT_DET_ERR:
2005130293Sscottl			sc->sc_omess[0] = MSG_INITIATOR_DET_ERR;
2006130293Sscottl			break;
2007130293Sscottl		case SEND_REJECT:
2008130293Sscottl			sc->sc_omess[0] = MSG_MESSAGE_REJECT;
2009130293Sscottl			break;
2010130293Sscottl		default:
2011130293Sscottl			/*
2012130293Sscottl			 * We normally do not get here, since the chip
2013130293Sscottl			 * automatically turns off ATN before the last
2014130293Sscottl			 * byte of a message is sent to the target.
2015130293Sscottl			 * However, if the target rejects our (multi-byte)
2016130293Sscottl			 * message early by switching to MSG IN phase
2017130293Sscottl			 * ATN remains on, so the target may return to
2018130293Sscottl			 * MSG OUT phase. If there are no scheduled messages
2019130293Sscottl			 * left we send a NO-OP.
2020130293Sscottl			 *
2021130293Sscottl			 * XXX - Note that this leaves no useful purpose for
2022130293Sscottl			 * the NCR_ATN flag.
2023130293Sscottl			 */
2024130293Sscottl			sc->sc_flags &= ~NCR_ATN;
2025130293Sscottl			sc->sc_omess[0] = MSG_NOOP;
2026130293Sscottl			break;
2027130293Sscottl		}
2028130293Sscottl		sc->sc_omp = sc->sc_omess;
2029130293Sscottl	}
2030130293Sscottl
2031130293Sscottl#ifdef DEBUG
2032130293Sscottl	if (ncr53c9x_debug & NCR_SHOWMSGS) {
2033130293Sscottl		int i;
2034145202Smarius
2035130293Sscottl		NCR_MSGS(("<msgout:"));
2036145202Smarius		for (i = 0; i < sc->sc_omlen; i++)
2037130293Sscottl			NCR_MSGS((" %02x", sc->sc_omess[i]));
2038130293Sscottl		NCR_MSGS(("> "));
2039130293Sscottl	}
2040130293Sscottl#endif
2041130293Sscottl	if (sc->sc_rev == NCR_VARIANT_FAS366) {
2042145202Smarius		/*
2043130293Sscottl		 * XXX fifo size
2044130293Sscottl		 */
2045130293Sscottl		ncr53c9x_flushfifo(sc);
2046130293Sscottl		ncr53c9x_wrfifo(sc, sc->sc_omp, sc->sc_omlen);
2047130293Sscottl		NCRCMD(sc, NCRCMD_TRANS);
2048130293Sscottl	} else {
2049130293Sscottl		/* (re)send the message */
2050130293Sscottl		size = min(sc->sc_omlen, sc->sc_maxxfer);
2051130293Sscottl		NCRDMA_SETUP(sc, &sc->sc_omp, &sc->sc_omlen, 0, &size);
2052130293Sscottl		/* Program the SCSI counter */
2053130293Sscottl		NCR_SET_COUNT(sc, size);
2054130293Sscottl
2055130293Sscottl		/* Load the count in and start the message-out transfer */
2056130293Sscottl		NCRCMD(sc, NCRCMD_NOP|NCRCMD_DMA);
2057130293Sscottl		NCRCMD(sc, NCRCMD_TRANS|NCRCMD_DMA);
2058130293Sscottl		NCRDMA_GO(sc);
2059130293Sscottl	}
2060130293Sscottl}
2061130293Sscottl
2062130293Sscottl/*
2063130293Sscottl * This is the most critical part of the driver, and has to know
2064130293Sscottl * how to deal with *all* error conditions and phases from the SCSI
2065130293Sscottl * bus. If there are no errors and the DMA was active, then call the
2066130293Sscottl * DMA pseudo-interrupt handler. If this returns 1, then that was it
2067130293Sscottl * and we can return from here without further processing.
2068130293Sscottl *
2069130293Sscottl * Most of this needs verifying.
2070130293Sscottl */
2071130293Sscottlvoid
2072130293Sscottlncr53c9x_intr(void *arg)
2073130293Sscottl{
2074130293Sscottl	struct ncr53c9x_softc *sc = arg;
2075130293Sscottl	struct ncr53c9x_ecb *ecb;
2076130293Sscottl	struct ncr53c9x_tinfo *ti;
2077130293Sscottl	size_t size;
2078130293Sscottl	int nfifo;
2079130293Sscottl
2080130293Sscottl	NCR_INTS(("[ncr53c9x_intr: state %d]", sc->sc_state));
2081130293Sscottl
2082130293Sscottl	if (!NCRDMA_ISINTR(sc))
2083130293Sscottl		return;
2084130293Sscottl
2085130293Sscottl	mtx_lock(&sc->sc_lock);
2086130293Sscottlagain:
2087130293Sscottl	/* and what do the registers say... */
2088130293Sscottl	ncr53c9x_readregs(sc);
2089130293Sscottl
2090130293Sscottl	/*
2091130293Sscottl	 * At the moment, only a SCSI Bus Reset or Illegal
2092130293Sscottl	 * Command are classed as errors. A disconnect is a
2093130293Sscottl	 * valid condition, and we let the code check is the
2094130293Sscottl	 * "NCR_BUSFREE_OK" flag was set before declaring it
2095130293Sscottl	 * and error.
2096130293Sscottl	 *
2097130293Sscottl	 * Also, the status register tells us about "Gross
2098130293Sscottl	 * Errors" and "Parity errors". Only the Gross Error
2099130293Sscottl	 * is really bad, and the parity errors are dealt
2100130293Sscottl	 * with later
2101130293Sscottl	 *
2102130293Sscottl	 * TODO
2103130293Sscottl	 *	If there are too many parity error, go to slow
2104130293Sscottl	 *	cable mode ?
2105130293Sscottl	 */
2106130293Sscottl
2107130293Sscottl	/* SCSI Reset */
2108130293Sscottl	if ((sc->sc_espintr & NCRINTR_SBR) != 0) {
2109130293Sscottl		if ((NCR_READ_REG(sc, NCR_FFLAG) & NCRFIFO_FF) != 0) {
2110130293Sscottl			NCRCMD(sc, NCRCMD_FLUSH);
2111130293Sscottl			DELAY(1);
2112130293Sscottl		}
2113130293Sscottl		if (sc->sc_state != NCR_SBR) {
2114130293Sscottl			device_printf(sc->sc_dev, "SCSI bus reset\n");
2115130293Sscottl			ncr53c9x_init(sc, 0); /* Restart everything */
2116130293Sscottl			goto out;
2117130293Sscottl		}
2118130293Sscottl#if 0
2119130293Sscottl/*XXX*/		printf("<expected bus reset: "
2120130293Sscottl		    "[intr %x, stat %x, step %d]>\n",
2121130293Sscottl		    sc->sc_espintr, sc->sc_espstat, sc->sc_espstep);
2122130293Sscottl#endif
2123130293Sscottl		if (sc->sc_nexus != NULL)
2124130293Sscottl			panic("%s: nexus in reset state",
2125130293Sscottl			    device_get_nameunit(sc->sc_dev));
2126130293Sscottl		goto sched;
2127130293Sscottl	}
2128130293Sscottl
2129130293Sscottl	ecb = sc->sc_nexus;
2130130293Sscottl
2131130293Sscottl#define NCRINTR_ERR (NCRINTR_SBR|NCRINTR_ILL)
2132130293Sscottl	if (sc->sc_espintr & NCRINTR_ERR ||
2133130293Sscottl	    sc->sc_espstat & NCRSTAT_GE) {
2134130293Sscottl
2135130293Sscottl		if ((sc->sc_espstat & NCRSTAT_GE) != 0) {
2136130293Sscottl			/* Gross Error; no target ? */
2137130293Sscottl			if (NCR_READ_REG(sc, NCR_FFLAG) & NCRFIFO_FF) {
2138130293Sscottl				NCRCMD(sc, NCRCMD_FLUSH);
2139130293Sscottl				DELAY(1);
2140130293Sscottl			}
2141130293Sscottl			if (sc->sc_state == NCR_CONNECTED ||
2142130293Sscottl			    sc->sc_state == NCR_SELECTING) {
2143130293Sscottl				ecb->ccb->ccb_h.status = CAM_SEL_TIMEOUT;
2144130293Sscottl				ncr53c9x_done(sc, ecb);
2145130293Sscottl			}
2146130293Sscottl			goto out;
2147130293Sscottl		}
2148130293Sscottl
2149130293Sscottl		if ((sc->sc_espintr & NCRINTR_ILL) != 0) {
2150130293Sscottl			if ((sc->sc_flags & NCR_EXPECT_ILLCMD) != 0) {
2151130293Sscottl				/*
2152130293Sscottl				 * Eat away "Illegal command" interrupt
2153130293Sscottl				 * on a ESP100 caused by a re-selection
2154130293Sscottl				 * while we were trying to select
2155130293Sscottl				 * another target.
2156130293Sscottl				 */
2157130293Sscottl#ifdef DEBUG
2158130293Sscottl				device_printf(sc->sc_dev, "ESP100 work-around "
2159130293Sscottl				    "activated\n");
2160130293Sscottl#endif
2161130293Sscottl				sc->sc_flags &= ~NCR_EXPECT_ILLCMD;
2162130293Sscottl				goto out;
2163130293Sscottl			}
2164130293Sscottl			/* illegal command, out of sync ? */
2165130293Sscottl			device_printf(sc->sc_dev, "illegal command: 0x%x "
2166130293Sscottl			    "(state %d, phase %x, prevphase %x)\n",
2167130293Sscottl			    sc->sc_lastcmd,
2168130293Sscottl			    sc->sc_state, sc->sc_phase, sc->sc_prevphase);
2169130293Sscottl			if (NCR_READ_REG(sc, NCR_FFLAG) & NCRFIFO_FF) {
2170130293Sscottl				NCRCMD(sc, NCRCMD_FLUSH);
2171130293Sscottl				DELAY(1);
2172130293Sscottl			}
2173130293Sscottl			ncr53c9x_init(sc, 1); /* Restart everything */
2174130293Sscottl			goto out;
2175130293Sscottl		}
2176130293Sscottl	}
2177130293Sscottl	sc->sc_flags &= ~NCR_EXPECT_ILLCMD;
2178130293Sscottl
2179130293Sscottl	/*
2180130293Sscottl	 * Call if DMA is active.
2181130293Sscottl	 *
2182130293Sscottl	 * If DMA_INTR returns true, then maybe go 'round the loop
2183130293Sscottl	 * again in case there is no more DMA queued, but a phase
2184130293Sscottl	 * change is expected.
2185130293Sscottl	 */
2186130293Sscottl	if (NCRDMA_ISACTIVE(sc)) {
2187130293Sscottl		int r = NCRDMA_INTR(sc);
2188130293Sscottl		if (r == -1) {
2189130293Sscottl			device_printf(sc->sc_dev, "DMA error; resetting\n");
2190130293Sscottl			ncr53c9x_init(sc, 1);
2191130293Sscottl			goto out;
2192130293Sscottl		}
2193130293Sscottl		/* If DMA active here, then go back to work... */
2194130293Sscottl		if (NCRDMA_ISACTIVE(sc))
2195130293Sscottl			goto out;
2196130293Sscottl
2197130293Sscottl		if ((sc->sc_espstat & NCRSTAT_TC) == 0) {
2198130293Sscottl			/*
2199130293Sscottl			 * DMA not completed.  If we can not find a
2200130293Sscottl			 * acceptable explanation, print a diagnostic.
2201130293Sscottl			 */
2202130293Sscottl			if (sc->sc_state == NCR_SELECTING)
2203130293Sscottl				/*
2204130293Sscottl				 * This can happen if we are reselected
2205130293Sscottl				 * while using DMA to select a target.
2206130293Sscottl				 */
2207130293Sscottl				/*void*/;
2208130293Sscottl			else if (sc->sc_prevphase == MESSAGE_OUT_PHASE) {
2209130293Sscottl				/*
2210130293Sscottl				 * Our (multi-byte) message (eg SDTR) was
2211130293Sscottl				 * interrupted by the target to send
2212130293Sscottl				 * a MSG REJECT.
2213130293Sscottl				 * Print diagnostic if current phase
2214130293Sscottl				 * is not MESSAGE IN.
2215130293Sscottl				 */
2216130293Sscottl				if (sc->sc_phase != MESSAGE_IN_PHASE)
2217130293Sscottl					device_printf(sc->sc_dev,"!TC on MSGOUT"
2218130293Sscottl					    " [intr %x, stat %x, step %d]"
2219130293Sscottl					    " prevphase %x, resid %lx\n",
2220130293Sscottl					    sc->sc_espintr,
2221130293Sscottl					    sc->sc_espstat,
2222130293Sscottl					    sc->sc_espstep,
2223130293Sscottl					    sc->sc_prevphase,
2224130293Sscottl					    (u_long)sc->sc_omlen);
2225130293Sscottl			} else if (sc->sc_dleft == 0) {
2226130293Sscottl				/*
2227130293Sscottl				 * The DMA operation was started for
2228130293Sscottl				 * a DATA transfer. Print a diagnostic
2229130293Sscottl				 * if the DMA counter and TC bit
2230130293Sscottl				 * appear to be out of sync.
2231145386Sscottl				 *
2232145386Sscottl				 * XXX This is fatal and usually means that
2233145386Sscottl				 *     the DMA engine is hopelessly out of
2234145386Sscottl				 *     sync with reality.  A disk is likely
2235145386Sscottl				 *     getting spammed at this point.
2236130293Sscottl				 */
2237130293Sscottl				device_printf(sc->sc_dev, "!TC on DATA XFER"
2238130293Sscottl				    " [intr %x, stat %x, step %d]"
2239130293Sscottl				    " prevphase %x, resid %x\n",
2240130293Sscottl				    sc->sc_espintr,
2241130293Sscottl				    sc->sc_espstat,
2242130293Sscottl				    sc->sc_espstep,
2243130293Sscottl				    sc->sc_prevphase,
2244130293Sscottl				    ecb ? ecb->dleft : -1);
2245145386Sscottl				panic("esp: unrecoverable DMA error");
2246130293Sscottl			}
2247130293Sscottl		}
2248130293Sscottl	}
2249130293Sscottl
2250130293Sscottl	/*
2251130293Sscottl	 * Check for less serious errors.
2252130293Sscottl	 */
2253130293Sscottl	if ((sc->sc_espstat & NCRSTAT_PE) != 0) {
2254130293Sscottl		device_printf(sc->sc_dev, "SCSI bus parity error\n");
2255130293Sscottl		if (sc->sc_prevphase == MESSAGE_IN_PHASE)
2256130293Sscottl			ncr53c9x_sched_msgout(SEND_PARITY_ERROR);
2257130293Sscottl		else
2258130293Sscottl			ncr53c9x_sched_msgout(SEND_INIT_DET_ERR);
2259130293Sscottl	}
2260130293Sscottl
2261130293Sscottl	if ((sc->sc_espintr & NCRINTR_DIS) != 0) {
2262130293Sscottl		sc->sc_msgify = 0;
2263130293Sscottl		NCR_INTS(("<DISC [intr %x, stat %x, step %d]>",
2264130293Sscottl		    sc->sc_espintr,sc->sc_espstat,sc->sc_espstep));
2265130293Sscottl		if (NCR_READ_REG(sc, NCR_FFLAG) & NCRFIFO_FF) {
2266130293Sscottl			NCRCMD(sc, NCRCMD_FLUSH);
2267130293Sscottl/*			DELAY(1); */
2268130293Sscottl		}
2269130293Sscottl		/*
2270130293Sscottl		 * This command must (apparently) be issued within
2271130293Sscottl		 * 250mS of a disconnect. So here you are...
2272130293Sscottl		 */
2273130293Sscottl		NCRCMD(sc, NCRCMD_ENSEL);
2274130293Sscottl
2275130293Sscottl		switch (sc->sc_state) {
2276130293Sscottl		case NCR_RESELECTED:
2277130293Sscottl			goto sched;
2278130293Sscottl
2279130293Sscottl		case NCR_SELECTING:
2280130293Sscottl		{
2281130293Sscottl			struct ncr53c9x_linfo *li;
2282130293Sscottl
2283130293Sscottl			ecb->ccb->ccb_h.status = CAM_SEL_TIMEOUT;
2284130293Sscottl
2285130293Sscottl			/* Selection timeout -- discard all LUNs if empty */
2286130293Sscottl			ti = &sc->sc_tinfo[ecb->ccb->ccb_h.target_id];
2287130293Sscottl			li = LIST_FIRST(&ti->luns);
2288130293Sscottl			while (li != NULL) {
2289130293Sscottl				if (li->untagged == NULL && li->used == 0) {
2290130293Sscottl					if (li->lun < NCR_NLUN)
2291130293Sscottl						ti->lun[li->lun] = NULL;
2292130293Sscottl					LIST_REMOVE(li, link);
2293130293Sscottl					free(li, M_DEVBUF);
2294130293Sscottl					/*
2295130293Sscottl					 * Restart the search at the beginning
2296130293Sscottl					 */
2297130293Sscottl					li = LIST_FIRST(&ti->luns);
2298130293Sscottl					continue;
2299130293Sscottl				}
2300130293Sscottl				li = LIST_NEXT(li, link);
2301130293Sscottl			}
2302130293Sscottl			goto finish;
2303130293Sscottl		}
2304130293Sscottl		case NCR_CONNECTED:
2305130293Sscottl			if ((sc->sc_flags & NCR_SYNCHNEGO) != 0) {
2306130293Sscottl#ifdef NCR53C9X_DEBUG
2307130293Sscottl				if (ecb != NULL)
2308130293Sscottl					xpt_print_path(ecb->ccb->ccb_h.path);
2309130293Sscottl				printf("sync nego not completed!\n");
2310130293Sscottl#endif
2311130293Sscottl				ti = &sc->sc_tinfo[ecb->ccb->ccb_h.target_id];
2312130293Sscottl				sc->sc_flags &= ~NCR_SYNCHNEGO;
2313130293Sscottl				ti->flags &= ~(T_NEGOTIATE | T_SYNCMODE);
2314130293Sscottl			}
2315130293Sscottl
2316130293Sscottl			/* it may be OK to disconnect */
2317130293Sscottl			if ((sc->sc_flags & NCR_ABORTING) == 0) {
2318130293Sscottl				/*
2319130293Sscottl				 * Section 5.1.1 of the SCSI 2 spec
2320130293Sscottl				 * suggests issuing a REQUEST SENSE
2321130293Sscottl				 * following an unexpected disconnect.
2322130293Sscottl				 * Some devices go into a contingent
2323130293Sscottl				 * allegiance condition when
2324130293Sscottl				 * disconnecting, and this is necessary
2325130293Sscottl				 * to clean up their state.
2326130293Sscottl				 */
2327130293Sscottl				device_printf(sc->sc_dev, "unexpected "
2328130293Sscottl				    "disconnect [state %d, intr %x, stat %x, "
2329130293Sscottl				    "phase(c %x, p %x)]; ", sc->sc_state,
2330130293Sscottl				    sc->sc_espintr, sc->sc_espstat,
2331130293Sscottl				    sc->sc_phase, sc->sc_prevphase);
2332130293Sscottl
2333130293Sscottl				if ((ecb->flags & ECB_SENSE) != 0) {
2334130293Sscottl					printf("resetting\n");
2335130293Sscottl					goto reset;
2336130293Sscottl				}
2337130293Sscottl				printf("sending REQUEST SENSE\n");
2338130424Sscottl				untimeout(ncr53c9x_timeout, ecb,
2339130293Sscottl					  ecb->ccb->ccb_h.timeout_ch);
2340130293Sscottl				ncr53c9x_sense(sc, ecb);
2341130293Sscottl				goto out;
2342130293Sscottl			}
2343130293Sscottl
2344130293Sscottl			ecb->ccb->ccb_h.status = CAM_CMD_TIMEOUT;
2345130293Sscottl			goto finish;
2346130293Sscottl
2347130293Sscottl		case NCR_DISCONNECT:
2348130293Sscottl			sc->sc_nexus = NULL;
2349130293Sscottl			goto sched;
2350130293Sscottl
2351130293Sscottl		case NCR_CMDCOMPLETE:
2352130293Sscottl			ecb->ccb->ccb_h.status = CAM_REQ_CMP;
2353130293Sscottl			goto finish;
2354130293Sscottl		}
2355130293Sscottl	}
2356130293Sscottl
2357130293Sscottl	switch (sc->sc_state) {
2358130293Sscottl
2359130293Sscottl	case NCR_SBR:
2360130293Sscottl		device_printf(sc->sc_dev, "waiting for Bus Reset to happen\n");
2361130293Sscottl		goto out;
2362130293Sscottl
2363130293Sscottl	case NCR_RESELECTED:
2364130293Sscottl		/*
2365130293Sscottl		 * we must be continuing a message ?
2366130293Sscottl		 */
2367130293Sscottl		device_printf(sc->sc_dev, "unhandled reselect continuation, "
2368130293Sscottl			"state %d, intr %02x\n", sc->sc_state, sc->sc_espintr);
2369130293Sscottl		ncr53c9x_init(sc, 1);
2370130293Sscottl		goto out;
2371130293Sscottl		break;
2372130293Sscottl
2373130293Sscottl	case NCR_IDENTIFIED:
2374130293Sscottl		ecb = sc->sc_nexus;
2375130293Sscottl		if (sc->sc_phase != MESSAGE_IN_PHASE) {
2376130293Sscottl			int i = (NCR_READ_REG(sc, NCR_FFLAG) & NCRFIFO_FF);
2377130293Sscottl 			/*
2378145202Smarius			 * Things are seriously screwed up.
2379130293Sscottl			 * Pull the brakes, i.e. reset
2380130293Sscottl			 */
2381130293Sscottl			device_printf(sc->sc_dev, "target didn't send tag: %d "
2382130293Sscottl			    "bytes in fifo\n", i);
2383130293Sscottl			/* Drain and display fifo */
2384130293Sscottl			while (i-- > 0)
2385130293Sscottl				printf("[%d] ", NCR_READ_REG(sc, NCR_FIFO));
2386130293Sscottl
2387130293Sscottl			ncr53c9x_init(sc, 1);
2388130293Sscottl			goto out;
2389130293Sscottl		} else
2390130293Sscottl			goto msgin;
2391130293Sscottl
2392130293Sscottl	case NCR_IDLE:
2393130293Sscottl	case NCR_SELECTING:
2394130293Sscottl		ecb = sc->sc_nexus;
2395130293Sscottl		if (sc->sc_espintr & NCRINTR_RESEL) {
2396130293Sscottl			sc->sc_msgpriq = sc->sc_msgout = sc->sc_msgoutq = 0;
2397130293Sscottl			sc->sc_flags = 0;
2398130293Sscottl			/*
2399130293Sscottl			 * If we're trying to select a
2400130293Sscottl			 * target ourselves, push our command
2401130293Sscottl			 * back into the ready list.
2402130293Sscottl			 */
2403130293Sscottl			if (sc->sc_state == NCR_SELECTING) {
2404130293Sscottl				NCR_INTS(("backoff selector "));
2405130424Sscottl				untimeout(ncr53c9x_timeout, ecb,
2406130293Sscottl					  ecb->ccb->ccb_h.timeout_ch);
2407130293Sscottl				ncr53c9x_dequeue(sc, ecb);
2408130293Sscottl				TAILQ_INSERT_HEAD(&sc->ready_list, ecb, chain);
2409130293Sscottl				ecb->flags |= ECB_READY;
2410130293Sscottl				ecb = sc->sc_nexus = NULL;
2411130293Sscottl			}
2412130293Sscottl			sc->sc_state = NCR_RESELECTED;
2413130293Sscottl			if (sc->sc_phase != MESSAGE_IN_PHASE) {
2414130293Sscottl				/*
2415145202Smarius				 * Things are seriously screwed up.
2416130293Sscottl				 * Pull the brakes, i.e. reset
2417130293Sscottl				 */
2418130293Sscottl				device_printf(sc->sc_dev, "target didn't "
2419130293Sscottl				    "identify\n");
2420130293Sscottl				ncr53c9x_init(sc, 1);
2421130293Sscottl				goto out;
2422130293Sscottl			}
2423130293Sscottl			/*
2424130293Sscottl			 * The C90 only inhibits FIFO writes until reselection
2425133039Strhodes			 * is complete instead of waiting until the interrupt
2426130293Sscottl			 * status register has been read.  So, if the reselect
2427130293Sscottl			 * happens while we were entering command bytes (for
2428130293Sscottl			 * another target) some of those bytes can appear in
2429130293Sscottl			 * the FIFO here, after the interrupt is taken.
2430130293Sscottl			 *
2431130293Sscottl			 * To remedy this situation, pull the Selection ID
2432130293Sscottl			 * and Identify message from the FIFO directly, and
2433130293Sscottl			 * ignore any extraneous fifo contents. Also, set
2434130293Sscottl			 * a flag that allows one Illegal Command Interrupt
2435130293Sscottl			 * to occur which the chip also generates as a result
2436130293Sscottl			 * of writing to the FIFO during a reselect.
2437130293Sscottl			 */
2438130293Sscottl			if (sc->sc_rev == NCR_VARIANT_ESP100) {
2439130293Sscottl				nfifo = NCR_READ_REG(sc, NCR_FFLAG) & NCRFIFO_FF;
2440130293Sscottl				sc->sc_imess[0] = NCR_READ_REG(sc, NCR_FIFO);
2441130293Sscottl				sc->sc_imess[1] = NCR_READ_REG(sc, NCR_FIFO);
2442130293Sscottl				sc->sc_imlen = 2;
2443130293Sscottl				if (nfifo != 2) {
2444130293Sscottl					/* Flush the rest */
2445130293Sscottl					NCRCMD(sc, NCRCMD_FLUSH);
2446130293Sscottl				}
2447130293Sscottl				sc->sc_flags |= NCR_EXPECT_ILLCMD;
2448130293Sscottl				if (nfifo > 2)
2449130293Sscottl					nfifo = 2; /* We fixed it.. */
2450130293Sscottl			} else
2451130293Sscottl				nfifo = ncr53c9x_rdfifo(sc, NCR_RDFIFO_START);
2452130293Sscottl
2453130293Sscottl			if (nfifo != 2) {
2454130293Sscottl				device_printf(sc->sc_dev, "RESELECT: %d bytes "
2455130293Sscottl				    "in FIFO! [intr %x, stat %x, step %d, "
2456130293Sscottl				    "prevphase %x]\n",
2457130293Sscottl				    nfifo,
2458130293Sscottl				    sc->sc_espintr,
2459130293Sscottl				    sc->sc_espstat,
2460130293Sscottl				    sc->sc_espstep,
2461130293Sscottl				    sc->sc_prevphase);
2462130293Sscottl				ncr53c9x_init(sc, 1);
2463130293Sscottl				goto out;
2464130293Sscottl			}
2465130293Sscottl			sc->sc_selid = sc->sc_imess[0];
2466130293Sscottl			NCR_INTS(("selid=%02x ", sc->sc_selid));
2467130293Sscottl
2468130293Sscottl			/* Handle identify message */
2469130293Sscottl			ncr53c9x_msgin(sc);
2470130293Sscottl
2471130293Sscottl			if (sc->sc_state != NCR_CONNECTED &&
2472130293Sscottl			    sc->sc_state != NCR_IDENTIFIED) {
2473130293Sscottl				/* IDENTIFY fail?! */
2474130293Sscottl				device_printf(sc->sc_dev, "identify failed, "
2475130293Sscottl				    "state %d, intr %02x\n", sc->sc_state,
2476130293Sscottl				    sc->sc_espintr);
2477130293Sscottl				ncr53c9x_init(sc, 1);
2478130293Sscottl				goto out;
2479130293Sscottl			}
2480130293Sscottl			goto shortcut; /* ie. next phase expected soon */
2481130293Sscottl		}
2482130293Sscottl
2483130293Sscottl#define	NCRINTR_DONE	(NCRINTR_FC|NCRINTR_BS)
2484130293Sscottl		if ((sc->sc_espintr & NCRINTR_DONE) == NCRINTR_DONE) {
2485130293Sscottl			/*
2486130293Sscottl			 * Arbitration won; examine the `step' register
2487130293Sscottl			 * to determine how far the selection could progress.
2488130293Sscottl			 */
2489130293Sscottl			ecb = sc->sc_nexus;
2490130293Sscottl			if (ecb == NULL)
2491130293Sscottl				panic("ncr53c9x: no nexus");
2492130293Sscottl
2493130293Sscottl			ti = &sc->sc_tinfo[ecb->ccb->ccb_h.target_id];
2494130293Sscottl
2495130293Sscottl			switch (sc->sc_espstep) {
2496130293Sscottl			case 0:
2497130293Sscottl				/*
2498130293Sscottl				 * The target did not respond with a
2499130293Sscottl				 * message out phase - probably an old
2500130293Sscottl				 * device that doesn't recognize ATN.
2501130293Sscottl				 * Clear ATN and just continue, the
2502130293Sscottl				 * target should be in the command
2503130293Sscottl				 * phase.
2504130293Sscottl				 * XXXX check for command phase?
2505130293Sscottl				 */
2506130293Sscottl				NCRCMD(sc, NCRCMD_RSTATN);
2507130293Sscottl				break;
2508130293Sscottl			case 1:
2509130293Sscottl				if ((ti->flags & T_NEGOTIATE) == 0 &&
2510130293Sscottl				    ecb->tag[0] == 0) {
2511130293Sscottl					device_printf(sc->sc_dev, "step 1 & "
2512130293Sscottl					    "!NEG\n");
2513130293Sscottl					goto reset;
2514130293Sscottl				}
2515130293Sscottl				if (sc->sc_phase != MESSAGE_OUT_PHASE) {
2516130293Sscottl					device_printf(sc->sc_dev, "!MSGOUT\n");
2517130293Sscottl					goto reset;
2518130293Sscottl				}
2519130293Sscottl				if (ti->flags & T_WIDE) {
2520130293Sscottl					ti->flags |= T_WDTRSENT;
2521130293Sscottl					ncr53c9x_sched_msgout(SEND_WDTR);
2522130293Sscottl				}
2523130293Sscottl				if (ti->flags & T_NEGOTIATE) {
2524130293Sscottl					/* Start negotiating */
2525130293Sscottl					sc->sc_flags |= NCR_SYNCHNEGO;
2526130293Sscottl					if (ecb->tag[0])
2527130293Sscottl						ncr53c9x_sched_msgout(
2528130293Sscottl						    SEND_TAG|SEND_SDTR);
2529130293Sscottl					else
2530130293Sscottl						ncr53c9x_sched_msgout(
2531130293Sscottl						    SEND_SDTR);
2532130293Sscottl				} else {
2533130293Sscottl					/* Could not do ATN3 so send TAG */
2534130293Sscottl					ncr53c9x_sched_msgout(SEND_TAG);
2535130293Sscottl				}
2536130293Sscottl				sc->sc_prevphase = MESSAGE_OUT_PHASE; /* XXXX */
2537130293Sscottl				break;
2538130293Sscottl			case 3:
2539130293Sscottl				/*
2540130293Sscottl				 * Grr, this is supposed to mean
2541130293Sscottl				 * "target left command phase  prematurely".
2542130293Sscottl				 * It seems to happen regularly when
2543130293Sscottl				 * sync mode is on.
2544130293Sscottl				 * Look at FIFO to see if command went out.
2545130293Sscottl				 * (Timing problems?)
2546130293Sscottl				 */
2547130293Sscottl				if (sc->sc_features & NCR_F_DMASELECT) {
2548130293Sscottl					if (sc->sc_cmdlen == 0)
2549130293Sscottl						/* Hope for the best.. */
2550130293Sscottl						break;
2551130293Sscottl				} else if ((NCR_READ_REG(sc, NCR_FFLAG)
2552130293Sscottl				    & NCRFIFO_FF) == 0) {
2553130293Sscottl					/* Hope for the best.. */
2554130293Sscottl					break;
2555130293Sscottl				}
2556130293Sscottl				printf("(%s:%d:%d): selection failed;"
2557130293Sscottl				    " %d left in FIFO "
2558130293Sscottl				    "[intr %x, stat %x, step %d]\n",
2559130293Sscottl				    device_get_nameunit(sc->sc_dev),
2560130293Sscottl				    ecb->ccb->ccb_h.target_id,
2561130293Sscottl				    ecb->ccb->ccb_h.target_lun,
2562130293Sscottl				    NCR_READ_REG(sc, NCR_FFLAG)
2563130293Sscottl				     & NCRFIFO_FF,
2564130293Sscottl				    sc->sc_espintr, sc->sc_espstat,
2565130293Sscottl				    sc->sc_espstep);
2566130293Sscottl				NCRCMD(sc, NCRCMD_FLUSH);
2567130293Sscottl				ncr53c9x_sched_msgout(SEND_ABORT);
2568130293Sscottl				goto out;
2569130293Sscottl			case 2:
2570130293Sscottl				/* Select stuck at Command Phase */
2571130293Sscottl				NCRCMD(sc, NCRCMD_FLUSH);
2572130293Sscottl				break;
2573130293Sscottl			case 4:
2574130293Sscottl				if (sc->sc_features & NCR_F_DMASELECT &&
2575130293Sscottl				    sc->sc_cmdlen != 0)
2576130293Sscottl					printf("(%s:%d:%d): select; "
2577130293Sscottl					    "%lu left in DMA buffer "
2578130293Sscottl					    "[intr %x, stat %x, step %d]\n",
2579130293Sscottl					    device_get_nameunit(sc->sc_dev),
2580130293Sscottl					    ecb->ccb->ccb_h.target_id,
2581130293Sscottl					    ecb->ccb->ccb_h.target_lun,
2582130293Sscottl					    (u_long)sc->sc_cmdlen,
2583130293Sscottl					    sc->sc_espintr,
2584130293Sscottl					    sc->sc_espstat,
2585130293Sscottl					    sc->sc_espstep);
2586130293Sscottl				/* So far, everything went fine */
2587130293Sscottl				break;
2588130293Sscottl			}
2589130293Sscottl
2590130293Sscottl			sc->sc_prevphase = INVALID_PHASE; /* ?? */
2591130293Sscottl			/* Do an implicit RESTORE POINTERS. */
2592130293Sscottl			sc->sc_dp = ecb->daddr;
2593130293Sscottl			sc->sc_dleft = ecb->dleft;
2594130293Sscottl			sc->sc_state = NCR_CONNECTED;
2595130293Sscottl			break;
2596130293Sscottl
2597130293Sscottl		} else {
2598130293Sscottl
2599130293Sscottl			device_printf(sc->sc_dev, "unexpected status after "
2600130293Sscottl			    "select: [intr %x, stat %x, step %x]\n",
2601130293Sscottl			    sc->sc_espintr, sc->sc_espstat, sc->sc_espstep);
2602130293Sscottl			NCRCMD(sc, NCRCMD_FLUSH);
2603130293Sscottl			DELAY(1);
2604130293Sscottl			goto reset;
2605130293Sscottl		}
2606130293Sscottl		if (sc->sc_state == NCR_IDLE) {
2607130293Sscottl			device_printf(sc->sc_dev, "stray interrupt\n");
2608130293Sscottl			mtx_unlock(&sc->sc_lock);
2609130293Sscottl			return;
2610130293Sscottl		}
2611130293Sscottl		break;
2612130293Sscottl
2613130293Sscottl	case NCR_CONNECTED:
2614130293Sscottl		if ((sc->sc_flags & NCR_ICCS) != 0) {
2615130293Sscottl			/* "Initiate Command Complete Steps" in progress */
2616130293Sscottl			u_char msg;
2617130293Sscottl
2618130293Sscottl			sc->sc_flags &= ~NCR_ICCS;
2619130293Sscottl
2620130293Sscottl			if (!(sc->sc_espintr & NCRINTR_DONE)) {
2621130293Sscottl				device_printf(sc->sc_dev, "ICCS: "
2622130293Sscottl				    ": [intr %x, stat %x, step %x]\n",
2623130293Sscottl				    sc->sc_espintr, sc->sc_espstat,
2624130293Sscottl				    sc->sc_espstep);
2625130293Sscottl			}
2626130293Sscottl			ncr53c9x_rdfifo(sc, NCR_RDFIFO_START);
2627130293Sscottl			if (sc->sc_imlen < 2)
2628130293Sscottl				device_printf(sc->sc_dev, "can't get status, "
2629130293Sscottl				    "only %d bytes\n", (int)sc->sc_imlen);
2630130293Sscottl			ecb->stat = sc->sc_imess[sc->sc_imlen - 2];
2631130293Sscottl			msg = sc->sc_imess[sc->sc_imlen - 1];
2632130293Sscottl			NCR_PHASE(("<stat:(%x,%x)>", ecb->stat, msg));
2633130293Sscottl			if (msg == MSG_CMDCOMPLETE) {
2634130293Sscottl				ecb->dleft = (ecb->flags & ECB_TENTATIVE_DONE)
2635130293Sscottl					? 0 : sc->sc_dleft;
2636130293Sscottl				if ((ecb->flags & ECB_SENSE) == 0)
2637130293Sscottl					ecb->ccb->csio.resid = ecb->dleft;
2638130293Sscottl				sc->sc_state = NCR_CMDCOMPLETE;
2639130293Sscottl			} else
2640130293Sscottl				device_printf(sc->sc_dev, "STATUS_PHASE: "
2641130293Sscottl				    "msg %d\n", msg);
2642130293Sscottl			sc->sc_imlen = 0;
2643130293Sscottl			NCRCMD(sc, NCRCMD_MSGOK);
2644130293Sscottl			goto shortcut; /* ie. wait for disconnect */
2645130293Sscottl		}
2646130293Sscottl		break;
2647130293Sscottl
2648130293Sscottl	default:
2649130293Sscottl		device_printf(sc->sc_dev, "invalid state: %d [intr %x, "
2650130293Sscottl		    "phase(c %x, p %x)]\n", sc->sc_state,
2651130293Sscottl		    sc->sc_espintr, sc->sc_phase, sc->sc_prevphase);
2652130293Sscottl		goto reset;
2653130293Sscottl	}
2654130293Sscottl
2655130293Sscottl	/*
2656130293Sscottl	 * Driver is now in state NCR_CONNECTED, i.e. we
2657130293Sscottl	 * have a current command working the SCSI bus.
2658130293Sscottl	 */
2659130293Sscottl	if (sc->sc_state != NCR_CONNECTED || ecb == NULL) {
2660130293Sscottl		panic("ncr53c9x: no nexus");
2661130293Sscottl	}
2662130293Sscottl
2663130293Sscottl	switch (sc->sc_phase) {
2664130293Sscottl	case MESSAGE_OUT_PHASE:
2665130293Sscottl		NCR_PHASE(("MESSAGE_OUT_PHASE "));
2666130293Sscottl		ncr53c9x_msgout(sc);
2667130293Sscottl		sc->sc_prevphase = MESSAGE_OUT_PHASE;
2668130293Sscottl		break;
2669130293Sscottl
2670130293Sscottl	case MESSAGE_IN_PHASE:
2671130293Sscottlmsgin:
2672130293Sscottl		NCR_PHASE(("MESSAGE_IN_PHASE "));
2673130293Sscottl		if ((sc->sc_espintr & NCRINTR_BS) != 0) {
2674130293Sscottl			if ((sc->sc_rev != NCR_VARIANT_FAS366) ||
2675130293Sscottl			    !(sc->sc_espstat2 & NCRFAS_STAT2_EMPTY)) {
2676130293Sscottl				NCRCMD(sc, NCRCMD_FLUSH);
2677130293Sscottl			}
2678130293Sscottl			sc->sc_flags |= NCR_WAITI;
2679130293Sscottl			NCRCMD(sc, NCRCMD_TRANS);
2680130293Sscottl		} else if ((sc->sc_espintr & NCRINTR_FC) != 0) {
2681130293Sscottl			if ((sc->sc_flags & NCR_WAITI) == 0) {
2682130293Sscottl				device_printf(sc->sc_dev, "MSGIN: unexpected "
2683130293Sscottl				    "FC bit: [intr %x, stat %x, step %x]\n",
2684130293Sscottl				    sc->sc_espintr, sc->sc_espstat,
2685130293Sscottl				    sc->sc_espstep);
2686130293Sscottl			}
2687130293Sscottl			sc->sc_flags &= ~NCR_WAITI;
2688130293Sscottl			ncr53c9x_rdfifo(sc,
2689145202Smarius			    (sc->sc_prevphase == sc->sc_phase) ?
2690130293Sscottl			    NCR_RDFIFO_CONTINUE : NCR_RDFIFO_START);
2691130293Sscottl			ncr53c9x_msgin(sc);
2692130293Sscottl		} else {
2693130293Sscottl			device_printf(sc->sc_dev, "MSGIN: weird bits: "
2694130293Sscottl			    "[intr %x, stat %x, step %x]\n",
2695130293Sscottl			    sc->sc_espintr, sc->sc_espstat, sc->sc_espstep);
2696130293Sscottl		}
2697130293Sscottl		sc->sc_prevphase = MESSAGE_IN_PHASE;
2698130293Sscottl		goto shortcut;	/* i.e. expect data to be ready */
2699130293Sscottl
2700130293Sscottl	case COMMAND_PHASE:
2701130293Sscottl		/*
2702130293Sscottl		 * Send the command block. Normally we don't see this
2703130293Sscottl		 * phase because the SEL_ATN command takes care of
2704130293Sscottl		 * all this. However, we end up here if either the
2705130293Sscottl		 * target or we wanted to exchange some more messages
2706130293Sscottl		 * first (e.g. to start negotiations).
2707130293Sscottl		 */
2708130293Sscottl
2709130293Sscottl		NCR_PHASE(("COMMAND_PHASE 0x%02x (%d) ",
2710130293Sscottl		    ecb->cmd.cmd.opcode, ecb->clen));
2711130293Sscottl		if (NCR_READ_REG(sc, NCR_FFLAG) & NCRFIFO_FF) {
2712130293Sscottl			NCRCMD(sc, NCRCMD_FLUSH);
2713130293Sscottl/*			DELAY(1);*/
2714130293Sscottl		}
2715130293Sscottl		if (sc->sc_features & NCR_F_DMASELECT) {
2716130293Sscottl			/* setup DMA transfer for command */
2717130293Sscottl			size = ecb->clen;
2718130293Sscottl			sc->sc_cmdlen = size;
2719130293Sscottl			sc->sc_cmdp = (caddr_t)&ecb->cmd.cmd;
2720130293Sscottl			NCRDMA_SETUP(sc, &sc->sc_cmdp, &sc->sc_cmdlen,
2721130293Sscottl			    0, &size);
2722130293Sscottl			/* Program the SCSI counter */
2723130293Sscottl			NCR_SET_COUNT(sc, size);
2724130293Sscottl
2725130293Sscottl			/* load the count in */
2726130293Sscottl			NCRCMD(sc, NCRCMD_NOP|NCRCMD_DMA);
2727130293Sscottl
2728130293Sscottl			/* start the command transfer */
2729130293Sscottl			NCRCMD(sc, NCRCMD_TRANS | NCRCMD_DMA);
2730130293Sscottl			NCRDMA_GO(sc);
2731130293Sscottl		} else {
2732130293Sscottl			ncr53c9x_wrfifo(sc, (u_char *)&ecb->cmd.cmd, ecb->clen);
2733130293Sscottl			NCRCMD(sc, NCRCMD_TRANS);
2734130293Sscottl		}
2735130293Sscottl		sc->sc_prevphase = COMMAND_PHASE;
2736130293Sscottl		break;
2737130293Sscottl
2738130293Sscottl	case DATA_OUT_PHASE:
2739130293Sscottl		NCR_PHASE(("DATA_OUT_PHASE [%ld] ",(long)sc->sc_dleft));
2740130293Sscottl		NCRCMD(sc, NCRCMD_FLUSH);
2741130293Sscottl		size = min(sc->sc_dleft, sc->sc_maxxfer);
2742130293Sscottl		NCRDMA_SETUP(sc, &sc->sc_dp, &sc->sc_dleft, 0, &size);
2743130293Sscottl		sc->sc_prevphase = DATA_OUT_PHASE;
2744130293Sscottl		goto setup_xfer;
2745130293Sscottl
2746130293Sscottl	case DATA_IN_PHASE:
2747130293Sscottl		NCR_PHASE(("DATA_IN_PHASE "));
2748130293Sscottl		if (sc->sc_rev == NCR_VARIANT_ESP100)
2749130293Sscottl			NCRCMD(sc, NCRCMD_FLUSH);
2750130293Sscottl		size = min(sc->sc_dleft, sc->sc_maxxfer);
2751130293Sscottl		NCRDMA_SETUP(sc, &sc->sc_dp, &sc->sc_dleft, 1, &size);
2752130293Sscottl		sc->sc_prevphase = DATA_IN_PHASE;
2753130293Sscottl	setup_xfer:
2754130293Sscottl		/* Target returned to data phase: wipe "done" memory */
2755130293Sscottl		ecb->flags &= ~ECB_TENTATIVE_DONE;
2756130293Sscottl
2757130293Sscottl		/* Program the SCSI counter */
2758130293Sscottl		NCR_SET_COUNT(sc, size);
2759130293Sscottl
2760130293Sscottl		/* load the count in */
2761130293Sscottl		NCRCMD(sc, NCRCMD_NOP|NCRCMD_DMA);
2762130293Sscottl
2763130293Sscottl		/*
2764130293Sscottl		 * Note that if `size' is 0, we've already transceived
2765130293Sscottl		 * all the bytes we want but we're still in DATA PHASE.
2766130293Sscottl		 * Apparently, the device needs padding. Also, a
2767130293Sscottl		 * transfer size of 0 means "maximum" to the chip
2768130293Sscottl		 * DMA logic.
2769130293Sscottl		 */
2770130293Sscottl		NCRCMD(sc,
2771130293Sscottl		    (size == 0 ? NCRCMD_TRPAD : NCRCMD_TRANS) | NCRCMD_DMA);
2772130293Sscottl		NCRDMA_GO(sc);
2773130293Sscottl		goto out;
2774130293Sscottl
2775130293Sscottl	case STATUS_PHASE:
2776130293Sscottl		NCR_PHASE(("STATUS_PHASE "));
2777130293Sscottl		sc->sc_flags |= NCR_ICCS;
2778130293Sscottl		NCRCMD(sc, NCRCMD_ICCS);
2779130293Sscottl		sc->sc_prevphase = STATUS_PHASE;
2780130293Sscottl		goto shortcut;	/* i.e. expect status results soon */
2781130293Sscottl
2782130293Sscottl	case INVALID_PHASE:
2783130293Sscottl		break;
2784130293Sscottl
2785130293Sscottl	default:
2786130293Sscottl		device_printf(sc->sc_dev, "unexpected bus phase; resetting\n");
2787130293Sscottl		goto reset;
2788130293Sscottl	}
2789130293Sscottl
2790130293Sscottlout:
2791130293Sscottl	mtx_unlock(&sc->sc_lock);
2792130293Sscottl	return;
2793130293Sscottl
2794130293Sscottlreset:
2795130293Sscottl	ncr53c9x_init(sc, 1);
2796130293Sscottl	goto out;
2797130293Sscottl
2798130293Sscottlfinish:
2799130293Sscottl	ncr53c9x_done(sc, ecb);
2800130293Sscottl	goto out;
2801130293Sscottl
2802130293Sscottlsched:
2803130293Sscottl	sc->sc_state = NCR_IDLE;
2804130293Sscottl	ncr53c9x_sched(sc);
2805130293Sscottl	goto out;
2806130293Sscottl
2807130293Sscottlshortcut:
2808130293Sscottl	/*
2809130293Sscottl	 * The idea is that many of the SCSI operations take very little
2810130293Sscottl	 * time, and going away and getting interrupted is too high an
2811130293Sscottl	 * overhead to pay. For example, selecting, sending a message
2812130293Sscottl	 * and command and then doing some work can be done in one "pass".
2813130293Sscottl	 *
2814130293Sscottl	 * The delay is a heuristic. It is 2 when at 20MHz, 2 at 25MHz and 1
2815130293Sscottl	 * at 40MHz. This needs testing.
2816130293Sscottl	 */
2817130293Sscottl	{
2818130293Sscottl		struct timeval wait, cur;
2819130293Sscottl
2820130293Sscottl		microtime(&wait);
2821130293Sscottl		wait.tv_usec += 50 / sc->sc_freq;
2822130293Sscottl		if (wait.tv_usec > 1000000) {
2823130293Sscottl			wait.tv_sec++;
2824130293Sscottl			wait.tv_usec -= 1000000;
2825130293Sscottl		}
2826130293Sscottl		do {
2827130293Sscottl			if (NCRDMA_ISINTR(sc))
2828130293Sscottl				goto again;
2829130293Sscottl			microtime(&cur);
2830130293Sscottl		} while (cur.tv_sec <= wait.tv_sec &&
2831130293Sscottl			 cur.tv_usec <= wait.tv_usec);
2832130293Sscottl	}
2833130293Sscottl	goto out;
2834130293Sscottl}
2835130293Sscottl
2836130293Sscottlstatic void
2837130293Sscottlncr53c9x_abort(sc, ecb)
2838130293Sscottl	struct ncr53c9x_softc *sc;
2839130293Sscottl	struct ncr53c9x_ecb *ecb;
2840130293Sscottl{
2841130293Sscottl
2842130293Sscottl	/* 2 secs for the abort */
2843130293Sscottl	ecb->timeout = NCR_ABORT_TIMEOUT;
2844130293Sscottl	ecb->flags |= ECB_ABORT;
2845130293Sscottl
2846130293Sscottl	if (ecb == sc->sc_nexus) {
2847130293Sscottl		/*
2848130293Sscottl		 * If we're still selecting, the message will be scheduled
2849130293Sscottl		 * after selection is complete.
2850130293Sscottl		 */
2851130293Sscottl		if (sc->sc_state == NCR_CONNECTED)
2852130293Sscottl			ncr53c9x_sched_msgout(SEND_ABORT);
2853130293Sscottl
2854130293Sscottl		/*
2855130293Sscottl		 * Reschedule timeout.
2856130293Sscottl		 */
2857130293Sscottl		ecb->ccb->ccb_h.timeout_ch =
2858130424Sscottl		    timeout(ncr53c9x_timeout, ecb, mstohz(ecb->timeout));
2859130293Sscottl	} else {
2860130293Sscottl		/*
2861130293Sscottl		 * Just leave the command where it is.
2862130293Sscottl		 * XXX - what choice do we have but to reset the SCSI
2863130293Sscottl		 *	 eventually?
2864130293Sscottl		 */
2865130293Sscottl		if (sc->sc_state == NCR_IDLE)
2866130293Sscottl			ncr53c9x_sched(sc);
2867130293Sscottl	}
2868130293Sscottl}
2869130293Sscottl
2870130293Sscottlstatic void
2871130293Sscottlncr53c9x_timeout(void *arg)
2872130293Sscottl{
2873130293Sscottl	struct ncr53c9x_ecb *ecb = arg;
2874130293Sscottl	union ccb *ccb = ecb->ccb;
2875130293Sscottl	struct ncr53c9x_softc *sc = ecb->sc;
2876130293Sscottl	struct ncr53c9x_tinfo *ti = &sc->sc_tinfo[ccb->ccb_h.target_id];
2877130293Sscottl
2878130293Sscottl	xpt_print_path(ccb->ccb_h.path);
2879130293Sscottl	device_printf(sc->sc_dev, "timed out [ecb %p (flags 0x%x, dleft %x, "
2880130293Sscottl	    "stat %x)], <state %d, nexus %p, phase(l %x, c %x, p %x), "
2881130293Sscottl	    "resid %lx, msg(q %x,o %x) %s>",
2882130293Sscottl	    ecb, ecb->flags, ecb->dleft, ecb->stat,
2883130293Sscottl	    sc->sc_state, sc->sc_nexus,
2884130293Sscottl	    NCR_READ_REG(sc, NCR_STAT),
2885130293Sscottl	    sc->sc_phase, sc->sc_prevphase,
2886130293Sscottl	    (long)sc->sc_dleft, sc->sc_msgpriq, sc->sc_msgout,
2887130293Sscottl	    NCRDMA_ISACTIVE(sc) ? "DMA active" : "");
2888130293Sscottl#if NCR53C9X_DEBUG > 1
2889130293Sscottl	printf("TRACE: %s.", ecb->trace);
2890130293Sscottl#endif
2891130293Sscottl
2892130293Sscottl	mtx_lock(&sc->sc_lock);
2893130293Sscottl
2894130293Sscottl	if (ecb->flags & ECB_ABORT) {
2895130293Sscottl		/* abort timed out */
2896130293Sscottl		printf(" AGAIN\n");
2897130293Sscottl
2898130293Sscottl		ncr53c9x_init(sc, 1);
2899130293Sscottl	} else {
2900130293Sscottl		/* abort the operation that has timed out */
2901130293Sscottl		printf("\n");
2902130293Sscottl		ccb->ccb_h.status = CAM_CMD_TIMEOUT;
2903130293Sscottl		ncr53c9x_abort(sc, ecb);
2904130293Sscottl
2905130293Sscottl		/* Disable sync mode if stuck in a data phase */
2906130293Sscottl		if (ecb == sc->sc_nexus &&
2907130293Sscottl		    (ti->flags & T_SYNCMODE) != 0 &&
2908130293Sscottl		    (sc->sc_phase & (MSGI|CDI)) == 0) {
2909130293Sscottl			/* XXX ASYNC CALLBACK! */
2910130293Sscottl			xpt_print_path(ccb->ccb_h.path);
2911130293Sscottl			printf("sync negotiation disabled\n");
2912130293Sscottl			sc->sc_cfflags |=
2913130293Sscottl			    (1 << ((ccb->ccb_h.target_id & 7) + 8));
2914130293Sscottl		}
2915130293Sscottl	}
2916130293Sscottl
2917130293Sscottl	mtx_unlock(&sc->sc_lock);
2918130293Sscottl}
2919130293Sscottl
2920130293Sscottlstatic void
2921130293Sscottlncr53c9x_watch(void *arg)
2922130293Sscottl{
2923130293Sscottl	struct ncr53c9x_softc *sc = (struct ncr53c9x_softc *)arg;
2924130293Sscottl	struct ncr53c9x_tinfo *ti;
2925130293Sscottl	struct ncr53c9x_linfo *li;
2926130293Sscottl	int t;
2927130293Sscottl	/* Delete any structures that have not been used in 10min. */
2928130293Sscottl	time_t old = time_second - (10 * 60);
2929130293Sscottl
2930130293Sscottl	mtx_lock(&sc->sc_lock);
2931130293Sscottl	for (t = 0; t < sc->sc_ntarg; t++) {
2932130293Sscottl		ti = &sc->sc_tinfo[t];
2933130293Sscottl		li = LIST_FIRST(&ti->luns);
2934130293Sscottl		while (li) {
2935130293Sscottl			if (li->last_used < old &&
2936130293Sscottl			    li->untagged == NULL &&
2937130293Sscottl			    li->used == 0) {
2938130293Sscottl				if (li->lun < NCR_NLUN)
2939130293Sscottl					ti->lun[li->lun] = NULL;
2940130293Sscottl				LIST_REMOVE(li, link);
2941130293Sscottl				free(li, M_DEVBUF);
2942130293Sscottl				/* Restart the search at the beginning */
2943130293Sscottl				li = LIST_FIRST(&ti->luns);
2944130293Sscottl				continue;
2945130293Sscottl			}
2946130293Sscottl			li = LIST_NEXT(li, link);
2947130293Sscottl		}
2948130293Sscottl	}
2949130293Sscottl	mtx_unlock(&sc->sc_lock);
2950130293Sscottl	callout_reset(&sc->sc_watchdog, 60 * hz, ncr53c9x_watch, sc);
2951130293Sscottl}
2952