ncr53c9x.c revision 1.36.2.17 1 1.36.2.17 bouyer /* $NetBSD: ncr53c9x.c,v 1.36.2.17 2001/04/24 07:29:31 bouyer Exp $ */
2 1.1 thorpej
3 1.27 mycroft /*-
4 1.27 mycroft * Copyright (c) 1998 The NetBSD Foundation, Inc.
5 1.27 mycroft * All rights reserved.
6 1.27 mycroft *
7 1.27 mycroft * This code is derived from software contributed to The NetBSD Foundation
8 1.27 mycroft * by Charles M. Hannum.
9 1.1 thorpej *
10 1.1 thorpej * Redistribution and use in source and binary forms, with or without
11 1.1 thorpej * modification, are permitted provided that the following conditions
12 1.1 thorpej * are met:
13 1.1 thorpej * 1. Redistributions of source code must retain the above copyright
14 1.1 thorpej * notice, this list of conditions and the following disclaimer.
15 1.1 thorpej * 2. Redistributions in binary form must reproduce the above copyright
16 1.1 thorpej * notice, this list of conditions and the following disclaimer in the
17 1.1 thorpej * documentation and/or other materials provided with the distribution.
18 1.1 thorpej * 3. All advertising materials mentioning features or use of this software
19 1.1 thorpej * must display the following acknowledgement:
20 1.27 mycroft * This product includes software developed by the NetBSD
21 1.27 mycroft * Foundation, Inc. and its contributors.
22 1.27 mycroft * 4. Neither the name of The NetBSD Foundation nor the names of its
23 1.27 mycroft * contributors may be used to endorse or promote products derived
24 1.27 mycroft * from this software without specific prior written permission.
25 1.1 thorpej *
26 1.27 mycroft * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 1.27 mycroft * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 1.27 mycroft * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 1.27 mycroft * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 1.27 mycroft * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 1.27 mycroft * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 1.27 mycroft * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 1.27 mycroft * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 1.27 mycroft * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 1.27 mycroft * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 1.27 mycroft * POSSIBILITY OF SUCH DAMAGE.
37 1.1 thorpej */
38 1.1 thorpej
39 1.1 thorpej /*
40 1.1 thorpej * Copyright (c) 1994 Peter Galbavy
41 1.1 thorpej * Copyright (c) 1995 Paul Kranenburg
42 1.1 thorpej * All rights reserved.
43 1.1 thorpej *
44 1.1 thorpej * Redistribution and use in source and binary forms, with or without
45 1.1 thorpej * modification, are permitted provided that the following conditions
46 1.1 thorpej * are met:
47 1.1 thorpej * 1. Redistributions of source code must retain the above copyright
48 1.1 thorpej * notice, this list of conditions and the following disclaimer.
49 1.1 thorpej * 2. Redistributions in binary form must reproduce the above copyright
50 1.1 thorpej * notice, this list of conditions and the following disclaimer in the
51 1.1 thorpej * documentation and/or other materials provided with the distribution.
52 1.1 thorpej * 3. All advertising materials mentioning features or use of this software
53 1.1 thorpej * must display the following acknowledgement:
54 1.1 thorpej * This product includes software developed by Peter Galbavy
55 1.1 thorpej * 4. The name of the author may not be used to endorse or promote products
56 1.1 thorpej * derived from this software without specific prior written permission.
57 1.1 thorpej *
58 1.1 thorpej * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
59 1.1 thorpej * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
60 1.1 thorpej * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
61 1.1 thorpej * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
62 1.1 thorpej * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
63 1.1 thorpej * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
64 1.1 thorpej * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
65 1.1 thorpej * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
66 1.1 thorpej * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
67 1.1 thorpej * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
68 1.1 thorpej * POSSIBILITY OF SUCH DAMAGE.
69 1.1 thorpej */
70 1.1 thorpej
71 1.1 thorpej /*
72 1.1 thorpej * Based on aic6360 by Jarle Greipsland
73 1.1 thorpej *
74 1.1 thorpej * Acknowledgements: Many of the algorithms used in this driver are
75 1.1 thorpej * inspired by the work of Julian Elischer (julian (at) tfs.com) and
76 1.1 thorpej * Charles Hannum (mycroft (at) duality.gnu.ai.mit.edu). Thanks a million!
77 1.1 thorpej */
78 1.1 thorpej
79 1.1 thorpej #include <sys/types.h>
80 1.1 thorpej #include <sys/param.h>
81 1.1 thorpej #include <sys/systm.h>
82 1.36.2.4 bouyer #include <sys/callout.h>
83 1.1 thorpej #include <sys/kernel.h>
84 1.1 thorpej #include <sys/errno.h>
85 1.1 thorpej #include <sys/ioctl.h>
86 1.1 thorpej #include <sys/device.h>
87 1.1 thorpej #include <sys/buf.h>
88 1.24 pk #include <sys/malloc.h>
89 1.1 thorpej #include <sys/proc.h>
90 1.1 thorpej #include <sys/queue.h>
91 1.36.2.6 bouyer #include <sys/pool.h>
92 1.36.2.5 bouyer #include <sys/scsiio.h>
93 1.1 thorpej
94 1.18 bouyer #include <dev/scsipi/scsi_all.h>
95 1.18 bouyer #include <dev/scsipi/scsipi_all.h>
96 1.18 bouyer #include <dev/scsipi/scsiconf.h>
97 1.18 bouyer #include <dev/scsipi/scsi_message.h>
98 1.1 thorpej
99 1.1 thorpej #include <dev/ic/ncr53c9xreg.h>
100 1.1 thorpej #include <dev/ic/ncr53c9xvar.h>
101 1.1 thorpej
102 1.1 thorpej int ncr53c9x_debug = 0; /*NCR_SHOWPHASE|NCR_SHOWMISC|NCR_SHOWTRAC|NCR_SHOWCMDS;*/
103 1.36.2.6 bouyer #ifdef DEBUG
104 1.36.2.6 bouyer int ncr53c9x_notag = 0;
105 1.36.2.6 bouyer #endif
106 1.1 thorpej
107 1.36.2.6 bouyer /*static*/ void ncr53c9x_readregs(struct ncr53c9x_softc *);
108 1.36.2.6 bouyer /*static*/ void ncr53c9x_select(struct ncr53c9x_softc *, struct ncr53c9x_ecb *);
109 1.36.2.6 bouyer /*static*/ int ncr53c9x_reselect(struct ncr53c9x_softc *, int, int, int);
110 1.36.2.6 bouyer /*static*/ void ncr53c9x_scsi_reset(struct ncr53c9x_softc *);
111 1.36.2.6 bouyer /*static*/ int ncr53c9x_poll(struct ncr53c9x_softc *,
112 1.36.2.6 bouyer struct scsipi_xfer *, int);
113 1.36.2.6 bouyer /*static*/ void ncr53c9x_sched(struct ncr53c9x_softc *);
114 1.36.2.6 bouyer /*static*/ void ncr53c9x_done(struct ncr53c9x_softc *, struct ncr53c9x_ecb *);
115 1.36.2.6 bouyer /*static*/ void ncr53c9x_msgin(struct ncr53c9x_softc *);
116 1.36.2.6 bouyer /*static*/ void ncr53c9x_msgout(struct ncr53c9x_softc *);
117 1.36.2.6 bouyer /*static*/ void ncr53c9x_timeout(void *arg);
118 1.36.2.6 bouyer /*static*/ void ncr53c9x_watch(void *arg);
119 1.36.2.6 bouyer /*static*/ void ncr53c9x_abort(struct ncr53c9x_softc *, struct ncr53c9x_ecb *);
120 1.36.2.16 bouyer /*static*/ void ncr53c9x_dequeue(struct ncr53c9x_softc *,
121 1.36.2.16 bouyer struct ncr53c9x_ecb *);
122 1.36.2.6 bouyer /*static*/ int ncr53c9x_ioctl(struct scsipi_channel *, u_long,
123 1.36.2.6 bouyer caddr_t, int, struct proc *);
124 1.36.2.6 bouyer
125 1.36.2.6 bouyer void ncr53c9x_sense(struct ncr53c9x_softc *, struct ncr53c9x_ecb *);
126 1.36.2.6 bouyer void ncr53c9x_free_ecb(struct ncr53c9x_softc *, struct ncr53c9x_ecb *);
127 1.36.2.6 bouyer struct ncr53c9x_ecb *ncr53c9x_get_ecb(struct ncr53c9x_softc *, int);
128 1.36.2.6 bouyer
129 1.36.2.6 bouyer static inline int ncr53c9x_stp2cpb(struct ncr53c9x_softc *, int);
130 1.36.2.6 bouyer static inline void ncr53c9x_setsync(struct ncr53c9x_softc *,
131 1.36.2.6 bouyer struct ncr53c9x_tinfo *);
132 1.36.2.6 bouyer void ncr53c9x_update_xfer_mode (struct ncr53c9x_softc *, int);
133 1.36.2.6 bouyer static struct ncr53c9x_linfo *ncr53c9x_lunsearch(struct ncr53c9x_tinfo *,
134 1.36.2.6 bouyer int64_t lun);
135 1.36.2.6 bouyer
136 1.36.2.15 bouyer static void ncr53c9x_wrfifo(struct ncr53c9x_softc *, u_char *, int);
137 1.36.2.15 bouyer
138 1.36.2.15 bouyer static int ncr53c9x_rdfifo(struct ncr53c9x_softc *, int);
139 1.36.2.15 bouyer #define NCR_RDFIFO_START 0
140 1.36.2.15 bouyer #define NCR_RDFIFO_CONTINUE 1
141 1.36.2.15 bouyer
142 1.36.2.15 bouyer
143 1.36.2.15 bouyer #define NCR_SET_COUNT(sc, size) do { \
144 1.36.2.16 bouyer NCR_WRITE_REG((sc), NCR_TCL, (size)); \
145 1.36.2.16 bouyer NCR_WRITE_REG((sc), NCR_TCM, (size) >> 8); \
146 1.36.2.16 bouyer if ((sc->sc_cfg2 & NCRCFG2_FE) || \
147 1.36.2.16 bouyer (sc->sc_rev == NCR_VARIANT_FAS366)) { \
148 1.36.2.16 bouyer NCR_WRITE_REG((sc), NCR_TCH, (size) >> 16); \
149 1.36.2.16 bouyer } \
150 1.36.2.16 bouyer if (sc->sc_rev == NCR_VARIANT_FAS366) { \
151 1.36.2.16 bouyer NCR_WRITE_REG(sc, NCR_RCH, 0); \
152 1.36.2.16 bouyer } \
153 1.36.2.15 bouyer } while (0)
154 1.36.2.15 bouyer
155 1.36.2.6 bouyer static int ecb_pool_initialized = 0;
156 1.36.2.6 bouyer static struct pool ecb_pool;
157 1.1 thorpej
158 1.1 thorpej /*
159 1.1 thorpej * Names for the NCR53c9x variants, correspnding to the variant tags
160 1.1 thorpej * in ncr53c9xvar.h.
161 1.1 thorpej */
162 1.36.2.4 bouyer static const char *ncr53c9x_variant_names[] = {
163 1.1 thorpej "ESP100",
164 1.1 thorpej "ESP100A",
165 1.1 thorpej "ESP200",
166 1.1 thorpej "NCR53C94",
167 1.2 briggs "NCR53C96",
168 1.10 pk "ESP406",
169 1.10 pk "FAS408",
170 1.20 mhitch "FAS216",
171 1.33 thorpej "AM53C974",
172 1.36.2.15 bouyer "FAS366/HME",
173 1.1 thorpej };
174 1.1 thorpej
175 1.1 thorpej /*
176 1.36.2.6 bouyer * Search linked list for LUN info by LUN id.
177 1.36.2.6 bouyer */
178 1.36.2.6 bouyer static struct ncr53c9x_linfo *
179 1.36.2.6 bouyer ncr53c9x_lunsearch(ti, lun)
180 1.36.2.6 bouyer struct ncr53c9x_tinfo *ti;
181 1.36.2.6 bouyer int64_t lun;
182 1.36.2.6 bouyer {
183 1.36.2.6 bouyer struct ncr53c9x_linfo *li;
184 1.36.2.16 bouyer LIST_FOREACH(li, &ti->luns, link)
185 1.36.2.6 bouyer if (li->lun == lun)
186 1.36.2.6 bouyer return (li);
187 1.36.2.6 bouyer return (NULL);
188 1.36.2.6 bouyer }
189 1.36.2.6 bouyer
190 1.36.2.6 bouyer /*
191 1.1 thorpej * Attach this instance, and then all the sub-devices
192 1.1 thorpej */
193 1.1 thorpej void
194 1.36.2.1 thorpej ncr53c9x_attach(sc)
195 1.1 thorpej struct ncr53c9x_softc *sc;
196 1.1 thorpej {
197 1.36.2.1 thorpej struct scsipi_adapter *adapt = &sc->sc_adapter;
198 1.36.2.1 thorpej struct scsipi_channel *chan = &sc->sc_channel;
199 1.1 thorpej
200 1.36.2.6 bouyer callout_init(&sc->sc_watchdog);
201 1.1 thorpej /*
202 1.24 pk * Allocate SCSI message buffers.
203 1.24 pk * Front-ends can override allocation to avoid alignment
204 1.24 pk * handling in the DMA engines. Note that that ncr53c9x_msgout()
205 1.24 pk * can request a 1 byte DMA transfer.
206 1.24 pk */
207 1.24 pk if (sc->sc_omess == NULL)
208 1.24 pk sc->sc_omess = malloc(NCR_MAX_MSG_LEN, M_DEVBUF, M_NOWAIT);
209 1.24 pk
210 1.24 pk if (sc->sc_imess == NULL)
211 1.36.2.16 bouyer sc->sc_imess = malloc(NCR_MAX_MSG_LEN + 1, M_DEVBUF, M_NOWAIT);
212 1.24 pk
213 1.24 pk if (sc->sc_omess == NULL || sc->sc_imess == NULL) {
214 1.24 pk printf("out of memory\n");
215 1.24 pk return;
216 1.24 pk }
217 1.24 pk
218 1.24 pk /*
219 1.1 thorpej * Note, the front-end has set us up to print the chip variation.
220 1.1 thorpej */
221 1.1 thorpej if (sc->sc_rev >= NCR_VARIANT_MAX) {
222 1.1 thorpej printf("\n%s: unknown variant %d, devices not attached\n",
223 1.1 thorpej sc->sc_dev.dv_xname, sc->sc_rev);
224 1.1 thorpej return;
225 1.1 thorpej }
226 1.1 thorpej
227 1.1 thorpej printf(": %s, %dMHz, SCSI ID %d\n",
228 1.1 thorpej ncr53c9x_variant_names[sc->sc_rev], sc->sc_freq, sc->sc_id);
229 1.1 thorpej
230 1.1 thorpej sc->sc_ccf = FREQTOCCF(sc->sc_freq);
231 1.1 thorpej
232 1.1 thorpej /* The value *must not* be == 1. Make it 2 */
233 1.1 thorpej if (sc->sc_ccf == 1)
234 1.1 thorpej sc->sc_ccf = 2;
235 1.1 thorpej
236 1.1 thorpej /*
237 1.1 thorpej * The recommended timeout is 250ms. This register is loaded
238 1.1 thorpej * with a value calculated as follows, from the docs:
239 1.1 thorpej *
240 1.1 thorpej * (timout period) x (CLK frequency)
241 1.1 thorpej * reg = -------------------------------------
242 1.1 thorpej * 8192 x (Clock Conversion Factor)
243 1.1 thorpej *
244 1.1 thorpej * Since CCF has a linear relation to CLK, this generally computes
245 1.1 thorpej * to the constant of 153.
246 1.1 thorpej */
247 1.1 thorpej sc->sc_timeout = ((250 * 1000) * sc->sc_freq) / (8192 * sc->sc_ccf);
248 1.1 thorpej
249 1.1 thorpej /* CCF register only has 3 bits; 0 is actually 8 */
250 1.1 thorpej sc->sc_ccf &= 7;
251 1.1 thorpej
252 1.1 thorpej /*
253 1.36.2.1 thorpej * Fill in the scsipi_adapter.
254 1.1 thorpej */
255 1.36.2.1 thorpej adapt->adapt_dev = &sc->sc_dev;
256 1.36.2.1 thorpej adapt->adapt_nchannels = 1;
257 1.36.2.6 bouyer adapt->adapt_openings = 256;
258 1.36.2.8 bouyer adapt->adapt_max_periph = 256;
259 1.36.2.5 bouyer adapt->adapt_ioctl = ncr53c9x_ioctl;
260 1.36.2.1 thorpej /* adapt_request initialized by front-end */
261 1.36.2.1 thorpej /* adapt_minphys initialized by front-end */
262 1.36.2.1 thorpej
263 1.36.2.1 thorpej /*
264 1.36.2.1 thorpej * Fill in the scsipi_channel.
265 1.36.2.1 thorpej */
266 1.36.2.1 thorpej memset(chan, 0, sizeof(*chan));
267 1.36.2.1 thorpej chan->chan_adapter = adapt;
268 1.36.2.1 thorpej chan->chan_bustype = &scsi_bustype;
269 1.36.2.1 thorpej chan->chan_channel = 0;
270 1.36.2.15 bouyer chan->chan_ntargets = 8; /* XXX fas has 16(not supported) */
271 1.36.2.1 thorpej chan->chan_nluns = 8;
272 1.36.2.1 thorpej chan->chan_id = sc->sc_id;
273 1.10 pk
274 1.10 pk /*
275 1.36.2.4 bouyer * Add reference to adapter so that we drop the reference after
276 1.36.2.4 bouyer * config_found() to make sure the adatper is disabled.
277 1.10 pk */
278 1.36.2.4 bouyer if (scsipi_adapter_addref(adapt) != 0) {
279 1.36.2.4 bouyer printf("%s: unable to enable controller\n",
280 1.36.2.4 bouyer sc->sc_dev.dv_xname);
281 1.36.2.4 bouyer return;
282 1.10 pk }
283 1.24 pk
284 1.36.2.4 bouyer /* Reset state & bus */
285 1.36.2.4 bouyer sc->sc_cfflags = sc->sc_dev.dv_cfdata->cf_flags;
286 1.36.2.4 bouyer sc->sc_state = 0;
287 1.36.2.4 bouyer ncr53c9x_init(sc, 1);
288 1.36.2.4 bouyer
289 1.36.2.1 thorpej /*
290 1.36.2.4 bouyer * Now try to attach all the sub-devices
291 1.36.2.1 thorpej */
292 1.36.2.4 bouyer sc->sc_child = config_found(&sc->sc_dev, &sc->sc_channel, scsiprint);
293 1.36.2.4 bouyer
294 1.36.2.4 bouyer scsipi_adapter_delref(adapt);
295 1.36.2.6 bouyer callout_reset(&sc->sc_watchdog, 60*hz, ncr53c9x_watch, sc);
296 1.36.2.4 bouyer }
297 1.36.2.4 bouyer
298 1.36.2.4 bouyer int
299 1.36.2.4 bouyer ncr53c9x_detach(sc, flags)
300 1.36.2.4 bouyer struct ncr53c9x_softc *sc;
301 1.36.2.4 bouyer int flags;
302 1.36.2.4 bouyer {
303 1.36.2.4 bouyer int error;
304 1.36.2.4 bouyer
305 1.36.2.4 bouyer if (sc->sc_child) {
306 1.36.2.4 bouyer error = config_detach(sc->sc_child, flags);
307 1.36.2.4 bouyer if (error)
308 1.36.2.4 bouyer return (error);
309 1.36.2.4 bouyer }
310 1.36.2.4 bouyer
311 1.36.2.4 bouyer free(sc->sc_imess, M_DEVBUF);
312 1.36.2.4 bouyer free(sc->sc_omess, M_DEVBUF);
313 1.36.2.4 bouyer
314 1.36.2.4 bouyer return (0);
315 1.1 thorpej }
316 1.1 thorpej
317 1.1 thorpej /*
318 1.30 pk * This is the generic ncr53c9x reset function. It does not reset the SCSI bus,
319 1.30 pk * only this controller, but kills any on-going commands, and also stops
320 1.1 thorpej * and resets the DMA.
321 1.1 thorpej *
322 1.1 thorpej * After reset, registers are loaded with the defaults from the attach
323 1.1 thorpej * routine above.
324 1.1 thorpej */
325 1.1 thorpej void
326 1.1 thorpej ncr53c9x_reset(sc)
327 1.1 thorpej struct ncr53c9x_softc *sc;
328 1.1 thorpej {
329 1.1 thorpej
330 1.1 thorpej /* reset DMA first */
331 1.1 thorpej NCRDMA_RESET(sc);
332 1.1 thorpej
333 1.1 thorpej /* reset SCSI chip */
334 1.1 thorpej NCRCMD(sc, NCRCMD_RSTCHIP);
335 1.1 thorpej NCRCMD(sc, NCRCMD_NOP);
336 1.1 thorpej DELAY(500);
337 1.1 thorpej
338 1.1 thorpej /* do these backwards, and fall through */
339 1.1 thorpej switch (sc->sc_rev) {
340 1.10 pk case NCR_VARIANT_ESP406:
341 1.10 pk case NCR_VARIANT_FAS408:
342 1.36.2.4 bouyer NCR_WRITE_REG(sc, NCR_CFG5, sc->sc_cfg5 | NCRCFG5_SINT);
343 1.36.2.4 bouyer NCR_WRITE_REG(sc, NCR_CFG4, sc->sc_cfg4);
344 1.33 thorpej case NCR_VARIANT_AM53C974:
345 1.20 mhitch case NCR_VARIANT_FAS216:
346 1.1 thorpej case NCR_VARIANT_NCR53C94:
347 1.2 briggs case NCR_VARIANT_NCR53C96:
348 1.1 thorpej case NCR_VARIANT_ESP200:
349 1.26 thorpej sc->sc_features |= NCR_F_HASCFG3;
350 1.1 thorpej NCR_WRITE_REG(sc, NCR_CFG3, sc->sc_cfg3);
351 1.1 thorpej case NCR_VARIANT_ESP100A:
352 1.36.2.16 bouyer sc->sc_features |= NCR_F_SELATN3;
353 1.1 thorpej NCR_WRITE_REG(sc, NCR_CFG2, sc->sc_cfg2);
354 1.1 thorpej case NCR_VARIANT_ESP100:
355 1.1 thorpej NCR_WRITE_REG(sc, NCR_CFG1, sc->sc_cfg1);
356 1.1 thorpej NCR_WRITE_REG(sc, NCR_CCF, sc->sc_ccf);
357 1.1 thorpej NCR_WRITE_REG(sc, NCR_SYNCOFF, 0);
358 1.1 thorpej NCR_WRITE_REG(sc, NCR_TIMEOUT, sc->sc_timeout);
359 1.1 thorpej break;
360 1.36.2.15 bouyer
361 1.36.2.15 bouyer case NCR_VARIANT_FAS366:
362 1.36.2.16 bouyer sc->sc_features |=
363 1.36.2.16 bouyer NCR_F_HASCFG3 | NCR_F_FASTSCSI | NCR_F_SELATN3;
364 1.36.2.16 bouyer sc->sc_cfg3 = NCRFASCFG3_FASTCLK | NCRFASCFG3_OBAUTO;
365 1.36.2.16 bouyer sc->sc_cfg3_fscsi = NCRFASCFG3_FASTSCSI;
366 1.36.2.15 bouyer NCR_WRITE_REG(sc, NCR_CFG3, sc->sc_cfg3);
367 1.36.2.15 bouyer sc->sc_cfg2 = 0; /* NCRCFG2_HMEFE| NCRCFG2_HME32 */
368 1.36.2.15 bouyer NCR_WRITE_REG(sc, NCR_CFG2, sc->sc_cfg2);
369 1.36.2.15 bouyer NCR_WRITE_REG(sc, NCR_CFG1, sc->sc_cfg1);
370 1.36.2.15 bouyer NCR_WRITE_REG(sc, NCR_CCF, sc->sc_ccf);
371 1.36.2.15 bouyer NCR_WRITE_REG(sc, NCR_SYNCOFF, 0);
372 1.36.2.15 bouyer NCR_WRITE_REG(sc, NCR_TIMEOUT, sc->sc_timeout);
373 1.36.2.15 bouyer break;
374 1.36.2.15 bouyer
375 1.1 thorpej default:
376 1.1 thorpej printf("%s: unknown revision code, assuming ESP100\n",
377 1.1 thorpej sc->sc_dev.dv_xname);
378 1.1 thorpej NCR_WRITE_REG(sc, NCR_CFG1, sc->sc_cfg1);
379 1.1 thorpej NCR_WRITE_REG(sc, NCR_CCF, sc->sc_ccf);
380 1.1 thorpej NCR_WRITE_REG(sc, NCR_SYNCOFF, 0);
381 1.1 thorpej NCR_WRITE_REG(sc, NCR_TIMEOUT, sc->sc_timeout);
382 1.1 thorpej }
383 1.33 thorpej
384 1.33 thorpej if (sc->sc_rev == NCR_VARIANT_AM53C974)
385 1.36.2.4 bouyer NCR_WRITE_REG(sc, NCR_AMDCFG4, sc->sc_cfg4);
386 1.36.2.15 bouyer
387 1.36.2.15 bouyer #if 0
388 1.36.2.15 bouyer printf("%s: ncr53c9x_reset: revision %d\n",
389 1.36.2.15 bouyer sc->sc_dev.dv_xname, sc->sc_rev);
390 1.36.2.16 bouyer printf("%s: ncr53c9x_reset: cfg1 0x%x, cfg2 0x%x, cfg3 0x%x, "
391 1.36.2.16 bouyer "ccf 0x%x, timeout 0x%x\n",
392 1.36.2.16 bouyer sc->sc_dev.dv_xname, sc->sc_cfg1, sc->sc_cfg2, sc->sc_cfg3,
393 1.36.2.16 bouyer sc->sc_ccf, sc->sc_timeout);
394 1.36.2.15 bouyer #endif
395 1.1 thorpej }
396 1.1 thorpej
397 1.1 thorpej /*
398 1.1 thorpej * Reset the SCSI bus, but not the chip
399 1.1 thorpej */
400 1.1 thorpej void
401 1.1 thorpej ncr53c9x_scsi_reset(sc)
402 1.1 thorpej struct ncr53c9x_softc *sc;
403 1.1 thorpej {
404 1.1 thorpej
405 1.1 thorpej (*sc->sc_glue->gl_dma_stop)(sc);
406 1.1 thorpej
407 1.1 thorpej printf("%s: resetting SCSI bus\n", sc->sc_dev.dv_xname);
408 1.1 thorpej NCRCMD(sc, NCRCMD_RSTSCSI);
409 1.1 thorpej }
410 1.1 thorpej
411 1.1 thorpej /*
412 1.30 pk * Initialize ncr53c9x state machine
413 1.1 thorpej */
414 1.1 thorpej void
415 1.1 thorpej ncr53c9x_init(sc, doreset)
416 1.1 thorpej struct ncr53c9x_softc *sc;
417 1.1 thorpej int doreset;
418 1.1 thorpej {
419 1.1 thorpej struct ncr53c9x_ecb *ecb;
420 1.36.2.6 bouyer struct ncr53c9x_linfo *li;
421 1.36.2.6 bouyer int i, r;
422 1.1 thorpej
423 1.36.2.15 bouyer NCR_TRACE(("[NCR_INIT(%d) %d] ", doreset, sc->sc_state));
424 1.1 thorpej
425 1.36.2.6 bouyer if (!ecb_pool_initialized) {
426 1.36.2.6 bouyer /* All instances share this pool */
427 1.36.2.16 bouyer pool_init(&ecb_pool, sizeof(struct ncr53c9x_ecb), 0, 0, 0,
428 1.36.2.16 bouyer "ncr53c9x_ecb", 0, NULL, NULL, 0);
429 1.36.2.6 bouyer ecb_pool_initialized = 1;
430 1.36.2.6 bouyer }
431 1.36.2.6 bouyer
432 1.1 thorpej if (sc->sc_state == 0) {
433 1.1 thorpej /* First time through; initialize. */
434 1.36.2.6 bouyer
435 1.1 thorpej TAILQ_INIT(&sc->ready_list);
436 1.1 thorpej sc->sc_nexus = NULL;
437 1.1 thorpej bzero(sc->sc_tinfo, sizeof(sc->sc_tinfo));
438 1.36.2.6 bouyer for (r = 0; r < NCR_NTARG; r++) {
439 1.36.2.6 bouyer LIST_INIT(&sc->sc_tinfo[r].luns);
440 1.36.2.6 bouyer }
441 1.1 thorpej } else {
442 1.1 thorpej /* Cancel any active commands. */
443 1.1 thorpej sc->sc_state = NCR_CLEANING;
444 1.36.2.6 bouyer sc->sc_msgify = 0;
445 1.1 thorpej if ((ecb = sc->sc_nexus) != NULL) {
446 1.16 pk ecb->xs->error = XS_TIMEOUT;
447 1.1 thorpej ncr53c9x_done(sc, ecb);
448 1.1 thorpej }
449 1.36.2.6 bouyer /* Cancel outstanding disconnected commands on each LUN */
450 1.36.2.6 bouyer for (r = 0; r < 8; r++) {
451 1.36.2.6 bouyer LIST_FOREACH(li, &sc->sc_tinfo[r].luns, link) {
452 1.36.2.6 bouyer if ((ecb = li->untagged) != NULL) {
453 1.36.2.6 bouyer li->untagged = NULL;
454 1.36.2.16 bouyer /*
455 1.36.2.6 bouyer * XXXXXXX
456 1.36.2.6 bouyer *
457 1.36.2.16 bouyer * Should we terminate a command
458 1.36.2.16 bouyer * that never reached the disk?
459 1.36.2.6 bouyer */
460 1.36.2.6 bouyer li->busy = 0;
461 1.36.2.6 bouyer ecb->xs->error = XS_TIMEOUT;
462 1.36.2.6 bouyer ncr53c9x_done(sc, ecb);
463 1.36.2.6 bouyer }
464 1.36.2.6 bouyer for (i = 0; i < 256; i++)
465 1.36.2.6 bouyer if ((ecb = li->queued[i])) {
466 1.36.2.6 bouyer li->queued[i] = NULL;
467 1.36.2.6 bouyer ecb->xs->error = XS_TIMEOUT;
468 1.36.2.6 bouyer ncr53c9x_done(sc, ecb);
469 1.36.2.6 bouyer }
470 1.36.2.6 bouyer li->used = 0;
471 1.36.2.6 bouyer }
472 1.1 thorpej }
473 1.1 thorpej }
474 1.1 thorpej
475 1.1 thorpej /*
476 1.1 thorpej * reset the chip to a known state
477 1.1 thorpej */
478 1.1 thorpej ncr53c9x_reset(sc);
479 1.1 thorpej
480 1.1 thorpej sc->sc_phase = sc->sc_prevphase = INVALID_PHASE;
481 1.1 thorpej for (r = 0; r < 8; r++) {
482 1.1 thorpej struct ncr53c9x_tinfo *ti = &sc->sc_tinfo[r];
483 1.1 thorpej /* XXX - config flags per target: low bits: no reselect; high bits: no synch */
484 1.1 thorpej
485 1.36.2.8 bouyer ti->flags = ((sc->sc_minsync && !(sc->sc_cfflags & (1<<(r+8))))
486 1.36.2.16 bouyer ? 0 : T_SYNCHOFF) |
487 1.36.2.16 bouyer ((sc->sc_cfflags & (1<<r)) ? T_RSELECTOFF : 0) |
488 1.36.2.16 bouyer T_NEED_TO_RESET;
489 1.36.2.6 bouyer #ifdef DEBUG
490 1.36.2.6 bouyer if (ncr53c9x_notag)
491 1.36.2.13 bouyer ti->flags &= ~T_TAG;
492 1.36.2.6 bouyer #endif
493 1.1 thorpej ti->period = sc->sc_minsync;
494 1.1 thorpej ti->offset = 0;
495 1.36.2.15 bouyer ti->cfg3 = 0;
496 1.1 thorpej }
497 1.1 thorpej
498 1.1 thorpej if (doreset) {
499 1.1 thorpej sc->sc_state = NCR_SBR;
500 1.1 thorpej NCRCMD(sc, NCRCMD_RSTSCSI);
501 1.1 thorpej } else {
502 1.1 thorpej sc->sc_state = NCR_IDLE;
503 1.15 pk ncr53c9x_sched(sc);
504 1.1 thorpej }
505 1.1 thorpej }
506 1.1 thorpej
507 1.1 thorpej /*
508 1.1 thorpej * Read the NCR registers, and save their contents for later use.
509 1.1 thorpej * NCR_STAT, NCR_STEP & NCR_INTR are mostly zeroed out when reading
510 1.1 thorpej * NCR_INTR - so make sure it is the last read.
511 1.1 thorpej *
512 1.1 thorpej * I think that (from reading the docs) most bits in these registers
513 1.1 thorpej * only make sense when he DMA CSR has an interrupt showing. Call only
514 1.1 thorpej * if an interrupt is pending.
515 1.1 thorpej */
516 1.25 pk __inline__ void
517 1.1 thorpej ncr53c9x_readregs(sc)
518 1.1 thorpej struct ncr53c9x_softc *sc;
519 1.1 thorpej {
520 1.1 thorpej
521 1.1 thorpej sc->sc_espstat = NCR_READ_REG(sc, NCR_STAT);
522 1.1 thorpej /* Only the stepo bits are of interest */
523 1.1 thorpej sc->sc_espstep = NCR_READ_REG(sc, NCR_STEP) & NCRSTEP_MASK;
524 1.36.2.15 bouyer
525 1.36.2.15 bouyer if (sc->sc_rev == NCR_VARIANT_FAS366)
526 1.36.2.15 bouyer sc->sc_espstat2 = NCR_READ_REG(sc, NCR_STAT2);
527 1.36.2.15 bouyer
528 1.1 thorpej sc->sc_espintr = NCR_READ_REG(sc, NCR_INTR);
529 1.1 thorpej
530 1.1 thorpej if (sc->sc_glue->gl_clear_latched_intr != NULL)
531 1.1 thorpej (*sc->sc_glue->gl_clear_latched_intr)(sc);
532 1.1 thorpej
533 1.1 thorpej /*
534 1.1 thorpej * Determine the SCSI bus phase, return either a real SCSI bus phase
535 1.1 thorpej * or some pseudo phase we use to detect certain exceptions.
536 1.1 thorpej */
537 1.1 thorpej
538 1.36.2.16 bouyer sc->sc_phase = (sc->sc_espintr & NCRINTR_DIS) ?
539 1.36.2.16 bouyer /* Disconnected */ BUSFREE_PHASE : sc->sc_espstat & NCRSTAT_PHASE;
540 1.1 thorpej
541 1.36.2.15 bouyer NCR_MISC(("regs[intr=%02x,stat=%02x,step=%02x,stat2=%02x] ",
542 1.36.2.16 bouyer sc->sc_espintr, sc->sc_espstat, sc->sc_espstep, sc->sc_espstat2));
543 1.1 thorpej }
544 1.1 thorpej
545 1.1 thorpej /*
546 1.1 thorpej * Convert Synchronous Transfer Period to chip register Clock Per Byte value.
547 1.1 thorpej */
548 1.1 thorpej static inline int
549 1.1 thorpej ncr53c9x_stp2cpb(sc, period)
550 1.1 thorpej struct ncr53c9x_softc *sc;
551 1.1 thorpej int period;
552 1.1 thorpej {
553 1.1 thorpej int v;
554 1.1 thorpej v = (sc->sc_freq * period) / 250;
555 1.1 thorpej if (ncr53c9x_cpb2stp(sc, v) < period)
556 1.1 thorpej /* Correct round-down error */
557 1.1 thorpej v++;
558 1.25 pk return (v);
559 1.1 thorpej }
560 1.1 thorpej
561 1.1 thorpej static inline void
562 1.1 thorpej ncr53c9x_setsync(sc, ti)
563 1.1 thorpej struct ncr53c9x_softc *sc;
564 1.1 thorpej struct ncr53c9x_tinfo *ti;
565 1.1 thorpej {
566 1.36.2.15 bouyer u_char syncoff, synctp;
567 1.36.2.15 bouyer u_char cfg3 = sc->sc_cfg3 | ti->cfg3;
568 1.1 thorpej
569 1.1 thorpej if (ti->flags & T_SYNCMODE) {
570 1.26 thorpej syncoff = ti->offset;
571 1.26 thorpej synctp = ncr53c9x_stp2cpb(sc, ti->period);
572 1.26 thorpej if (sc->sc_features & NCR_F_FASTSCSI) {
573 1.26 thorpej /*
574 1.26 thorpej * If the period is 200ns or less (ti->period <= 50),
575 1.26 thorpej * put the chip in Fast SCSI mode.
576 1.26 thorpej */
577 1.26 thorpej if (ti->period <= 50)
578 1.35 mhitch /*
579 1.35 mhitch * There are (at least) 4 variations of the
580 1.35 mhitch * configuration 3 register. The drive attach
581 1.35 mhitch * routine sets the appropriate bit to put the
582 1.35 mhitch * chip into Fast SCSI mode so that it doesn't
583 1.35 mhitch * have to be figured out here each time.
584 1.35 mhitch */
585 1.35 mhitch cfg3 |= sc->sc_cfg3_fscsi;
586 1.26 thorpej }
587 1.33 thorpej
588 1.33 thorpej /*
589 1.33 thorpej * Am53c974 requires different SYNCTP values when the
590 1.33 thorpej * FSCSI bit is off.
591 1.33 thorpej */
592 1.33 thorpej if (sc->sc_rev == NCR_VARIANT_AM53C974 &&
593 1.33 thorpej (cfg3 & NCRAMDCFG3_FSCSI) == 0)
594 1.33 thorpej synctp--;
595 1.1 thorpej } else {
596 1.26 thorpej syncoff = 0;
597 1.26 thorpej synctp = 0;
598 1.1 thorpej }
599 1.26 thorpej
600 1.26 thorpej if (sc->sc_features & NCR_F_HASCFG3)
601 1.26 thorpej NCR_WRITE_REG(sc, NCR_CFG3, cfg3);
602 1.26 thorpej
603 1.26 thorpej NCR_WRITE_REG(sc, NCR_SYNCOFF, syncoff);
604 1.26 thorpej NCR_WRITE_REG(sc, NCR_SYNCTP, synctp);
605 1.1 thorpej }
606 1.1 thorpej
607 1.1 thorpej /*
608 1.1 thorpej * Send a command to a target, set the driver state to NCR_SELECTING
609 1.1 thorpej * and let the caller take care of the rest.
610 1.1 thorpej *
611 1.1 thorpej * Keeping this as a function allows me to say that this may be done
612 1.1 thorpej * by DMA instead of programmed I/O soon.
613 1.1 thorpej */
614 1.1 thorpej void
615 1.1 thorpej ncr53c9x_select(sc, ecb)
616 1.1 thorpej struct ncr53c9x_softc *sc;
617 1.1 thorpej struct ncr53c9x_ecb *ecb;
618 1.1 thorpej {
619 1.36.2.1 thorpej struct scsipi_periph *periph = ecb->xs->xs_periph;
620 1.36.2.1 thorpej int target = periph->periph_target;
621 1.36.2.1 thorpej int lun = periph->periph_lun;
622 1.1 thorpej struct ncr53c9x_tinfo *ti = &sc->sc_tinfo[target];
623 1.22 pk int tiflags = ti->flags;
624 1.1 thorpej u_char *cmd;
625 1.1 thorpej int clen;
626 1.36.2.16 bouyer int selatn3, selatns;
627 1.36.2.4 bouyer size_t dmasize;
628 1.1 thorpej
629 1.36.2.6 bouyer NCR_TRACE(("[ncr53c9x_select(t%d,l%d,cmd:%x,tag:%x,%x)] ",
630 1.36.2.16 bouyer target, lun, ecb->cmd.cmd.opcode, ecb->tag[0], ecb->tag[1]));
631 1.1 thorpej
632 1.1 thorpej sc->sc_state = NCR_SELECTING;
633 1.7 gwr /*
634 1.7 gwr * Schedule the timeout now, the first time we will go away
635 1.7 gwr * expecting to come back due to an interrupt, because it is
636 1.7 gwr * always possible that the interrupt may never happen.
637 1.7 gwr */
638 1.36.2.4 bouyer if ((ecb->xs->xs_control & XS_CTL_POLL) == 0) {
639 1.36.2.4 bouyer int timeout = ecb->timeout;
640 1.36.2.4 bouyer
641 1.36.2.4 bouyer if (hz > 100 && timeout > 1000)
642 1.36.2.4 bouyer timeout = (timeout / 1000) * hz;
643 1.36.2.4 bouyer else
644 1.36.2.4 bouyer timeout = (timeout * hz) / 1000;
645 1.36.2.6 bouyer
646 1.36.2.4 bouyer callout_reset(&ecb->xs->xs_callout, timeout,
647 1.36.2.16 bouyer ncr53c9x_timeout, ecb);
648 1.36.2.4 bouyer }
649 1.7 gwr
650 1.1 thorpej /*
651 1.1 thorpej * The docs say the target register is never reset, and I
652 1.1 thorpej * can't think of a better place to set it
653 1.1 thorpej */
654 1.36.2.15 bouyer if (sc->sc_rev == NCR_VARIANT_FAS366) {
655 1.36.2.15 bouyer NCRCMD(sc, NCRCMD_FLUSH);
656 1.36.2.15 bouyer NCR_WRITE_REG(sc, NCR_SELID, target | NCR_BUSID_HME);
657 1.36.2.15 bouyer } else {
658 1.36.2.15 bouyer NCR_WRITE_REG(sc, NCR_SELID, target);
659 1.36.2.15 bouyer }
660 1.1 thorpej ncr53c9x_setsync(sc, ti);
661 1.1 thorpej
662 1.36.2.6 bouyer if ((ecb->flags & ECB_SENSE) != 0) {
663 1.36.2.4 bouyer /*
664 1.36.2.4 bouyer * For REQUEST SENSE, we should not send an IDENTIFY or
665 1.36.2.4 bouyer * otherwise mangle the target. There should be no MESSAGE IN
666 1.36.2.4 bouyer * phase.
667 1.36.2.4 bouyer */
668 1.36.2.15 bouyer if (sc->sc_features & NCR_F_DMASELECT) {
669 1.36.2.4 bouyer /* setup DMA transfer for command */
670 1.36.2.4 bouyer dmasize = clen = ecb->clen;
671 1.36.2.4 bouyer sc->sc_cmdlen = clen;
672 1.36.2.6 bouyer sc->sc_cmdp = (caddr_t)&ecb->cmd.cmd;
673 1.36.2.16 bouyer
674 1.36.2.4 bouyer /* Program the SCSI counter */
675 1.36.2.15 bouyer NCR_SET_COUNT(sc, dmasize);
676 1.36.2.4 bouyer
677 1.36.2.15 bouyer if (sc->sc_rev != NCR_VARIANT_FAS366)
678 1.36.2.15 bouyer NCRCMD(sc, NCRCMD_NOP|NCRCMD_DMA);
679 1.22 pk
680 1.36.2.4 bouyer /* And get the targets attention */
681 1.36.2.4 bouyer NCRCMD(sc, NCRCMD_SELNATN | NCRCMD_DMA);
682 1.36.2.16 bouyer NCRDMA_SETUP(sc, &sc->sc_cmdp, &sc->sc_cmdlen, 0,
683 1.36.2.16 bouyer &dmasize);
684 1.36.2.4 bouyer NCRDMA_GO(sc);
685 1.36.2.4 bouyer } else {
686 1.36.2.15 bouyer ncr53c9x_wrfifo(sc, (u_char *)&ecb->cmd.cmd, ecb->clen);
687 1.36.2.4 bouyer NCRCMD(sc, NCRCMD_SELNATN);
688 1.36.2.4 bouyer }
689 1.36.2.4 bouyer return;
690 1.36.2.4 bouyer }
691 1.36.2.4 bouyer
692 1.36.2.16 bouyer selatn3 = selatns = 0;
693 1.36.2.16 bouyer if (ecb->tag[0] != 0) {
694 1.36.2.16 bouyer if (sc->sc_features & NCR_F_SELATN3)
695 1.36.2.16 bouyer /* use SELATN3 to send tag messages */
696 1.36.2.16 bouyer selatn3 = 1;
697 1.36.2.16 bouyer else
698 1.36.2.16 bouyer /* We don't have SELATN3; use SELATNS to send tags */
699 1.36.2.16 bouyer selatns = 1;
700 1.36.2.16 bouyer }
701 1.36.2.16 bouyer
702 1.36.2.16 bouyer if (ti->flags & T_NEGOTIATE) {
703 1.36.2.16 bouyer /* We have to use SELATNS to send sync/wide messages */
704 1.36.2.16 bouyer selatn3 = 0;
705 1.36.2.16 bouyer selatns = 1;
706 1.36.2.16 bouyer }
707 1.36.2.11 bouyer
708 1.36.2.16 bouyer cmd = (u_char *)&ecb->cmd.cmd;
709 1.36.2.11 bouyer
710 1.36.2.16 bouyer if (selatn3) {
711 1.36.2.16 bouyer /* We'll use tags with SELATN3 */
712 1.36.2.6 bouyer clen = ecb->clen + 3;
713 1.36.2.11 bouyer cmd -= 3;
714 1.36.2.11 bouyer cmd[0] = MSG_IDENTIFY(lun, 1); /* msg[0] */
715 1.36.2.11 bouyer cmd[1] = ecb->tag[0]; /* msg[1] */
716 1.36.2.11 bouyer cmd[2] = ecb->tag[1]; /* msg[2] */
717 1.36.2.6 bouyer } else {
718 1.36.2.16 bouyer /* We don't have tags, or will send messages with SELATNS */
719 1.36.2.6 bouyer clen = ecb->clen + 1;
720 1.36.2.11 bouyer cmd -= 1;
721 1.36.2.16 bouyer cmd[0] = MSG_IDENTIFY(lun, (tiflags & T_RSELECTOFF) == 0);
722 1.36.2.6 bouyer }
723 1.36.2.6 bouyer
724 1.36.2.16 bouyer if ((sc->sc_features & NCR_F_DMASELECT) && !selatns) {
725 1.22 pk
726 1.8 pk /* setup DMA transfer for command */
727 1.36.2.6 bouyer dmasize = clen;
728 1.8 pk sc->sc_cmdlen = clen;
729 1.36.2.6 bouyer sc->sc_cmdp = cmd;
730 1.22 pk
731 1.8 pk /* Program the SCSI counter */
732 1.36.2.15 bouyer NCR_SET_COUNT(sc, dmasize);
733 1.8 pk
734 1.22 pk /* load the count in */
735 1.36.2.15 bouyer /* if (sc->sc_rev != NCR_VARIANT_FAS366) */
736 1.36.2.15 bouyer NCRCMD(sc, NCRCMD_NOP|NCRCMD_DMA);
737 1.22 pk
738 1.8 pk /* And get the targets attention */
739 1.36.2.11 bouyer if (selatn3) {
740 1.36.2.11 bouyer sc->sc_msgout = SEND_TAG;
741 1.36.2.11 bouyer sc->sc_flags |= NCR_ATN;
742 1.36.2.6 bouyer NCRCMD(sc, NCRCMD_SELATN3 | NCRCMD_DMA);
743 1.36.2.11 bouyer } else
744 1.36.2.6 bouyer NCRCMD(sc, NCRCMD_SELATN | NCRCMD_DMA);
745 1.36.2.15 bouyer NCRDMA_SETUP(sc, &sc->sc_cmdp, &sc->sc_cmdlen, 0, &dmasize);
746 1.8 pk NCRDMA_GO(sc);
747 1.8 pk return;
748 1.8 pk }
749 1.22 pk
750 1.1 thorpej /*
751 1.1 thorpej * Who am I. This is where we tell the target that we are
752 1.1 thorpej * happy for it to disconnect etc.
753 1.1 thorpej */
754 1.1 thorpej
755 1.36.2.6 bouyer /* Now get the command into the FIFO */
756 1.36.2.15 bouyer ncr53c9x_wrfifo(sc, cmd, clen);
757 1.1 thorpej
758 1.1 thorpej /* And get the targets attention */
759 1.36.2.16 bouyer if (selatns) {
760 1.36.2.16 bouyer NCR_MISC(("SELATNS \n"));
761 1.36.2.16 bouyer /* Arbitrate, select and stop after IDENTIFY message */
762 1.36.2.16 bouyer NCRCMD(sc, NCRCMD_SELATNS);
763 1.36.2.16 bouyer } else if (selatn3) {
764 1.36.2.11 bouyer sc->sc_msgout = SEND_TAG;
765 1.36.2.11 bouyer sc->sc_flags |= NCR_ATN;
766 1.36.2.6 bouyer NCRCMD(sc, NCRCMD_SELATN3);
767 1.36.2.11 bouyer } else
768 1.36.2.6 bouyer NCRCMD(sc, NCRCMD_SELATN);
769 1.1 thorpej }
770 1.1 thorpej
771 1.1 thorpej void
772 1.36.2.2 thorpej ncr53c9x_free_ecb(sc, ecb)
773 1.1 thorpej struct ncr53c9x_softc *sc;
774 1.1 thorpej struct ncr53c9x_ecb *ecb;
775 1.1 thorpej {
776 1.1 thorpej int s;
777 1.1 thorpej
778 1.1 thorpej s = splbio();
779 1.1 thorpej ecb->flags = 0;
780 1.36.2.6 bouyer pool_put(&ecb_pool, (void *)ecb);
781 1.1 thorpej splx(s);
782 1.36.2.6 bouyer return;
783 1.1 thorpej }
784 1.1 thorpej
785 1.1 thorpej struct ncr53c9x_ecb *
786 1.36.2.6 bouyer ncr53c9x_get_ecb(sc, flags)
787 1.1 thorpej struct ncr53c9x_softc *sc;
788 1.36.2.6 bouyer int flags;
789 1.1 thorpej {
790 1.1 thorpej struct ncr53c9x_ecb *ecb;
791 1.36.2.6 bouyer int s, wait = 0;
792 1.36.2.6 bouyer
793 1.36.2.6 bouyer if ((curproc != NULL) && ((flags & XS_CTL_NOSLEEP) == 0))
794 1.36.2.6 bouyer wait = PR_WAITOK;
795 1.1 thorpej
796 1.1 thorpej s = splbio();
797 1.36.2.6 bouyer ecb = (struct ncr53c9x_ecb *)pool_get(&ecb_pool, wait);
798 1.1 thorpej splx(s);
799 1.36.2.6 bouyer bzero(ecb, sizeof(*ecb));
800 1.36.2.6 bouyer if (ecb)
801 1.36.2.6 bouyer ecb->flags |= ECB_ALLOC;
802 1.25 pk return (ecb);
803 1.1 thorpej }
804 1.1 thorpej
805 1.1 thorpej /*
806 1.1 thorpej * DRIVER FUNCTIONS CALLABLE FROM HIGHER LEVEL DRIVERS
807 1.1 thorpej */
808 1.1 thorpej
809 1.1 thorpej /*
810 1.1 thorpej * Start a SCSI-command
811 1.1 thorpej * This function is called by the higher level SCSI-driver to queue/run
812 1.1 thorpej * SCSI-commands.
813 1.1 thorpej */
814 1.36.2.4 bouyer
815 1.36.2.1 thorpej void
816 1.36.2.1 thorpej ncr53c9x_scsipi_request(chan, req, arg)
817 1.36.2.1 thorpej struct scsipi_channel *chan;
818 1.36.2.1 thorpej scsipi_adapter_req_t req;
819 1.36.2.1 thorpej void *arg;
820 1.1 thorpej {
821 1.36.2.1 thorpej struct scsipi_xfer *xs;
822 1.36.2.1 thorpej struct scsipi_periph *periph;
823 1.36.2.1 thorpej struct ncr53c9x_softc *sc = (void *)chan->chan_adapter->adapt_dev;
824 1.1 thorpej struct ncr53c9x_ecb *ecb;
825 1.1 thorpej int s, flags;
826 1.1 thorpej
827 1.36.2.1 thorpej NCR_TRACE(("[ncr53c9x_scsipi_request] "));
828 1.1 thorpej
829 1.36.2.1 thorpej switch (req) {
830 1.36.2.1 thorpej case ADAPTER_REQ_RUN_XFER:
831 1.36.2.1 thorpej xs = arg;
832 1.36.2.1 thorpej periph = xs->xs_periph;
833 1.36.2.1 thorpej flags = xs->xs_control;
834 1.36.2.1 thorpej
835 1.36.2.1 thorpej NCR_CMDS(("[0x%x, %d]->%d ", (int)xs->cmd->opcode, xs->cmdlen,
836 1.36.2.1 thorpej periph->periph_target));
837 1.36.2.1 thorpej
838 1.36.2.1 thorpej /* Get an ECB to use. */
839 1.36.2.6 bouyer ecb = ncr53c9x_get_ecb(sc, xs->xs_control);
840 1.36.2.1 thorpej #ifdef DIAGNOSTIC
841 1.36.2.1 thorpej /*
842 1.36.2.1 thorpej * This should never happen as we track resources
843 1.36.2.1 thorpej * in the mid-layer.
844 1.36.2.1 thorpej */
845 1.36.2.1 thorpej if (ecb == NULL) {
846 1.36.2.1 thorpej scsipi_printaddr(periph);
847 1.36.2.1 thorpej printf("unable to allocate ecb\n");
848 1.36.2.1 thorpej panic("ncr53c9x_scsipi_request");
849 1.36.2.1 thorpej }
850 1.36.2.1 thorpej #endif
851 1.1 thorpej
852 1.36.2.1 thorpej /* Initialize ecb */
853 1.36.2.1 thorpej ecb->xs = xs;
854 1.36.2.1 thorpej ecb->timeout = xs->timeout;
855 1.36.2.1 thorpej
856 1.36.2.1 thorpej if (flags & XS_CTL_RESET) {
857 1.36.2.1 thorpej ecb->flags |= ECB_RESET;
858 1.36.2.1 thorpej ecb->clen = 0;
859 1.36.2.1 thorpej ecb->dleft = 0;
860 1.36.2.1 thorpej } else {
861 1.36.2.1 thorpej bcopy(xs->cmd, &ecb->cmd.cmd, xs->cmdlen);
862 1.36.2.1 thorpej ecb->clen = xs->cmdlen;
863 1.36.2.1 thorpej ecb->daddr = xs->data;
864 1.36.2.1 thorpej ecb->dleft = xs->datalen;
865 1.36.2.1 thorpej }
866 1.36.2.1 thorpej ecb->stat = 0;
867 1.1 thorpej
868 1.36.2.1 thorpej s = splbio();
869 1.36.2.1 thorpej
870 1.36.2.1 thorpej TAILQ_INSERT_TAIL(&sc->ready_list, ecb, chain);
871 1.36.2.1 thorpej if (sc->sc_state == NCR_IDLE)
872 1.36.2.1 thorpej ncr53c9x_sched(sc);
873 1.1 thorpej
874 1.36.2.1 thorpej splx(s);
875 1.1 thorpej
876 1.36.2.1 thorpej if ((flags & XS_CTL_POLL) == 0)
877 1.36.2.1 thorpej return;
878 1.36.2.1 thorpej
879 1.36.2.1 thorpej /* Not allowed to use interrupts, use polling instead */
880 1.36.2.1 thorpej if (ncr53c9x_poll(sc, xs, ecb->timeout)) {
881 1.1 thorpej ncr53c9x_timeout(ecb);
882 1.36.2.1 thorpej if (ncr53c9x_poll(sc, xs, ecb->timeout))
883 1.36.2.1 thorpej ncr53c9x_timeout(ecb);
884 1.36.2.1 thorpej }
885 1.36.2.1 thorpej return;
886 1.36.2.1 thorpej
887 1.36.2.1 thorpej case ADAPTER_REQ_GROW_RESOURCES:
888 1.36.2.1 thorpej /* XXX Not supported. */
889 1.36.2.1 thorpej return;
890 1.36.2.1 thorpej
891 1.36.2.1 thorpej case ADAPTER_REQ_SET_XFER_MODE:
892 1.36.2.1 thorpej {
893 1.36.2.1 thorpej struct ncr53c9x_tinfo *ti;
894 1.36.2.3 thorpej struct scsipi_xfer_mode *xm = arg;
895 1.36.2.3 thorpej
896 1.36.2.3 thorpej ti = &sc->sc_tinfo[xm->xm_target];
897 1.36.2.3 thorpej ti->flags &= ~(T_NEGOTIATE|T_SYNCMODE);
898 1.36.2.3 thorpej ti->period = 0;
899 1.36.2.3 thorpej ti->offset = 0;
900 1.36.2.3 thorpej
901 1.36.2.8 bouyer if ((sc->sc_cfflags & (1<<(xm->xm_target+16))) == 0 &&
902 1.36.2.8 bouyer (xm->xm_mode & PERIPH_CAP_TQING))
903 1.36.2.13 bouyer ti->flags |= T_TAG;
904 1.36.2.8 bouyer else
905 1.36.2.13 bouyer ti->flags &= ~T_TAG;
906 1.36.2.8 bouyer
907 1.36.2.15 bouyer if ((xm->xm_mode & PERIPH_CAP_WIDE16) != 0) {
908 1.36.2.15 bouyer NCR_MISC(("%s: target %d: wide scsi negotiation\n",
909 1.36.2.15 bouyer sc->sc_dev.dv_xname, xm->xm_target));
910 1.36.2.15 bouyer if (sc->sc_rev == NCR_VARIANT_FAS366) {
911 1.36.2.15 bouyer ti->flags |= T_WIDE;
912 1.36.2.15 bouyer ti->width = 1;
913 1.36.2.15 bouyer }
914 1.36.2.15 bouyer }
915 1.36.2.15 bouyer
916 1.36.2.3 thorpej if ((xm->xm_mode & PERIPH_CAP_SYNC) != 0 &&
917 1.36.2.16 bouyer (ti->flags & T_SYNCHOFF) == 0 && sc->sc_minsync != 0) {
918 1.36.2.16 bouyer NCR_MISC(("%s: target %d: sync negotiation\n",
919 1.36.2.16 bouyer sc->sc_dev.dv_xname, xm->xm_target));
920 1.36.2.1 thorpej ti->flags |= T_NEGOTIATE;
921 1.36.2.1 thorpej ti->period = sc->sc_minsync;
922 1.36.2.1 thorpej }
923 1.36.2.3 thorpej /*
924 1.36.2.3 thorpej * If we're not going to negotiate, send the notification
925 1.36.2.3 thorpej * now, since it won't happen later.
926 1.36.2.3 thorpej */
927 1.36.2.3 thorpej if ((ti->flags & T_NEGOTIATE) == 0)
928 1.36.2.3 thorpej ncr53c9x_update_xfer_mode(sc, xm->xm_target);
929 1.36.2.1 thorpej return;
930 1.36.2.1 thorpej }
931 1.36.2.3 thorpej }
932 1.36.2.3 thorpej }
933 1.36.2.1 thorpej
934 1.36.2.3 thorpej void
935 1.36.2.3 thorpej ncr53c9x_update_xfer_mode(sc, target)
936 1.36.2.3 thorpej struct ncr53c9x_softc *sc;
937 1.36.2.3 thorpej int target;
938 1.36.2.3 thorpej {
939 1.36.2.3 thorpej struct scsipi_xfer_mode xm;
940 1.36.2.3 thorpej struct ncr53c9x_tinfo *ti = &sc->sc_tinfo[target];
941 1.36.2.1 thorpej
942 1.36.2.3 thorpej xm.xm_target = target;
943 1.36.2.3 thorpej xm.xm_mode = 0;
944 1.36.2.3 thorpej xm.xm_period = 0;
945 1.36.2.3 thorpej xm.xm_offset = 0;
946 1.36.2.3 thorpej
947 1.36.2.3 thorpej if (ti->flags & T_SYNCMODE) {
948 1.36.2.3 thorpej xm.xm_mode |= PERIPH_CAP_SYNC;
949 1.36.2.3 thorpej xm.xm_period = ti->period;
950 1.36.2.3 thorpej xm.xm_offset = ti->offset;
951 1.1 thorpej }
952 1.36.2.17 bouyer if (ti->width)
953 1.36.2.15 bouyer xm.xm_mode |= PERIPH_CAP_WIDE16;
954 1.36.2.15 bouyer
955 1.36.2.17 bouyer if ((ti->flags & (T_RSELECTOFF|T_TAG)) == T_TAG)
956 1.36.2.8 bouyer xm.xm_mode |= PERIPH_CAP_TQING;
957 1.36.2.3 thorpej
958 1.36.2.3 thorpej scsipi_async_event(&sc->sc_channel, ASYNC_EVENT_XFER_MODE, &xm);
959 1.1 thorpej }
960 1.1 thorpej
961 1.1 thorpej /*
962 1.1 thorpej * Used when interrupt driven I/O isn't allowed, e.g. during boot.
963 1.1 thorpej */
964 1.1 thorpej int
965 1.1 thorpej ncr53c9x_poll(sc, xs, count)
966 1.1 thorpej struct ncr53c9x_softc *sc;
967 1.18 bouyer struct scsipi_xfer *xs;
968 1.1 thorpej int count;
969 1.1 thorpej {
970 1.1 thorpej
971 1.1 thorpej NCR_TRACE(("[ncr53c9x_poll] "));
972 1.1 thorpej while (count) {
973 1.1 thorpej if (NCRDMA_ISINTR(sc)) {
974 1.1 thorpej ncr53c9x_intr(sc);
975 1.1 thorpej }
976 1.1 thorpej #if alternatively
977 1.1 thorpej if (NCR_READ_REG(sc, NCR_STAT) & NCRSTAT_INT)
978 1.1 thorpej ncr53c9x_intr(sc);
979 1.1 thorpej #endif
980 1.36 thorpej if ((xs->xs_status & XS_STS_DONE) != 0)
981 1.25 pk return (0);
982 1.1 thorpej if (sc->sc_state == NCR_IDLE) {
983 1.1 thorpej NCR_TRACE(("[ncr53c9x_poll: rescheduling] "));
984 1.1 thorpej ncr53c9x_sched(sc);
985 1.1 thorpej }
986 1.1 thorpej DELAY(1000);
987 1.1 thorpej count--;
988 1.1 thorpej }
989 1.25 pk return (1);
990 1.1 thorpej }
991 1.1 thorpej
992 1.36.2.5 bouyer int
993 1.36.2.5 bouyer ncr53c9x_ioctl(chan, cmd, arg, flag, p)
994 1.36.2.5 bouyer struct scsipi_channel *chan;
995 1.36.2.5 bouyer u_long cmd;
996 1.36.2.5 bouyer caddr_t arg;
997 1.36.2.5 bouyer int flag;
998 1.36.2.5 bouyer struct proc *p;
999 1.36.2.5 bouyer {
1000 1.36.2.8 bouyer /* struct ncr53c9x_softc *sc = (void *)chan->chan_adapter->adapt_dev; */
1001 1.36.2.6 bouyer int s, error = 0;
1002 1.36.2.5 bouyer
1003 1.36.2.5 bouyer s = splbio();
1004 1.36.2.5 bouyer
1005 1.36.2.5 bouyer switch (cmd) {
1006 1.36.2.5 bouyer default:
1007 1.36.2.5 bouyer error = ENOTTY;
1008 1.36.2.5 bouyer break;
1009 1.36.2.5 bouyer }
1010 1.36.2.5 bouyer splx(s);
1011 1.36.2.5 bouyer return (error);
1012 1.36.2.5 bouyer }
1013 1.36.2.5 bouyer
1014 1.1 thorpej
1015 1.1 thorpej /*
1016 1.1 thorpej * LOW LEVEL SCSI UTILITIES
1017 1.1 thorpej */
1018 1.1 thorpej
1019 1.1 thorpej /*
1020 1.1 thorpej * Schedule a scsi operation. This has now been pulled out of the interrupt
1021 1.36.2.1 thorpej * handler so that we may call it from ncr53c9x_scsipi_request and
1022 1.36.2.1 thorpej * ncr53c9x_done. This may save us an unecessary interrupt just to get
1023 1.36.2.1 thorpej * things going. Should only be called when state == NCR_IDLE and at bio pl.
1024 1.1 thorpej */
1025 1.1 thorpej void
1026 1.1 thorpej ncr53c9x_sched(sc)
1027 1.1 thorpej struct ncr53c9x_softc *sc;
1028 1.1 thorpej {
1029 1.1 thorpej struct ncr53c9x_ecb *ecb;
1030 1.36.2.1 thorpej struct scsipi_periph *periph;
1031 1.1 thorpej struct ncr53c9x_tinfo *ti;
1032 1.36.2.6 bouyer int lun;
1033 1.36.2.6 bouyer struct ncr53c9x_linfo *li;
1034 1.36.2.6 bouyer int s, tag;
1035 1.1 thorpej
1036 1.1 thorpej NCR_TRACE(("[ncr53c9x_sched] "));
1037 1.1 thorpej if (sc->sc_state != NCR_IDLE)
1038 1.1 thorpej panic("ncr53c9x_sched: not IDLE (state=%d)", sc->sc_state);
1039 1.1 thorpej
1040 1.1 thorpej /*
1041 1.1 thorpej * Find first ecb in ready queue that is for a target/lunit
1042 1.1 thorpej * combinations that is not busy.
1043 1.1 thorpej */
1044 1.36.2.6 bouyer for (ecb = TAILQ_FIRST(&sc->ready_list); ecb != NULL;
1045 1.36.2.6 bouyer ecb = TAILQ_NEXT(ecb, chain)) {
1046 1.36.2.1 thorpej periph = ecb->xs->xs_periph;
1047 1.36.2.1 thorpej ti = &sc->sc_tinfo[periph->periph_target];
1048 1.36.2.6 bouyer lun = periph->periph_lun;
1049 1.36.2.6 bouyer
1050 1.36.2.6 bouyer /* Select type of tag for this command */
1051 1.36.2.16 bouyer if ((ti->flags & (T_RSELECTOFF)) != 0)
1052 1.36.2.13 bouyer tag = 0;
1053 1.36.2.13 bouyer else if ((ti->flags & (T_TAG)) == 0)
1054 1.36.2.6 bouyer tag = 0;
1055 1.36.2.6 bouyer else if ((ecb->flags & ECB_SENSE) != 0)
1056 1.36.2.6 bouyer tag = 0;
1057 1.36.2.6 bouyer else
1058 1.36.2.6 bouyer tag = ecb->xs->xs_tag_type;
1059 1.36.2.6 bouyer #if 0
1060 1.36.2.6 bouyer /* XXXX Use tags for polled commands? */
1061 1.36.2.6 bouyer if (ecb->xs->xs_control & XS_CTL_POLL)
1062 1.36.2.6 bouyer tag = 0;
1063 1.36.2.6 bouyer #endif
1064 1.36.2.6 bouyer
1065 1.36.2.6 bouyer s = splbio();
1066 1.36.2.6 bouyer li = TINFO_LUN(ti, lun);
1067 1.36.2.6 bouyer if (li == NULL) {
1068 1.36.2.6 bouyer int wait = M_NOWAIT;
1069 1.36.2.6 bouyer int flags = ecb->xs->xs_control;
1070 1.36.2.6 bouyer
1071 1.36.2.6 bouyer /* Initialize LUN info and add to list. */
1072 1.36.2.16 bouyer if ((curproc != NULL) &&
1073 1.36.2.16 bouyer ((flags & XS_CTL_NOSLEEP) == 0))
1074 1.36.2.6 bouyer wait = M_WAITOK;
1075 1.36.2.16 bouyer if ((li = malloc(sizeof(*li), M_DEVBUF, M_NOWAIT))
1076 1.36.2.16 bouyer == NULL) {
1077 1.36.2.6 bouyer splx(s);
1078 1.36.2.6 bouyer continue;
1079 1.36.2.6 bouyer }
1080 1.36.2.6 bouyer bzero(li, sizeof(*li));
1081 1.36.2.6 bouyer li->lun = lun;
1082 1.36.2.6 bouyer
1083 1.36.2.6 bouyer LIST_INSERT_HEAD(&ti->luns, li, link);
1084 1.36.2.6 bouyer if (lun < NCR_NLUN)
1085 1.36.2.6 bouyer ti->lun[lun] = li;
1086 1.36.2.6 bouyer }
1087 1.36.2.6 bouyer li->last_used = time.tv_sec;
1088 1.36.2.6 bouyer if (tag == 0) {
1089 1.36.2.6 bouyer /* Try to issue this as an un-tagged command */
1090 1.36.2.6 bouyer if (li->untagged == NULL)
1091 1.36.2.6 bouyer li->untagged = ecb;
1092 1.36.2.6 bouyer }
1093 1.36.2.6 bouyer if (li->untagged != NULL) {
1094 1.36.2.6 bouyer tag = 0;
1095 1.36.2.6 bouyer if ((li->busy != 1) && li->used == 0) {
1096 1.36.2.6 bouyer /* We need to issue this untagged command now */
1097 1.36.2.6 bouyer ecb = li->untagged;
1098 1.36.2.6 bouyer periph = ecb->xs->xs_periph;
1099 1.36.2.16 bouyer } else {
1100 1.36.2.6 bouyer /* Not ready yet */
1101 1.36.2.6 bouyer splx(s);
1102 1.36.2.6 bouyer continue;
1103 1.36.2.6 bouyer }
1104 1.36.2.6 bouyer }
1105 1.36.2.6 bouyer ecb->tag[0] = tag;
1106 1.36.2.6 bouyer if (tag != 0) {
1107 1.36.2.6 bouyer li->queued[ecb->xs->xs_tag_id] = ecb;
1108 1.36.2.6 bouyer ecb->tag[1] = ecb->xs->xs_tag_id;
1109 1.36.2.6 bouyer }
1110 1.36.2.6 bouyer splx(s);
1111 1.36.2.6 bouyer if (li->untagged != NULL && (li->busy != 1)) {
1112 1.36.2.6 bouyer li->busy = 1;
1113 1.36.2.6 bouyer TAILQ_REMOVE(&sc->ready_list, ecb, chain);
1114 1.36.2.6 bouyer ecb->flags &= ~ECB_READY;
1115 1.36.2.6 bouyer sc->sc_nexus = ecb;
1116 1.36.2.6 bouyer ncr53c9x_select(sc, ecb);
1117 1.36.2.6 bouyer break;
1118 1.36.2.6 bouyer }
1119 1.36.2.6 bouyer if (li->untagged == NULL && tag != 0) {
1120 1.1 thorpej TAILQ_REMOVE(&sc->ready_list, ecb, chain);
1121 1.36.2.6 bouyer ecb->flags &= ~ECB_READY;
1122 1.1 thorpej sc->sc_nexus = ecb;
1123 1.1 thorpej ncr53c9x_select(sc, ecb);
1124 1.1 thorpej break;
1125 1.1 thorpej } else
1126 1.1 thorpej NCR_MISC(("%d:%d busy\n",
1127 1.36.2.16 bouyer periph->periph_target,
1128 1.36.2.16 bouyer periph->periph_lun));
1129 1.1 thorpej }
1130 1.1 thorpej }
1131 1.1 thorpej
1132 1.1 thorpej void
1133 1.1 thorpej ncr53c9x_sense(sc, ecb)
1134 1.1 thorpej struct ncr53c9x_softc *sc;
1135 1.1 thorpej struct ncr53c9x_ecb *ecb;
1136 1.1 thorpej {
1137 1.18 bouyer struct scsipi_xfer *xs = ecb->xs;
1138 1.36.2.1 thorpej struct scsipi_periph *periph = xs->xs_periph;
1139 1.36.2.1 thorpej struct ncr53c9x_tinfo *ti = &sc->sc_tinfo[periph->periph_target];
1140 1.18 bouyer struct scsipi_sense *ss = (void *)&ecb->cmd.cmd;
1141 1.36.2.6 bouyer struct ncr53c9x_linfo *li;
1142 1.36.2.6 bouyer int lun = periph->periph_lun;
1143 1.1 thorpej
1144 1.1 thorpej NCR_MISC(("requesting sense "));
1145 1.1 thorpej /* Next, setup a request sense command block */
1146 1.1 thorpej bzero(ss, sizeof(*ss));
1147 1.1 thorpej ss->opcode = REQUEST_SENSE;
1148 1.36.2.16 bouyer ss->byte2 = periph->periph_lun << SCSI_CMD_LUN_SHIFT;
1149 1.18 bouyer ss->length = sizeof(struct scsipi_sense_data);
1150 1.1 thorpej ecb->clen = sizeof(*ss);
1151 1.18 bouyer ecb->daddr = (char *)&xs->sense.scsi_sense;
1152 1.18 bouyer ecb->dleft = sizeof(struct scsipi_sense_data);
1153 1.1 thorpej ecb->flags |= ECB_SENSE;
1154 1.7 gwr ecb->timeout = NCR_SENSE_TIMEOUT;
1155 1.1 thorpej ti->senses++;
1156 1.36.2.6 bouyer li = TINFO_LUN(ti, lun);
1157 1.36.2.16 bouyer if (li->busy)
1158 1.36.2.16 bouyer li->busy = 0;
1159 1.36.2.6 bouyer ncr53c9x_dequeue(sc, ecb);
1160 1.36.2.6 bouyer li->untagged = ecb; /* must be executed first to fix C/A */
1161 1.36.2.6 bouyer li->busy = 2;
1162 1.1 thorpej if (ecb == sc->sc_nexus) {
1163 1.1 thorpej ncr53c9x_select(sc, ecb);
1164 1.1 thorpej } else {
1165 1.1 thorpej TAILQ_INSERT_HEAD(&sc->ready_list, ecb, chain);
1166 1.36.2.6 bouyer ecb->flags |= ECB_READY;
1167 1.1 thorpej if (sc->sc_state == NCR_IDLE)
1168 1.1 thorpej ncr53c9x_sched(sc);
1169 1.1 thorpej }
1170 1.1 thorpej }
1171 1.1 thorpej
1172 1.1 thorpej /*
1173 1.1 thorpej * POST PROCESSING OF SCSI_CMD (usually current)
1174 1.1 thorpej */
1175 1.1 thorpej void
1176 1.1 thorpej ncr53c9x_done(sc, ecb)
1177 1.1 thorpej struct ncr53c9x_softc *sc;
1178 1.1 thorpej struct ncr53c9x_ecb *ecb;
1179 1.1 thorpej {
1180 1.18 bouyer struct scsipi_xfer *xs = ecb->xs;
1181 1.36.2.1 thorpej struct scsipi_periph *periph = xs->xs_periph;
1182 1.36.2.1 thorpej struct ncr53c9x_tinfo *ti = &sc->sc_tinfo[periph->periph_target];
1183 1.36.2.6 bouyer int lun = periph->periph_lun;
1184 1.36.2.6 bouyer struct ncr53c9x_linfo *li = TINFO_LUN(ti, lun);
1185 1.1 thorpej
1186 1.1 thorpej NCR_TRACE(("[ncr53c9x_done(error:%x)] ", xs->error));
1187 1.1 thorpej
1188 1.36.2.4 bouyer callout_stop(&ecb->xs->xs_callout);
1189 1.7 gwr
1190 1.1 thorpej /*
1191 1.1 thorpej * Now, if we've come here with no error code, i.e. we've kept the
1192 1.1 thorpej * initial XS_NOERROR, and the status code signals that we should
1193 1.1 thorpej * check sense, we'll need to set up a request sense cmd block and
1194 1.1 thorpej * push the command back into the ready queue *before* any other
1195 1.1 thorpej * commands for this target/lunit, else we lose the sense info.
1196 1.1 thorpej * We don't support chk sense conditions for the request sense cmd.
1197 1.1 thorpej */
1198 1.1 thorpej if (xs->error == XS_NOERROR) {
1199 1.12 pk xs->status = ecb->stat;
1200 1.1 thorpej if ((ecb->flags & ECB_ABORT) != 0) {
1201 1.16 pk xs->error = XS_TIMEOUT;
1202 1.1 thorpej } else if ((ecb->flags & ECB_SENSE) != 0) {
1203 1.1 thorpej xs->error = XS_SENSE;
1204 1.1 thorpej } else if ((ecb->stat & ST_MASK) == SCSI_CHECK) {
1205 1.1 thorpej /* First, save the return values */
1206 1.1 thorpej xs->resid = ecb->dleft;
1207 1.1 thorpej ncr53c9x_sense(sc, ecb);
1208 1.1 thorpej return;
1209 1.1 thorpej } else {
1210 1.1 thorpej xs->resid = ecb->dleft;
1211 1.36.2.8 bouyer }
1212 1.36.2.9 bouyer if (xs->status == SCSI_QUEUE_FULL)
1213 1.36.2.8 bouyer xs->error = XS_BUSY;
1214 1.1 thorpej }
1215 1.1 thorpej
1216 1.1 thorpej #ifdef NCR53C9X_DEBUG
1217 1.1 thorpej if (ncr53c9x_debug & NCR_SHOWMISC) {
1218 1.1 thorpej if (xs->resid != 0)
1219 1.1 thorpej printf("resid=%d ", xs->resid);
1220 1.1 thorpej if (xs->error == XS_SENSE)
1221 1.36.2.16 bouyer printf("sense=0x%02x\n",
1222 1.36.2.16 bouyer xs->sense.scsi_sense.error_code);
1223 1.1 thorpej else
1224 1.1 thorpej printf("error=%d\n", xs->error);
1225 1.1 thorpej }
1226 1.1 thorpej #endif
1227 1.1 thorpej
1228 1.1 thorpej /*
1229 1.1 thorpej * Remove the ECB from whatever queue it's on.
1230 1.1 thorpej */
1231 1.36.2.6 bouyer ncr53c9x_dequeue(sc, ecb);
1232 1.1 thorpej if (ecb == sc->sc_nexus) {
1233 1.1 thorpej sc->sc_nexus = NULL;
1234 1.15 pk if (sc->sc_state != NCR_CLEANING) {
1235 1.15 pk sc->sc_state = NCR_IDLE;
1236 1.15 pk ncr53c9x_sched(sc);
1237 1.15 pk }
1238 1.36.2.6 bouyer }
1239 1.36.2.6 bouyer
1240 1.36.2.6 bouyer if (xs->error == XS_SELTIMEOUT) {
1241 1.36.2.6 bouyer /* Selection timeout -- discard this LUN if empty */
1242 1.36.2.6 bouyer if (li->untagged == NULL && li->used == 0) {
1243 1.36.2.6 bouyer if (lun < NCR_NLUN)
1244 1.36.2.6 bouyer ti->lun[lun] = NULL;
1245 1.36.2.6 bouyer LIST_REMOVE(li, link);
1246 1.36.2.6 bouyer free(li, M_DEVBUF);
1247 1.36.2.6 bouyer }
1248 1.36.2.6 bouyer }
1249 1.36.2.6 bouyer
1250 1.36.2.2 thorpej ncr53c9x_free_ecb(sc, ecb);
1251 1.1 thorpej ti->cmds++;
1252 1.18 bouyer scsipi_done(xs);
1253 1.1 thorpej }
1254 1.1 thorpej
1255 1.1 thorpej void
1256 1.1 thorpej ncr53c9x_dequeue(sc, ecb)
1257 1.1 thorpej struct ncr53c9x_softc *sc;
1258 1.1 thorpej struct ncr53c9x_ecb *ecb;
1259 1.1 thorpej {
1260 1.36.2.6 bouyer struct ncr53c9x_tinfo *ti =
1261 1.36.2.16 bouyer &sc->sc_tinfo[ecb->xs->xs_periph->periph_target];
1262 1.36.2.6 bouyer struct ncr53c9x_linfo *li;
1263 1.36.2.6 bouyer int64_t lun = ecb->xs->xs_periph->periph_lun;
1264 1.36.2.6 bouyer
1265 1.36.2.6 bouyer li = TINFO_LUN(ti, lun);
1266 1.36.2.6 bouyer #ifdef DIAGNOSTIC
1267 1.36.2.6 bouyer if (li == NULL || li->lun != lun)
1268 1.36.2.6 bouyer panic("ncr53c9x_dequeue: lun %qx for ecb %p does not exist\n",
1269 1.36.2.6 bouyer (long long) lun, ecb);
1270 1.36.2.6 bouyer #endif
1271 1.36.2.6 bouyer if (li->untagged == ecb) {
1272 1.36.2.6 bouyer li->busy = 0;
1273 1.36.2.6 bouyer li->untagged = NULL;
1274 1.36.2.6 bouyer }
1275 1.36.2.6 bouyer if (ecb->tag[0] && li->queued[ecb->tag[1]] != NULL) {
1276 1.36.2.6 bouyer #ifdef DIAGNOSTIC
1277 1.36.2.6 bouyer if (li->queued[ecb->tag[1]] != NULL &&
1278 1.36.2.6 bouyer (li->queued[ecb->tag[1]] != ecb))
1279 1.36.2.6 bouyer panic("ncr53c9x_dequeue: slot %d for lun %qx has %p "
1280 1.36.2.16 bouyer "instead of ecb %p\n", ecb->tag[1],
1281 1.36.2.16 bouyer (long long) lun,
1282 1.36.2.16 bouyer li->queued[ecb->tag[1]], ecb);
1283 1.36.2.6 bouyer #endif
1284 1.36.2.6 bouyer li->queued[ecb->tag[1]] = NULL;
1285 1.36.2.16 bouyer li->used--;
1286 1.36.2.16 bouyer }
1287 1.1 thorpej
1288 1.36.2.6 bouyer if ((ecb->flags & ECB_READY) != 0) {
1289 1.36.2.6 bouyer ecb->flags &= ~ECB_READY;
1290 1.1 thorpej TAILQ_REMOVE(&sc->ready_list, ecb, chain);
1291 1.1 thorpej }
1292 1.1 thorpej }
1293 1.1 thorpej
1294 1.1 thorpej /*
1295 1.1 thorpej * INTERRUPT/PROTOCOL ENGINE
1296 1.1 thorpej */
1297 1.1 thorpej
1298 1.1 thorpej /*
1299 1.1 thorpej * Schedule an outgoing message by prioritizing it, and asserting
1300 1.1 thorpej * attention on the bus. We can only do this when we are the initiator
1301 1.1 thorpej * else there will be an illegal command interrupt.
1302 1.1 thorpej */
1303 1.1 thorpej #define ncr53c9x_sched_msgout(m) \
1304 1.1 thorpej do { \
1305 1.36.2.6 bouyer NCR_MISC(("ncr53c9x_sched_msgout %x %d", m, __LINE__)); \
1306 1.1 thorpej NCRCMD(sc, NCRCMD_SETATN); \
1307 1.1 thorpej sc->sc_flags |= NCR_ATN; \
1308 1.1 thorpej sc->sc_msgpriq |= (m); \
1309 1.1 thorpej } while (0)
1310 1.1 thorpej
1311 1.36.2.15 bouyer static void
1312 1.36.2.15 bouyer ncr53c9x_flushfifo(struct ncr53c9x_softc *sc)
1313 1.36.2.15 bouyer {
1314 1.36.2.15 bouyer NCR_MISC(("[flushfifo] "));
1315 1.36.2.15 bouyer
1316 1.36.2.15 bouyer NCRCMD(sc, NCRCMD_FLUSH);
1317 1.36.2.15 bouyer
1318 1.36.2.15 bouyer if (sc->sc_phase == COMMAND_PHASE ||
1319 1.36.2.15 bouyer sc->sc_phase == MESSAGE_OUT_PHASE)
1320 1.36.2.15 bouyer DELAY(2);
1321 1.36.2.15 bouyer }
1322 1.36.2.15 bouyer
1323 1.36.2.15 bouyer static int
1324 1.36.2.15 bouyer ncr53c9x_rdfifo(struct ncr53c9x_softc *sc, int how)
1325 1.36.2.15 bouyer {
1326 1.36.2.15 bouyer int i, n;
1327 1.36.2.15 bouyer u_char *buf;
1328 1.36.2.15 bouyer
1329 1.36.2.15 bouyer switch(how) {
1330 1.36.2.15 bouyer case NCR_RDFIFO_START:
1331 1.36.2.15 bouyer buf = sc->sc_imess;
1332 1.36.2.15 bouyer sc->sc_imlen = 0;
1333 1.36.2.15 bouyer break;
1334 1.36.2.15 bouyer case NCR_RDFIFO_CONTINUE:
1335 1.36.2.15 bouyer buf = sc->sc_imess + sc->sc_imlen;
1336 1.36.2.15 bouyer break;
1337 1.36.2.15 bouyer default:
1338 1.36.2.15 bouyer panic("ncr53c9x_rdfifo: bad flag\n");
1339 1.36.2.15 bouyer break;
1340 1.36.2.15 bouyer }
1341 1.36.2.15 bouyer
1342 1.36.2.15 bouyer /*
1343 1.36.2.15 bouyer * XXX buffer (sc_imess) size for message
1344 1.36.2.15 bouyer */
1345 1.36.2.15 bouyer
1346 1.36.2.15 bouyer n = NCR_READ_REG(sc, NCR_FFLAG) & NCRFIFO_FF;
1347 1.36.2.15 bouyer
1348 1.36.2.15 bouyer if (sc->sc_rev == NCR_VARIANT_FAS366) {
1349 1.36.2.15 bouyer n *= 2;
1350 1.36.2.15 bouyer
1351 1.36.2.15 bouyer for (i = 0; i < n; i++)
1352 1.36.2.15 bouyer buf[i] = NCR_READ_REG(sc, NCR_FIFO);
1353 1.36.2.15 bouyer
1354 1.36.2.15 bouyer if (sc->sc_espstat2 & FAS_STAT2_ISHUTTLE) {
1355 1.36.2.15 bouyer
1356 1.36.2.15 bouyer NCR_WRITE_REG(sc, NCR_FIFO, 0);
1357 1.36.2.15 bouyer buf[i++] = NCR_READ_REG(sc, NCR_FIFO);
1358 1.36.2.15 bouyer
1359 1.36.2.15 bouyer NCR_READ_REG(sc, NCR_FIFO);
1360 1.36.2.15 bouyer
1361 1.36.2.15 bouyer ncr53c9x_flushfifo(sc);
1362 1.36.2.15 bouyer }
1363 1.36.2.15 bouyer } else {
1364 1.36.2.15 bouyer for (i = 0; i < n; i++)
1365 1.36.2.15 bouyer buf[i] = NCR_READ_REG(sc, NCR_FIFO);
1366 1.36.2.15 bouyer }
1367 1.36.2.15 bouyer
1368 1.36.2.15 bouyer sc->sc_imlen += i;
1369 1.36.2.15 bouyer
1370 1.36.2.15 bouyer #ifdef NCR53C9X_DEBUG
1371 1.36.2.15 bouyer {
1372 1.36.2.15 bouyer int j;
1373 1.36.2.15 bouyer
1374 1.36.2.15 bouyer NCR_TRACE(("\n[rdfifo %s (%d):",
1375 1.36.2.15 bouyer (how == NCR_RDFIFO_START) ? "start" : "cont",
1376 1.36.2.15 bouyer (int)sc->sc_imlen));
1377 1.36.2.15 bouyer if (ncr53c9x_debug & NCR_SHOWTRAC) {
1378 1.36.2.15 bouyer for (j = 0; j < sc->sc_imlen; j++)
1379 1.36.2.15 bouyer printf(" %02x", sc->sc_imess[j]);
1380 1.36.2.15 bouyer printf("]\n");
1381 1.36.2.15 bouyer }
1382 1.36.2.15 bouyer }
1383 1.36.2.15 bouyer #endif
1384 1.36.2.15 bouyer return sc->sc_imlen;
1385 1.36.2.15 bouyer }
1386 1.36.2.15 bouyer
1387 1.36.2.15 bouyer static void
1388 1.36.2.15 bouyer ncr53c9x_wrfifo(struct ncr53c9x_softc *sc, u_char *p, int len)
1389 1.36.2.15 bouyer {
1390 1.36.2.15 bouyer int i;
1391 1.36.2.15 bouyer
1392 1.36.2.15 bouyer #ifdef NCR53C9X_DEBUG
1393 1.36.2.15 bouyer NCR_MISC(("[wrfifo(%d):", len));
1394 1.36.2.15 bouyer if (ncr53c9x_debug & NCR_SHOWTRAC) {
1395 1.36.2.15 bouyer for (i = 0; i < len; i++)
1396 1.36.2.15 bouyer printf(" %02x", p[i]);
1397 1.36.2.15 bouyer printf("]\n");
1398 1.36.2.15 bouyer }
1399 1.36.2.15 bouyer #endif
1400 1.36.2.15 bouyer
1401 1.36.2.15 bouyer for (i = 0; i < len; i++) {
1402 1.36.2.15 bouyer NCR_WRITE_REG(sc, NCR_FIFO, p[i]);
1403 1.36.2.15 bouyer
1404 1.36.2.15 bouyer if (sc->sc_rev == NCR_VARIANT_FAS366)
1405 1.36.2.15 bouyer NCR_WRITE_REG(sc, NCR_FIFO, 0);
1406 1.36.2.15 bouyer }
1407 1.36.2.15 bouyer }
1408 1.36.2.15 bouyer
1409 1.1 thorpej int
1410 1.36.2.6 bouyer ncr53c9x_reselect(sc, message, tagtype, tagid)
1411 1.1 thorpej struct ncr53c9x_softc *sc;
1412 1.1 thorpej int message;
1413 1.36.2.6 bouyer int tagtype, tagid;
1414 1.1 thorpej {
1415 1.1 thorpej u_char selid, target, lun;
1416 1.36.2.6 bouyer struct ncr53c9x_ecb *ecb = NULL;
1417 1.1 thorpej struct ncr53c9x_tinfo *ti;
1418 1.36.2.6 bouyer struct ncr53c9x_linfo *li;
1419 1.1 thorpej
1420 1.36.2.15 bouyer
1421 1.36.2.15 bouyer if (sc->sc_rev == NCR_VARIANT_FAS366) {
1422 1.36.2.15 bouyer target = sc->sc_selid;
1423 1.36.2.15 bouyer } else {
1424 1.36.2.15 bouyer /*
1425 1.36.2.16 bouyer * The SCSI chip made a snapshot of the data bus
1426 1.36.2.16 bouyer * while the reselection was being negotiated.
1427 1.36.2.16 bouyer * This enables us to determine which target did
1428 1.36.2.15 bouyer * the reselect.
1429 1.36.2.15 bouyer */
1430 1.36.2.15 bouyer selid = sc->sc_selid & ~(1 << sc->sc_id);
1431 1.36.2.15 bouyer if (selid & (selid - 1)) {
1432 1.36.2.15 bouyer printf("%s: reselect with invalid selid %02x;"
1433 1.36.2.16 bouyer " sending DEVICE RESET\n",
1434 1.36.2.16 bouyer sc->sc_dev.dv_xname, selid);
1435 1.36.2.15 bouyer goto reset;
1436 1.36.2.15 bouyer }
1437 1.36.2.15 bouyer
1438 1.36.2.15 bouyer target = ffs(selid) - 1;
1439 1.1 thorpej }
1440 1.36.2.15 bouyer lun = message & 0x07;
1441 1.1 thorpej
1442 1.1 thorpej /*
1443 1.1 thorpej * Search wait queue for disconnected cmd
1444 1.1 thorpej * The list should be short, so I haven't bothered with
1445 1.1 thorpej * any more sophisticated structures than a simple
1446 1.1 thorpej * singly linked list.
1447 1.1 thorpej */
1448 1.36.2.6 bouyer ti = &sc->sc_tinfo[target];
1449 1.36.2.6 bouyer li = TINFO_LUN(ti, lun);
1450 1.36.2.6 bouyer
1451 1.36.2.6 bouyer /*
1452 1.36.2.6 bouyer * We can get as far as the LUN with the IDENTIFY
1453 1.36.2.16 bouyer * message. Check to see if we're running an
1454 1.36.2.6 bouyer * un-tagged command. Otherwise ack the IDENTIFY
1455 1.36.2.6 bouyer * and wait for a tag message.
1456 1.36.2.6 bouyer */
1457 1.36.2.6 bouyer if (li != NULL) {
1458 1.36.2.6 bouyer if (li->untagged != NULL && li->busy)
1459 1.36.2.6 bouyer ecb = li->untagged;
1460 1.36.2.6 bouyer else if (tagtype != MSG_SIMPLE_Q_TAG) {
1461 1.36.2.6 bouyer /* Wait for tag to come by */
1462 1.36.2.6 bouyer sc->sc_state = NCR_IDENTIFIED;
1463 1.36.2.6 bouyer return (0);
1464 1.36.2.6 bouyer } else if (tagtype)
1465 1.36.2.6 bouyer ecb = li->queued[tagid];
1466 1.1 thorpej }
1467 1.1 thorpej if (ecb == NULL) {
1468 1.36.2.16 bouyer printf("%s: reselect from target %d lun %d tag %x:%x "
1469 1.36.2.16 bouyer "with no nexus; sending ABORT\n",
1470 1.36.2.16 bouyer sc->sc_dev.dv_xname, target, lun, tagtype, tagid);
1471 1.1 thorpej goto abort;
1472 1.1 thorpej }
1473 1.1 thorpej
1474 1.1 thorpej /* Make this nexus active again. */
1475 1.1 thorpej sc->sc_state = NCR_CONNECTED;
1476 1.1 thorpej sc->sc_nexus = ecb;
1477 1.1 thorpej ncr53c9x_setsync(sc, ti);
1478 1.1 thorpej
1479 1.1 thorpej if (ecb->flags & ECB_RESET)
1480 1.1 thorpej ncr53c9x_sched_msgout(SEND_DEV_RESET);
1481 1.1 thorpej else if (ecb->flags & ECB_ABORT)
1482 1.1 thorpej ncr53c9x_sched_msgout(SEND_ABORT);
1483 1.1 thorpej
1484 1.1 thorpej /* Do an implicit RESTORE POINTERS. */
1485 1.1 thorpej sc->sc_dp = ecb->daddr;
1486 1.1 thorpej sc->sc_dleft = ecb->dleft;
1487 1.1 thorpej
1488 1.1 thorpej return (0);
1489 1.1 thorpej
1490 1.1 thorpej reset:
1491 1.1 thorpej ncr53c9x_sched_msgout(SEND_DEV_RESET);
1492 1.1 thorpej return (1);
1493 1.1 thorpej
1494 1.1 thorpej abort:
1495 1.1 thorpej ncr53c9x_sched_msgout(SEND_ABORT);
1496 1.1 thorpej return (1);
1497 1.1 thorpej }
1498 1.1 thorpej
1499 1.36.2.15 bouyer
1500 1.36.2.15 bouyer /*
1501 1.36.2.15 bouyer * XXX this might be common thing(check with scsipi)
1502 1.36.2.15 bouyer */
1503 1.1 thorpej #define IS1BYTEMSG(m) (((m) != 1 && (m) < 0x20) || (m) & 0x80)
1504 1.1 thorpej #define IS2BYTEMSG(m) (((m) & 0xf0) == 0x20)
1505 1.1 thorpej #define ISEXTMSG(m) ((m) == 1)
1506 1.1 thorpej
1507 1.36.2.15 bouyer static inline int
1508 1.36.2.15 bouyer __verify_msg_format(u_char *p, int len)
1509 1.36.2.15 bouyer {
1510 1.36.2.15 bouyer
1511 1.36.2.15 bouyer if (len == 1 && IS1BYTEMSG(p[0]))
1512 1.36.2.15 bouyer return 1;
1513 1.36.2.15 bouyer if (len == 2 && IS2BYTEMSG(p[0]))
1514 1.36.2.15 bouyer return 1;
1515 1.36.2.15 bouyer if (len >= 3 && ISEXTMSG(p[0]) &&
1516 1.36.2.15 bouyer len == p[1] + 2)
1517 1.36.2.15 bouyer return 1;
1518 1.36.2.15 bouyer
1519 1.36.2.15 bouyer return 0;
1520 1.36.2.15 bouyer }
1521 1.36.2.15 bouyer
1522 1.1 thorpej /*
1523 1.1 thorpej * Get an incoming message as initiator.
1524 1.1 thorpej *
1525 1.1 thorpej * The SCSI bus must already be in MESSAGE_IN_PHASE and there is a
1526 1.1 thorpej * byte in the FIFO
1527 1.1 thorpej */
1528 1.1 thorpej void
1529 1.1 thorpej ncr53c9x_msgin(sc)
1530 1.36.2.4 bouyer struct ncr53c9x_softc *sc;
1531 1.1 thorpej {
1532 1.1 thorpej
1533 1.36.2.15 bouyer NCR_TRACE(("[ncr53c9x_msgin(curmsglen:%ld)] ", (long)sc->sc_imlen));
1534 1.1 thorpej
1535 1.36.2.15 bouyer if (sc->sc_imlen == 0) {
1536 1.36.2.16 bouyer printf("%s: msgin: no msg byte available\n",
1537 1.36.2.16 bouyer sc->sc_dev.dv_xname);
1538 1.1 thorpej return;
1539 1.1 thorpej }
1540 1.1 thorpej
1541 1.1 thorpej /*
1542 1.1 thorpej * Prepare for a new message. A message should (according
1543 1.1 thorpej * to the SCSI standard) be transmitted in one single
1544 1.1 thorpej * MESSAGE_IN_PHASE. If we have been in some other phase,
1545 1.1 thorpej * then this is a new message.
1546 1.1 thorpej */
1547 1.36.2.16 bouyer if (sc->sc_prevphase != MESSAGE_IN_PHASE &&
1548 1.36.2.16 bouyer sc->sc_state != NCR_RESELECTED) {
1549 1.36.2.16 bouyer printf("%s: phase change, dropping message, "
1550 1.36.2.16 bouyer "prev %d, state %d\n",
1551 1.36.2.15 bouyer sc->sc_dev.dv_xname, sc->sc_prevphase, sc->sc_state);
1552 1.1 thorpej sc->sc_flags &= ~NCR_DROP_MSGI;
1553 1.1 thorpej sc->sc_imlen = 0;
1554 1.1 thorpej }
1555 1.1 thorpej
1556 1.36.2.15 bouyer NCR_TRACE(("<msgbyte:0x%02x>", sc->sc_imess[0]));
1557 1.1 thorpej
1558 1.1 thorpej /*
1559 1.1 thorpej * If we're going to reject the message, don't bother storing
1560 1.1 thorpej * the incoming bytes. But still, we need to ACK them.
1561 1.1 thorpej */
1562 1.36.2.6 bouyer if ((sc->sc_flags & NCR_DROP_MSGI) != 0) {
1563 1.1 thorpej NCRCMD(sc, NCRCMD_MSGOK);
1564 1.36.2.16 bouyer printf("<dropping msg byte %x>", sc->sc_imess[sc->sc_imlen]);
1565 1.1 thorpej return;
1566 1.1 thorpej }
1567 1.1 thorpej
1568 1.1 thorpej if (sc->sc_imlen >= NCR_MAX_MSG_LEN) {
1569 1.1 thorpej ncr53c9x_sched_msgout(SEND_REJECT);
1570 1.1 thorpej sc->sc_flags |= NCR_DROP_MSGI;
1571 1.1 thorpej } else {
1572 1.36.2.15 bouyer u_char *pb;
1573 1.36.2.16 bouyer int plen;
1574 1.36.2.15 bouyer
1575 1.36.2.15 bouyer switch (sc->sc_state) {
1576 1.1 thorpej /*
1577 1.36.2.15 bouyer * if received message is the first of reselection
1578 1.36.2.15 bouyer * then first byte is selid, and then message
1579 1.1 thorpej */
1580 1.36.2.15 bouyer case NCR_RESELECTED:
1581 1.36.2.15 bouyer pb = sc->sc_imess + 1;
1582 1.36.2.15 bouyer plen = sc->sc_imlen - 1;
1583 1.36.2.15 bouyer break;
1584 1.36.2.15 bouyer default:
1585 1.36.2.15 bouyer pb = sc->sc_imess;
1586 1.36.2.15 bouyer plen = sc->sc_imlen;
1587 1.36.2.15 bouyer break;
1588 1.36.2.15 bouyer }
1589 1.36.2.15 bouyer
1590 1.36.2.15 bouyer if (__verify_msg_format(pb, plen))
1591 1.1 thorpej goto gotit;
1592 1.1 thorpej }
1593 1.36.2.15 bouyer
1594 1.1 thorpej /* Ack what we have so far */
1595 1.1 thorpej NCRCMD(sc, NCRCMD_MSGOK);
1596 1.1 thorpej return;
1597 1.1 thorpej
1598 1.1 thorpej gotit:
1599 1.36.2.15 bouyer NCR_MSGS(("gotmsg(%x) state %d", sc->sc_imess[0], sc->sc_state));
1600 1.36.2.16 bouyer /* we got complete message, flush the imess, */
1601 1.36.2.16 bouyer /* XXX nobody uses imlen below */
1602 1.36.2.15 bouyer sc->sc_imlen = 0;
1603 1.1 thorpej /*
1604 1.1 thorpej * Now we should have a complete message (1 byte, 2 byte
1605 1.1 thorpej * and moderately long extended messages). We only handle
1606 1.1 thorpej * extended messages which total length is shorter than
1607 1.1 thorpej * NCR_MAX_MSG_LEN. Longer messages will be amputated.
1608 1.1 thorpej */
1609 1.1 thorpej switch (sc->sc_state) {
1610 1.1 thorpej struct ncr53c9x_ecb *ecb;
1611 1.1 thorpej struct ncr53c9x_tinfo *ti;
1612 1.36.2.11 bouyer struct ncr53c9x_linfo *li;
1613 1.36.2.11 bouyer int lun;
1614 1.1 thorpej
1615 1.1 thorpej case NCR_CONNECTED:
1616 1.1 thorpej ecb = sc->sc_nexus;
1617 1.36.2.1 thorpej ti = &sc->sc_tinfo[ecb->xs->xs_periph->periph_target];
1618 1.1 thorpej
1619 1.1 thorpej switch (sc->sc_imess[0]) {
1620 1.1 thorpej case MSG_CMDCOMPLETE:
1621 1.1 thorpej NCR_MSGS(("cmdcomplete "));
1622 1.1 thorpej if (sc->sc_dleft < 0) {
1623 1.36.2.1 thorpej scsipi_printaddr(ecb->xs->xs_periph);
1624 1.30 pk printf("got %ld extra bytes\n",
1625 1.36.2.16 bouyer -(long)sc->sc_dleft);
1626 1.1 thorpej sc->sc_dleft = 0;
1627 1.1 thorpej }
1628 1.36.2.16 bouyer ecb->dleft = (ecb->flags & ECB_TENTATIVE_DONE) ?
1629 1.36.2.16 bouyer 0 : sc->sc_dleft;
1630 1.13 pk if ((ecb->flags & ECB_SENSE) == 0)
1631 1.13 pk ecb->xs->resid = ecb->dleft;
1632 1.1 thorpej sc->sc_state = NCR_CMDCOMPLETE;
1633 1.1 thorpej break;
1634 1.1 thorpej
1635 1.1 thorpej case MSG_MESSAGE_REJECT:
1636 1.23 pk NCR_MSGS(("msg reject (msgout=%x) ", sc->sc_msgout));
1637 1.1 thorpej switch (sc->sc_msgout) {
1638 1.36.2.11 bouyer case SEND_TAG:
1639 1.36.2.11 bouyer /*
1640 1.36.2.11 bouyer * Target does not like tagged queuing.
1641 1.36.2.11 bouyer * - Flush the command queue
1642 1.36.2.11 bouyer * - Disable tagged queuing for the target
1643 1.36.2.11 bouyer * - Dequeue ecb from the queued array.
1644 1.36.2.11 bouyer */
1645 1.36.2.16 bouyer printf("%s: tagged queuing rejected: "
1646 1.36.2.16 bouyer "target %d\n",
1647 1.36.2.15 bouyer sc->sc_dev.dv_xname,
1648 1.36.2.15 bouyer ecb->xs->xs_periph->periph_target);
1649 1.36.2.15 bouyer
1650 1.36.2.11 bouyer NCR_MSGS(("(rejected sent tag)"));
1651 1.36.2.11 bouyer NCRCMD(sc, NCRCMD_FLUSH);
1652 1.36.2.11 bouyer DELAY(1);
1653 1.36.2.13 bouyer ti->flags &= ~T_TAG;
1654 1.36.2.12 bouyer lun = ecb->xs->xs_periph->periph_lun;
1655 1.36.2.11 bouyer li = TINFO_LUN(ti, lun);
1656 1.36.2.11 bouyer if (ecb->tag[0] &&
1657 1.36.2.11 bouyer li->queued[ecb->tag[1]] != NULL) {
1658 1.36.2.11 bouyer li->queued[ecb->tag[1]] = NULL;
1659 1.36.2.16 bouyer li->used--;
1660 1.36.2.11 bouyer }
1661 1.36.2.11 bouyer ecb->tag[0] = ecb->tag[1] = 0;
1662 1.36.2.11 bouyer li->untagged = ecb;
1663 1.36.2.11 bouyer li->busy = 1;
1664 1.36.2.11 bouyer break;
1665 1.36.2.11 bouyer
1666 1.1 thorpej case SEND_SDTR:
1667 1.36.2.16 bouyer printf("%s: sync transfer rejected: "
1668 1.36.2.16 bouyer "target %d\n",
1669 1.36.2.15 bouyer sc->sc_dev.dv_xname,
1670 1.36.2.15 bouyer ecb->xs->xs_periph->periph_target);
1671 1.36.2.15 bouyer
1672 1.1 thorpej sc->sc_flags &= ~NCR_SYNCHNEGO;
1673 1.1 thorpej ti->flags &= ~(T_NEGOTIATE | T_SYNCMODE);
1674 1.1 thorpej ncr53c9x_setsync(sc, ti);
1675 1.36.2.10 bouyer ncr53c9x_update_xfer_mode(sc,
1676 1.36.2.10 bouyer ecb->xs->xs_periph->periph_target);
1677 1.1 thorpej break;
1678 1.36.2.11 bouyer
1679 1.36.2.15 bouyer case SEND_WDTR:
1680 1.36.2.16 bouyer printf("%s: wide transfer rejected: "
1681 1.36.2.16 bouyer "target %d\n",
1682 1.36.2.15 bouyer sc->sc_dev.dv_xname,
1683 1.36.2.15 bouyer ecb->xs->xs_periph->periph_target);
1684 1.36.2.15 bouyer ti->flags &= ~T_WIDE;
1685 1.36.2.17 bouyer ti->width = 0;
1686 1.36.2.15 bouyer break;
1687 1.36.2.15 bouyer
1688 1.1 thorpej case SEND_INIT_DET_ERR:
1689 1.1 thorpej goto abort;
1690 1.1 thorpej }
1691 1.1 thorpej break;
1692 1.1 thorpej
1693 1.1 thorpej case MSG_NOOP:
1694 1.1 thorpej NCR_MSGS(("noop "));
1695 1.1 thorpej break;
1696 1.1 thorpej
1697 1.36.2.6 bouyer case MSG_HEAD_OF_Q_TAG:
1698 1.36.2.6 bouyer case MSG_SIMPLE_Q_TAG:
1699 1.36.2.6 bouyer case MSG_ORDERED_Q_TAG:
1700 1.36.2.16 bouyer NCR_MSGS(("TAG %x:%x",
1701 1.36.2.16 bouyer sc->sc_imess[0], sc->sc_imess[1]));
1702 1.36.2.6 bouyer break;
1703 1.36.2.6 bouyer
1704 1.1 thorpej case MSG_DISCONNECT:
1705 1.1 thorpej NCR_MSGS(("disconnect "));
1706 1.1 thorpej ti->dconns++;
1707 1.1 thorpej sc->sc_state = NCR_DISCONNECT;
1708 1.8 pk
1709 1.13 pk /*
1710 1.13 pk * Mark the fact that all bytes have moved. The
1711 1.13 pk * target may not bother to do a SAVE POINTERS
1712 1.13 pk * at this stage. This flag will set the residual
1713 1.13 pk * count to zero on MSG COMPLETE.
1714 1.13 pk */
1715 1.13 pk if (sc->sc_dleft == 0)
1716 1.13 pk ecb->flags |= ECB_TENTATIVE_DONE;
1717 1.13 pk
1718 1.13 pk break;
1719 1.1 thorpej
1720 1.1 thorpej case MSG_SAVEDATAPOINTER:
1721 1.1 thorpej NCR_MSGS(("save datapointer "));
1722 1.1 thorpej ecb->daddr = sc->sc_dp;
1723 1.1 thorpej ecb->dleft = sc->sc_dleft;
1724 1.1 thorpej break;
1725 1.1 thorpej
1726 1.1 thorpej case MSG_RESTOREPOINTERS:
1727 1.1 thorpej NCR_MSGS(("restore datapointer "));
1728 1.1 thorpej sc->sc_dp = ecb->daddr;
1729 1.1 thorpej sc->sc_dleft = ecb->dleft;
1730 1.1 thorpej break;
1731 1.1 thorpej
1732 1.1 thorpej case MSG_EXTENDED:
1733 1.1 thorpej NCR_MSGS(("extended(%x) ", sc->sc_imess[2]));
1734 1.1 thorpej switch (sc->sc_imess[2]) {
1735 1.1 thorpej case MSG_EXT_SDTR:
1736 1.1 thorpej NCR_MSGS(("SDTR period %d, offset %d ",
1737 1.36.2.16 bouyer sc->sc_imess[3], sc->sc_imess[4]));
1738 1.1 thorpej if (sc->sc_imess[1] != 3)
1739 1.1 thorpej goto reject;
1740 1.1 thorpej ti->period = sc->sc_imess[3];
1741 1.1 thorpej ti->offset = sc->sc_imess[4];
1742 1.1 thorpej ti->flags &= ~T_NEGOTIATE;
1743 1.1 thorpej if (sc->sc_minsync == 0 ||
1744 1.1 thorpej ti->offset == 0 ||
1745 1.1 thorpej ti->period > 124) {
1746 1.36.2.1 thorpej #if 0
1747 1.29 pk #ifdef NCR53C9X_DEBUG
1748 1.36.2.1 thorpej scsipi_printaddr(ecb->xs->xs_periph);
1749 1.29 pk printf("async mode\n");
1750 1.29 pk #endif
1751 1.36.2.1 thorpej #endif
1752 1.36.2.10 bouyer ti->flags &= ~T_SYNCMODE;
1753 1.36.2.6 bouyer if ((sc->sc_flags&NCR_SYNCHNEGO) == 0) {
1754 1.1 thorpej /*
1755 1.1 thorpej * target initiated negotiation
1756 1.1 thorpej */
1757 1.1 thorpej ti->offset = 0;
1758 1.1 thorpej ncr53c9x_sched_msgout(
1759 1.1 thorpej SEND_SDTR);
1760 1.1 thorpej }
1761 1.1 thorpej } else {
1762 1.36.2.1 thorpej #if 0
1763 1.1 thorpej int r = 250/ti->period;
1764 1.1 thorpej int s = (100*250)/ti->period - 100*r;
1765 1.36.2.1 thorpej #endif
1766 1.1 thorpej int p;
1767 1.1 thorpej
1768 1.1 thorpej p = ncr53c9x_stp2cpb(sc, ti->period);
1769 1.1 thorpej ti->period = ncr53c9x_cpb2stp(sc, p);
1770 1.36.2.1 thorpej #if 0
1771 1.1 thorpej #ifdef NCR53C9X_DEBUG
1772 1.36.2.1 thorpej scsipi_printaddr(ecb->xs->xs_periph);
1773 1.36.2.4 bouyer printf("max sync rate %d.%02dMB/s\n",
1774 1.36.2.16 bouyer r, s);
1775 1.1 thorpej #endif
1776 1.36.2.1 thorpej #endif
1777 1.22 pk if ((sc->sc_flags&NCR_SYNCHNEGO) == 0) {
1778 1.1 thorpej /*
1779 1.1 thorpej * target initiated negotiation
1780 1.1 thorpej */
1781 1.1 thorpej if (ti->period <
1782 1.1 thorpej sc->sc_minsync)
1783 1.1 thorpej ti->period =
1784 1.1 thorpej sc->sc_minsync;
1785 1.1 thorpej if (ti->offset > 15)
1786 1.1 thorpej ti->offset = 15;
1787 1.1 thorpej ti->flags &= ~T_SYNCMODE;
1788 1.1 thorpej ncr53c9x_sched_msgout(
1789 1.1 thorpej SEND_SDTR);
1790 1.1 thorpej } else {
1791 1.1 thorpej /* we are sync */
1792 1.1 thorpej ti->flags |= T_SYNCMODE;
1793 1.1 thorpej }
1794 1.1 thorpej }
1795 1.36.2.10 bouyer ncr53c9x_update_xfer_mode(sc,
1796 1.36.2.10 bouyer ecb->xs->xs_periph->periph_target);
1797 1.1 thorpej sc->sc_flags &= ~NCR_SYNCHNEGO;
1798 1.1 thorpej ncr53c9x_setsync(sc, ti);
1799 1.1 thorpej break;
1800 1.1 thorpej
1801 1.36.2.15 bouyer case MSG_EXT_WDTR:
1802 1.36.2.15 bouyer printf("%s: wide mode %d\n",
1803 1.36.2.15 bouyer sc->sc_dev.dv_xname, sc->sc_imess[3]);
1804 1.36.2.15 bouyer if (sc->sc_imess[3] == 1) {
1805 1.36.2.15 bouyer ti->cfg3 |= NCRFASCFG3_EWIDE;
1806 1.36.2.15 bouyer ncr53c9x_setsync(sc, ti);
1807 1.36.2.17 bouyer } else
1808 1.36.2.17 bouyer ti->width = 0;
1809 1.36.2.15 bouyer ti->flags &= ~T_WIDE;
1810 1.36.2.15 bouyer break;
1811 1.1 thorpej default:
1812 1.36.2.1 thorpej scsipi_printaddr(ecb->xs->xs_periph);
1813 1.30 pk printf("unrecognized MESSAGE EXTENDED;"
1814 1.36.2.16 bouyer " sending REJECT\n");
1815 1.1 thorpej goto reject;
1816 1.1 thorpej }
1817 1.1 thorpej break;
1818 1.1 thorpej
1819 1.1 thorpej default:
1820 1.1 thorpej NCR_MSGS(("ident "));
1821 1.36.2.1 thorpej scsipi_printaddr(ecb->xs->xs_periph);
1822 1.30 pk printf("unrecognized MESSAGE; sending REJECT\n");
1823 1.1 thorpej reject:
1824 1.1 thorpej ncr53c9x_sched_msgout(SEND_REJECT);
1825 1.1 thorpej break;
1826 1.1 thorpej }
1827 1.1 thorpej break;
1828 1.1 thorpej
1829 1.36.2.6 bouyer case NCR_IDENTIFIED:
1830 1.36.2.15 bouyer /*
1831 1.36.2.15 bouyer * IDENTIFY message was received and queue tag is expected now
1832 1.36.2.15 bouyer */
1833 1.36.2.15 bouyer if ((sc->sc_imess[0] != MSG_SIMPLE_Q_TAG) ||
1834 1.36.2.15 bouyer (sc->sc_msgify == 0)) {
1835 1.36.2.15 bouyer printf("%s: TAG reselect without IDENTIFY;"
1836 1.36.2.15 bouyer " MSG %x;"
1837 1.36.2.15 bouyer " sending DEVICE RESET\n",
1838 1.36.2.15 bouyer sc->sc_dev.dv_xname,
1839 1.36.2.15 bouyer sc->sc_imess[0]);
1840 1.36.2.15 bouyer goto reset;
1841 1.36.2.15 bouyer }
1842 1.36.2.15 bouyer (void) ncr53c9x_reselect(sc, sc->sc_msgify,
1843 1.36.2.15 bouyer sc->sc_imess[0], sc->sc_imess[1]);
1844 1.36.2.15 bouyer break;
1845 1.36.2.15 bouyer
1846 1.36.2.15 bouyer case NCR_RESELECTED:
1847 1.36.2.15 bouyer if (MSG_ISIDENTIFY(sc->sc_imess[1])) {
1848 1.36.2.15 bouyer sc->sc_msgify = sc->sc_imess[1];
1849 1.36.2.6 bouyer } else {
1850 1.31 pk printf("%s: reselect without IDENTIFY;"
1851 1.36.2.16 bouyer " MSG %x;"
1852 1.36.2.16 bouyer " sending DEVICE RESET\n",
1853 1.36.2.16 bouyer sc->sc_dev.dv_xname,
1854 1.36.2.16 bouyer sc->sc_imess[1]);
1855 1.1 thorpej goto reset;
1856 1.1 thorpej }
1857 1.36.2.15 bouyer (void) ncr53c9x_reselect(sc, sc->sc_msgify, 0, 0);
1858 1.1 thorpej break;
1859 1.1 thorpej
1860 1.1 thorpej default:
1861 1.31 pk printf("%s: unexpected MESSAGE IN; sending DEVICE RESET\n",
1862 1.36.2.16 bouyer sc->sc_dev.dv_xname);
1863 1.1 thorpej reset:
1864 1.1 thorpej ncr53c9x_sched_msgout(SEND_DEV_RESET);
1865 1.1 thorpej break;
1866 1.1 thorpej
1867 1.1 thorpej abort:
1868 1.1 thorpej ncr53c9x_sched_msgout(SEND_ABORT);
1869 1.1 thorpej break;
1870 1.1 thorpej }
1871 1.1 thorpej
1872 1.36.2.11 bouyer /* if we have more messages to send set ATN */
1873 1.36.2.15 bouyer if (sc->sc_msgpriq)
1874 1.36.2.15 bouyer NCRCMD(sc, NCRCMD_SETATN);
1875 1.36.2.11 bouyer
1876 1.1 thorpej /* Ack last message byte */
1877 1.1 thorpej NCRCMD(sc, NCRCMD_MSGOK);
1878 1.1 thorpej
1879 1.1 thorpej /* Done, reset message pointer. */
1880 1.1 thorpej sc->sc_flags &= ~NCR_DROP_MSGI;
1881 1.1 thorpej sc->sc_imlen = 0;
1882 1.1 thorpej }
1883 1.1 thorpej
1884 1.1 thorpej
1885 1.1 thorpej /*
1886 1.1 thorpej * Send the highest priority, scheduled message
1887 1.1 thorpej */
1888 1.1 thorpej void
1889 1.1 thorpej ncr53c9x_msgout(sc)
1890 1.36.2.4 bouyer struct ncr53c9x_softc *sc;
1891 1.1 thorpej {
1892 1.1 thorpej struct ncr53c9x_tinfo *ti;
1893 1.1 thorpej struct ncr53c9x_ecb *ecb;
1894 1.1 thorpej size_t size;
1895 1.1 thorpej
1896 1.1 thorpej NCR_TRACE(("[ncr53c9x_msgout(priq:%x, prevphase:%x)]",
1897 1.1 thorpej sc->sc_msgpriq, sc->sc_prevphase));
1898 1.1 thorpej
1899 1.22 pk /*
1900 1.22 pk * XXX - the NCR_ATN flag is not in sync with the actual ATN
1901 1.22 pk * condition on the SCSI bus. The 53c9x chip
1902 1.22 pk * automatically turns off ATN before sending the
1903 1.22 pk * message byte. (see also the comment below in the
1904 1.22 pk * default case when picking out a message to send)
1905 1.22 pk */
1906 1.1 thorpej if (sc->sc_flags & NCR_ATN) {
1907 1.1 thorpej if (sc->sc_prevphase != MESSAGE_OUT_PHASE) {
1908 1.1 thorpej new:
1909 1.1 thorpej NCRCMD(sc, NCRCMD_FLUSH);
1910 1.36.2.11 bouyer /* DELAY(1); */
1911 1.1 thorpej sc->sc_msgoutq = 0;
1912 1.1 thorpej sc->sc_omlen = 0;
1913 1.1 thorpej }
1914 1.1 thorpej } else {
1915 1.1 thorpej if (sc->sc_prevphase == MESSAGE_OUT_PHASE) {
1916 1.1 thorpej ncr53c9x_sched_msgout(sc->sc_msgoutq);
1917 1.1 thorpej goto new;
1918 1.1 thorpej } else {
1919 1.1 thorpej printf("%s at line %d: unexpected MESSAGE OUT phase\n",
1920 1.1 thorpej sc->sc_dev.dv_xname, __LINE__);
1921 1.1 thorpej }
1922 1.1 thorpej }
1923 1.36.2.16 bouyer
1924 1.1 thorpej if (sc->sc_omlen == 0) {
1925 1.1 thorpej /* Pick up highest priority message */
1926 1.1 thorpej sc->sc_msgout = sc->sc_msgpriq & -sc->sc_msgpriq;
1927 1.1 thorpej sc->sc_msgoutq |= sc->sc_msgout;
1928 1.1 thorpej sc->sc_msgpriq &= ~sc->sc_msgout;
1929 1.1 thorpej sc->sc_omlen = 1; /* "Default" message len */
1930 1.1 thorpej switch (sc->sc_msgout) {
1931 1.1 thorpej case SEND_SDTR:
1932 1.1 thorpej ecb = sc->sc_nexus;
1933 1.36.2.1 thorpej ti = &sc->sc_tinfo[ecb->xs->xs_periph->periph_target];
1934 1.1 thorpej sc->sc_omess[0] = MSG_EXTENDED;
1935 1.36.2.16 bouyer sc->sc_omess[1] = MSG_EXT_SDTR_LEN;
1936 1.1 thorpej sc->sc_omess[2] = MSG_EXT_SDTR;
1937 1.1 thorpej sc->sc_omess[3] = ti->period;
1938 1.1 thorpej sc->sc_omess[4] = ti->offset;
1939 1.1 thorpej sc->sc_omlen = 5;
1940 1.1 thorpej if ((sc->sc_flags & NCR_SYNCHNEGO) == 0) {
1941 1.1 thorpej ti->flags |= T_SYNCMODE;
1942 1.1 thorpej ncr53c9x_setsync(sc, ti);
1943 1.1 thorpej }
1944 1.1 thorpej break;
1945 1.36.2.15 bouyer case SEND_WDTR:
1946 1.36.2.15 bouyer ecb = sc->sc_nexus;
1947 1.36.2.15 bouyer ti = &sc->sc_tinfo[ecb->xs->xs_periph->periph_target];
1948 1.36.2.15 bouyer sc->sc_omess[0] = MSG_EXTENDED;
1949 1.36.2.16 bouyer sc->sc_omess[1] = MSG_EXT_WDTR_LEN;
1950 1.36.2.15 bouyer sc->sc_omess[2] = MSG_EXT_WDTR;
1951 1.36.2.15 bouyer sc->sc_omess[3] = ti->width;
1952 1.36.2.15 bouyer sc->sc_omlen = 4;
1953 1.36.2.15 bouyer break;
1954 1.36.2.6 bouyer case SEND_IDENTIFY:
1955 1.36.2.6 bouyer if (sc->sc_state != NCR_CONNECTED) {
1956 1.36.2.6 bouyer printf("%s at line %d: no nexus\n",
1957 1.36.2.6 bouyer sc->sc_dev.dv_xname, __LINE__);
1958 1.36.2.6 bouyer }
1959 1.36.2.6 bouyer ecb = sc->sc_nexus;
1960 1.36.2.6 bouyer sc->sc_omess[0] =
1961 1.36.2.6 bouyer MSG_IDENTIFY(ecb->xs->xs_periph->periph_lun, 0);
1962 1.36.2.6 bouyer break;
1963 1.36.2.6 bouyer case SEND_TAG:
1964 1.1 thorpej if (sc->sc_state != NCR_CONNECTED) {
1965 1.1 thorpej printf("%s at line %d: no nexus\n",
1966 1.1 thorpej sc->sc_dev.dv_xname, __LINE__);
1967 1.1 thorpej }
1968 1.1 thorpej ecb = sc->sc_nexus;
1969 1.36.2.6 bouyer sc->sc_omess[0] = ecb->tag[0];
1970 1.36.2.6 bouyer sc->sc_omess[1] = ecb->tag[1];
1971 1.36.2.6 bouyer sc->sc_omlen = 2;
1972 1.1 thorpej break;
1973 1.1 thorpej case SEND_DEV_RESET:
1974 1.1 thorpej sc->sc_flags |= NCR_ABORTING;
1975 1.1 thorpej sc->sc_omess[0] = MSG_BUS_DEV_RESET;
1976 1.1 thorpej ecb = sc->sc_nexus;
1977 1.36.2.1 thorpej ti = &sc->sc_tinfo[ecb->xs->xs_periph->periph_target];
1978 1.1 thorpej ti->flags &= ~T_SYNCMODE;
1979 1.36.2.10 bouyer ncr53c9x_update_xfer_mode(sc,
1980 1.36.2.10 bouyer ecb->xs->xs_periph->periph_target);
1981 1.36.2.5 bouyer if ((ti->flags & T_SYNCHOFF) == 0)
1982 1.36.2.5 bouyer /* We can re-start sync negotiation */
1983 1.36.2.5 bouyer ti->flags |= T_NEGOTIATE;
1984 1.1 thorpej break;
1985 1.1 thorpej case SEND_PARITY_ERROR:
1986 1.1 thorpej sc->sc_omess[0] = MSG_PARITY_ERROR;
1987 1.1 thorpej break;
1988 1.1 thorpej case SEND_ABORT:
1989 1.1 thorpej sc->sc_flags |= NCR_ABORTING;
1990 1.1 thorpej sc->sc_omess[0] = MSG_ABORT;
1991 1.1 thorpej break;
1992 1.1 thorpej case SEND_INIT_DET_ERR:
1993 1.1 thorpej sc->sc_omess[0] = MSG_INITIATOR_DET_ERR;
1994 1.1 thorpej break;
1995 1.1 thorpej case SEND_REJECT:
1996 1.1 thorpej sc->sc_omess[0] = MSG_MESSAGE_REJECT;
1997 1.1 thorpej break;
1998 1.1 thorpej default:
1999 1.22 pk /*
2000 1.22 pk * We normally do not get here, since the chip
2001 1.22 pk * automatically turns off ATN before the last
2002 1.22 pk * byte of a message is sent to the target.
2003 1.22 pk * However, if the target rejects our (multi-byte)
2004 1.22 pk * message early by switching to MSG IN phase
2005 1.22 pk * ATN remains on, so the target may return to
2006 1.22 pk * MSG OUT phase. If there are no scheduled messages
2007 1.22 pk * left we send a NO-OP.
2008 1.22 pk *
2009 1.22 pk * XXX - Note that this leaves no useful purpose for
2010 1.22 pk * the NCR_ATN flag.
2011 1.22 pk */
2012 1.1 thorpej sc->sc_flags &= ~NCR_ATN;
2013 1.1 thorpej sc->sc_omess[0] = MSG_NOOP;
2014 1.1 thorpej break;
2015 1.1 thorpej }
2016 1.1 thorpej sc->sc_omp = sc->sc_omess;
2017 1.1 thorpej }
2018 1.1 thorpej
2019 1.36.2.6 bouyer #ifdef DEBUG
2020 1.36.2.6 bouyer {
2021 1.36.2.6 bouyer int i;
2022 1.36.2.6 bouyer
2023 1.36.2.15 bouyer NCR_MISC(("<msgout:"));
2024 1.36.2.6 bouyer for (i = 0; i < sc->sc_omlen; i++)
2025 1.36.2.15 bouyer NCR_MISC((" %02x", sc->sc_omess[i]));
2026 1.36.2.15 bouyer NCR_MISC(("> "));
2027 1.36.2.6 bouyer }
2028 1.36.2.6 bouyer #endif
2029 1.36.2.15 bouyer if (sc->sc_rev == NCR_VARIANT_FAS366) {
2030 1.36.2.15 bouyer /*
2031 1.36.2.15 bouyer * XXX fifo size
2032 1.36.2.15 bouyer */
2033 1.36.2.15 bouyer ncr53c9x_flushfifo(sc);
2034 1.36.2.15 bouyer ncr53c9x_wrfifo(sc, sc->sc_omp, sc->sc_omlen);
2035 1.36.2.15 bouyer NCRCMD(sc, NCRCMD_TRANS);
2036 1.36.2.15 bouyer } else {
2037 1.36.2.15 bouyer /* (re)send the message */
2038 1.36.2.15 bouyer size = min(sc->sc_omlen, sc->sc_maxxfer);
2039 1.36.2.15 bouyer NCRDMA_SETUP(sc, &sc->sc_omp, &sc->sc_omlen, 0, &size);
2040 1.36.2.15 bouyer /* Program the SCSI counter */
2041 1.36.2.15 bouyer NCR_SET_COUNT(sc, size);
2042 1.36.2.15 bouyer
2043 1.36.2.15 bouyer /* Load the count in and start the message-out transfer */
2044 1.36.2.15 bouyer NCRCMD(sc, NCRCMD_NOP|NCRCMD_DMA);
2045 1.36.2.15 bouyer NCRCMD(sc, NCRCMD_TRANS|NCRCMD_DMA);
2046 1.36.2.15 bouyer NCRDMA_GO(sc);
2047 1.36.2.15 bouyer }
2048 1.1 thorpej }
2049 1.1 thorpej
2050 1.1 thorpej /*
2051 1.1 thorpej * This is the most critical part of the driver, and has to know
2052 1.1 thorpej * how to deal with *all* error conditions and phases from the SCSI
2053 1.1 thorpej * bus. If there are no errors and the DMA was active, then call the
2054 1.1 thorpej * DMA pseudo-interrupt handler. If this returns 1, then that was it
2055 1.1 thorpej * and we can return from here without further processing.
2056 1.1 thorpej *
2057 1.1 thorpej * Most of this needs verifying.
2058 1.1 thorpej */
2059 1.1 thorpej int
2060 1.36.2.4 bouyer ncr53c9x_intr(arg)
2061 1.36.2.4 bouyer void *arg;
2062 1.1 thorpej {
2063 1.36.2.4 bouyer struct ncr53c9x_softc *sc = arg;
2064 1.36.2.4 bouyer struct ncr53c9x_ecb *ecb;
2065 1.36.2.4 bouyer struct scsipi_periph *periph;
2066 1.1 thorpej struct ncr53c9x_tinfo *ti;
2067 1.1 thorpej size_t size;
2068 1.5 pk int nfifo;
2069 1.1 thorpej
2070 1.36.2.15 bouyer NCR_MISC(("[ncr53c9x_intr: state %d]", sc->sc_state));
2071 1.1 thorpej
2072 1.25 pk if (!NCRDMA_ISINTR(sc))
2073 1.25 pk return (0);
2074 1.25 pk
2075 1.25 pk again:
2076 1.25 pk /* and what do the registers say... */
2077 1.25 pk ncr53c9x_readregs(sc);
2078 1.25 pk
2079 1.25 pk sc->sc_intrcnt.ev_count++;
2080 1.25 pk
2081 1.1 thorpej /*
2082 1.25 pk * At the moment, only a SCSI Bus Reset or Illegal
2083 1.25 pk * Command are classed as errors. A disconnect is a
2084 1.25 pk * valid condition, and we let the code check is the
2085 1.25 pk * "NCR_BUSFREE_OK" flag was set before declaring it
2086 1.25 pk * and error.
2087 1.1 thorpej *
2088 1.25 pk * Also, the status register tells us about "Gross
2089 1.25 pk * Errors" and "Parity errors". Only the Gross Error
2090 1.25 pk * is really bad, and the parity errors are dealt
2091 1.25 pk * with later
2092 1.1 thorpej *
2093 1.25 pk * TODO
2094 1.25 pk * If there are too many parity error, go to slow
2095 1.25 pk * cable mode ?
2096 1.1 thorpej */
2097 1.25 pk
2098 1.25 pk /* SCSI Reset */
2099 1.36.2.6 bouyer if ((sc->sc_espintr & NCRINTR_SBR) != 0) {
2100 1.36.2.6 bouyer if ((NCR_READ_REG(sc, NCR_FFLAG) & NCRFIFO_FF) != 0) {
2101 1.25 pk NCRCMD(sc, NCRCMD_FLUSH);
2102 1.25 pk DELAY(1);
2103 1.25 pk }
2104 1.25 pk if (sc->sc_state != NCR_SBR) {
2105 1.36.2.16 bouyer printf("%s: SCSI bus reset\n", sc->sc_dev.dv_xname);
2106 1.25 pk ncr53c9x_init(sc, 0); /* Restart everything */
2107 1.25 pk return (1);
2108 1.25 pk }
2109 1.1 thorpej #if 0
2110 1.25 pk /*XXX*/ printf("<expected bus reset: "
2111 1.36.2.16 bouyer "[intr %x, stat %x, step %d]>\n",
2112 1.36.2.16 bouyer sc->sc_espintr, sc->sc_espstat, sc->sc_espstep);
2113 1.1 thorpej #endif
2114 1.36.2.6 bouyer if (sc->sc_nexus != NULL)
2115 1.25 pk panic("%s: nexus in reset state",
2116 1.36.2.16 bouyer sc->sc_dev.dv_xname);
2117 1.25 pk goto sched;
2118 1.25 pk }
2119 1.1 thorpej
2120 1.25 pk ecb = sc->sc_nexus;
2121 1.1 thorpej
2122 1.25 pk #define NCRINTR_ERR (NCRINTR_SBR|NCRINTR_ILL)
2123 1.25 pk if (sc->sc_espintr & NCRINTR_ERR ||
2124 1.25 pk sc->sc_espstat & NCRSTAT_GE) {
2125 1.1 thorpej
2126 1.36.2.6 bouyer if ((sc->sc_espstat & NCRSTAT_GE) != 0) {
2127 1.25 pk /* Gross Error; no target ? */
2128 1.1 thorpej if (NCR_READ_REG(sc, NCR_FFLAG) & NCRFIFO_FF) {
2129 1.1 thorpej NCRCMD(sc, NCRCMD_FLUSH);
2130 1.1 thorpej DELAY(1);
2131 1.1 thorpej }
2132 1.25 pk if (sc->sc_state == NCR_CONNECTED ||
2133 1.25 pk sc->sc_state == NCR_SELECTING) {
2134 1.25 pk ecb->xs->error = XS_TIMEOUT;
2135 1.25 pk ncr53c9x_done(sc, ecb);
2136 1.1 thorpej }
2137 1.25 pk return (1);
2138 1.1 thorpej }
2139 1.1 thorpej
2140 1.36.2.6 bouyer if ((sc->sc_espintr & NCRINTR_ILL) != 0) {
2141 1.36.2.6 bouyer if ((sc->sc_flags & NCR_EXPECT_ILLCMD) != 0) {
2142 1.25 pk /*
2143 1.25 pk * Eat away "Illegal command" interrupt
2144 1.25 pk * on a ESP100 caused by a re-selection
2145 1.25 pk * while we were trying to select
2146 1.25 pk * another target.
2147 1.25 pk */
2148 1.19 pk #ifdef DEBUG
2149 1.25 pk printf("%s: ESP100 work-around activated\n",
2150 1.25 pk sc->sc_dev.dv_xname);
2151 1.19 pk #endif
2152 1.25 pk sc->sc_flags &= ~NCR_EXPECT_ILLCMD;
2153 1.25 pk return (1);
2154 1.25 pk }
2155 1.25 pk /* illegal command, out of sync ? */
2156 1.25 pk printf("%s: illegal command: 0x%x "
2157 1.25 pk "(state %d, phase %x, prevphase %x)\n",
2158 1.36.2.16 bouyer sc->sc_dev.dv_xname, sc->sc_lastcmd,
2159 1.36.2.16 bouyer sc->sc_state, sc->sc_phase, sc->sc_prevphase);
2160 1.25 pk if (NCR_READ_REG(sc, NCR_FFLAG) & NCRFIFO_FF) {
2161 1.25 pk NCRCMD(sc, NCRCMD_FLUSH);
2162 1.25 pk DELAY(1);
2163 1.1 thorpej }
2164 1.25 pk ncr53c9x_init(sc, 1); /* Restart everything */
2165 1.25 pk return (1);
2166 1.1 thorpej }
2167 1.25 pk }
2168 1.25 pk sc->sc_flags &= ~NCR_EXPECT_ILLCMD;
2169 1.1 thorpej
2170 1.25 pk /*
2171 1.25 pk * Call if DMA is active.
2172 1.25 pk *
2173 1.25 pk * If DMA_INTR returns true, then maybe go 'round the loop
2174 1.25 pk * again in case there is no more DMA queued, but a phase
2175 1.25 pk * change is expected.
2176 1.25 pk */
2177 1.25 pk if (NCRDMA_ISACTIVE(sc)) {
2178 1.25 pk int r = NCRDMA_INTR(sc);
2179 1.25 pk if (r == -1) {
2180 1.25 pk printf("%s: DMA error; resetting\n",
2181 1.36.2.16 bouyer sc->sc_dev.dv_xname);
2182 1.25 pk ncr53c9x_init(sc, 1);
2183 1.25 pk }
2184 1.25 pk /* If DMA active here, then go back to work... */
2185 1.25 pk if (NCRDMA_ISACTIVE(sc))
2186 1.25 pk return (1);
2187 1.1 thorpej
2188 1.25 pk if ((sc->sc_espstat & NCRSTAT_TC) == 0) {
2189 1.25 pk /*
2190 1.25 pk * DMA not completed. If we can not find a
2191 1.25 pk * acceptable explanation, print a diagnostic.
2192 1.25 pk */
2193 1.25 pk if (sc->sc_state == NCR_SELECTING)
2194 1.25 pk /*
2195 1.25 pk * This can happen if we are reselected
2196 1.25 pk * while using DMA to select a target.
2197 1.25 pk */
2198 1.25 pk /*void*/;
2199 1.25 pk else if (sc->sc_prevphase == MESSAGE_OUT_PHASE) {
2200 1.25 pk /*
2201 1.25 pk * Our (multi-byte) message (eg SDTR) was
2202 1.25 pk * interrupted by the target to send
2203 1.25 pk * a MSG REJECT.
2204 1.25 pk * Print diagnostic if current phase
2205 1.25 pk * is not MESSAGE IN.
2206 1.25 pk */
2207 1.25 pk if (sc->sc_phase != MESSAGE_IN_PHASE)
2208 1.36.2.16 bouyer printf("%s: !TC on MSG OUT"
2209 1.36.2.16 bouyer " [intr %x, stat %x, step %d]"
2210 1.36.2.16 bouyer " prevphase %x, resid %lx\n",
2211 1.36.2.16 bouyer sc->sc_dev.dv_xname,
2212 1.36.2.16 bouyer sc->sc_espintr,
2213 1.36.2.16 bouyer sc->sc_espstat,
2214 1.36.2.16 bouyer sc->sc_espstep,
2215 1.36.2.16 bouyer sc->sc_prevphase,
2216 1.36.2.16 bouyer (u_long)sc->sc_omlen);
2217 1.25 pk } else if (sc->sc_dleft == 0) {
2218 1.22 pk /*
2219 1.25 pk * The DMA operation was started for
2220 1.25 pk * a DATA transfer. Print a diagnostic
2221 1.25 pk * if the DMA counter and TC bit
2222 1.25 pk * appear to be out of sync.
2223 1.22 pk */
2224 1.25 pk printf("%s: !TC on DATA XFER"
2225 1.36.2.16 bouyer " [intr %x, stat %x, step %d]"
2226 1.36.2.16 bouyer " prevphase %x, resid %x\n",
2227 1.36.2.16 bouyer sc->sc_dev.dv_xname,
2228 1.36.2.16 bouyer sc->sc_espintr,
2229 1.36.2.16 bouyer sc->sc_espstat,
2230 1.36.2.16 bouyer sc->sc_espstep,
2231 1.36.2.16 bouyer sc->sc_prevphase,
2232 1.36.2.16 bouyer ecb ? ecb->dleft : -1);
2233 1.22 pk }
2234 1.1 thorpej }
2235 1.25 pk }
2236 1.25 pk
2237 1.25 pk /*
2238 1.25 pk * Check for less serious errors.
2239 1.25 pk */
2240 1.36.2.6 bouyer if ((sc->sc_espstat & NCRSTAT_PE) != 0) {
2241 1.25 pk printf("%s: SCSI bus parity error\n", sc->sc_dev.dv_xname);
2242 1.25 pk if (sc->sc_prevphase == MESSAGE_IN_PHASE)
2243 1.25 pk ncr53c9x_sched_msgout(SEND_PARITY_ERROR);
2244 1.25 pk else
2245 1.25 pk ncr53c9x_sched_msgout(SEND_INIT_DET_ERR);
2246 1.25 pk }
2247 1.1 thorpej
2248 1.36.2.6 bouyer if ((sc->sc_espintr & NCRINTR_DIS) != 0) {
2249 1.36.2.6 bouyer sc->sc_msgify = 0;
2250 1.25 pk NCR_MISC(("<DISC [intr %x, stat %x, step %d]>",
2251 1.36.2.16 bouyer sc->sc_espintr,sc->sc_espstat,sc->sc_espstep));
2252 1.25 pk if (NCR_READ_REG(sc, NCR_FFLAG) & NCRFIFO_FF) {
2253 1.25 pk NCRCMD(sc, NCRCMD_FLUSH);
2254 1.36.2.11 bouyer /* DELAY(1); */
2255 1.1 thorpej }
2256 1.1 thorpej /*
2257 1.25 pk * This command must (apparently) be issued within
2258 1.25 pk * 250mS of a disconnect. So here you are...
2259 1.1 thorpej */
2260 1.25 pk NCRCMD(sc, NCRCMD_ENSEL);
2261 1.1 thorpej
2262 1.25 pk switch (sc->sc_state) {
2263 1.25 pk case NCR_RESELECTED:
2264 1.25 pk goto sched;
2265 1.22 pk
2266 1.36.2.16 bouyer case NCR_SELECTING:
2267 1.36.2.6 bouyer {
2268 1.36.2.6 bouyer struct ncr53c9x_linfo *li;
2269 1.36.2.6 bouyer
2270 1.25 pk ecb->xs->error = XS_SELTIMEOUT;
2271 1.1 thorpej
2272 1.36.2.6 bouyer /* Selection timeout -- discard all LUNs if empty */
2273 1.36.2.6 bouyer periph = ecb->xs->xs_periph;
2274 1.36.2.6 bouyer ti = &sc->sc_tinfo[periph->periph_target];
2275 1.36.2.6 bouyer li = LIST_FIRST(&ti->luns);
2276 1.36.2.6 bouyer while (li != NULL) {
2277 1.36.2.6 bouyer if (li->untagged == NULL && li->used == 0) {
2278 1.36.2.6 bouyer if (li->lun < NCR_NLUN)
2279 1.36.2.6 bouyer ti->lun[li->lun] = NULL;
2280 1.36.2.6 bouyer LIST_REMOVE(li, link);
2281 1.36.2.6 bouyer free(li, M_DEVBUF);
2282 1.36.2.16 bouyer /*
2283 1.36.2.16 bouyer * Restart the search at the beginning
2284 1.36.2.16 bouyer */
2285 1.36.2.6 bouyer li = LIST_FIRST(&ti->luns);
2286 1.36.2.6 bouyer continue;
2287 1.36.2.6 bouyer }
2288 1.36.2.6 bouyer li = LIST_NEXT(li, link);
2289 1.36.2.6 bouyer }
2290 1.36.2.6 bouyer goto finish;
2291 1.36.2.6 bouyer }
2292 1.25 pk case NCR_CONNECTED:
2293 1.36.2.6 bouyer if ((sc->sc_flags & NCR_SYNCHNEGO) != 0) {
2294 1.1 thorpej #ifdef NCR53C9X_DEBUG
2295 1.36.2.6 bouyer if (ecb != NULL)
2296 1.36.2.1 thorpej scsipi_printaddr(ecb->xs->xs_periph);
2297 1.25 pk printf("sync nego not completed!\n");
2298 1.1 thorpej #endif
2299 1.36.2.1 thorpej ti = &sc->sc_tinfo[ecb->xs->xs_periph->periph_target];
2300 1.25 pk sc->sc_flags &= ~NCR_SYNCHNEGO;
2301 1.25 pk ti->flags &= ~(T_NEGOTIATE | T_SYNCMODE);
2302 1.25 pk }
2303 1.1 thorpej
2304 1.25 pk /* it may be OK to disconnect */
2305 1.25 pk if ((sc->sc_flags & NCR_ABORTING) == 0) {
2306 1.36.2.16 bouyer /*
2307 1.25 pk * Section 5.1.1 of the SCSI 2 spec
2308 1.25 pk * suggests issuing a REQUEST SENSE
2309 1.25 pk * following an unexpected disconnect.
2310 1.25 pk * Some devices go into a contingent
2311 1.25 pk * allegiance condition when
2312 1.25 pk * disconnecting, and this is necessary
2313 1.25 pk * to clean up their state.
2314 1.36.2.16 bouyer */
2315 1.25 pk printf("%s: unexpected disconnect; ",
2316 1.25 pk sc->sc_dev.dv_xname);
2317 1.36.2.6 bouyer if ((ecb->flags & ECB_SENSE) != 0) {
2318 1.25 pk printf("resetting\n");
2319 1.25 pk goto reset;
2320 1.1 thorpej }
2321 1.25 pk printf("sending REQUEST SENSE\n");
2322 1.36.2.4 bouyer callout_stop(&ecb->xs->xs_callout);
2323 1.25 pk ncr53c9x_sense(sc, ecb);
2324 1.25 pk goto out;
2325 1.25 pk }
2326 1.1 thorpej
2327 1.25 pk ecb->xs->error = XS_TIMEOUT;
2328 1.25 pk goto finish;
2329 1.1 thorpej
2330 1.25 pk case NCR_DISCONNECT:
2331 1.25 pk sc->sc_nexus = NULL;
2332 1.25 pk goto sched;
2333 1.1 thorpej
2334 1.25 pk case NCR_CMDCOMPLETE:
2335 1.25 pk goto finish;
2336 1.1 thorpej }
2337 1.25 pk }
2338 1.1 thorpej
2339 1.25 pk switch (sc->sc_state) {
2340 1.25 pk
2341 1.25 pk case NCR_SBR:
2342 1.25 pk printf("%s: waiting for SCSI Bus Reset to happen\n",
2343 1.36.2.16 bouyer sc->sc_dev.dv_xname);
2344 1.25 pk return (1);
2345 1.1 thorpej
2346 1.25 pk case NCR_RESELECTED:
2347 1.25 pk /*
2348 1.25 pk * we must be continuing a message ?
2349 1.25 pk */
2350 1.25 pk if (sc->sc_phase != MESSAGE_IN_PHASE) {
2351 1.25 pk printf("%s: target didn't identify\n",
2352 1.36.2.16 bouyer sc->sc_dev.dv_xname);
2353 1.25 pk ncr53c9x_init(sc, 1);
2354 1.25 pk return (1);
2355 1.25 pk }
2356 1.25 pk printf("<<RESELECT CONT'd>>");
2357 1.25 pk #if XXXX
2358 1.25 pk ncr53c9x_msgin(sc);
2359 1.25 pk if (sc->sc_state != NCR_CONNECTED) {
2360 1.25 pk /* IDENTIFY fail?! */
2361 1.25 pk printf("%s: identify failed\n",
2362 1.36.2.16 bouyer sc->sc_dev.dv_xname, sc->sc_state);
2363 1.25 pk ncr53c9x_init(sc, 1);
2364 1.25 pk return (1);
2365 1.25 pk }
2366 1.25 pk #endif
2367 1.25 pk break;
2368 1.25 pk
2369 1.36.2.6 bouyer case NCR_IDENTIFIED:
2370 1.36.2.6 bouyer ecb = sc->sc_nexus;
2371 1.36.2.6 bouyer if (sc->sc_phase != MESSAGE_IN_PHASE) {
2372 1.36.2.16 bouyer int i = (NCR_READ_REG(sc, NCR_FFLAG) & NCRFIFO_FF);
2373 1.36.2.6 bouyer /*
2374 1.36.2.6 bouyer * Things are seriously fucked up.
2375 1.36.2.6 bouyer * Pull the brakes, i.e. reset
2376 1.36.2.6 bouyer */
2377 1.36.2.6 bouyer printf("%s: target didn't send tag: %d bytes in fifo\n",
2378 1.36.2.16 bouyer sc->sc_dev.dv_xname, i);
2379 1.36.2.6 bouyer /* Drain and display fifo */
2380 1.36.2.6 bouyer while (i-- > 0)
2381 1.36.2.6 bouyer printf("[%d] ", NCR_READ_REG(sc, NCR_FIFO));
2382 1.36.2.16 bouyer
2383 1.36.2.6 bouyer ncr53c9x_init(sc, 1);
2384 1.36.2.6 bouyer return (1);
2385 1.36.2.16 bouyer } else
2386 1.36.2.6 bouyer goto msgin;
2387 1.36.2.6 bouyer
2388 1.36.2.6 bouyer break;
2389 1.36.2.6 bouyer
2390 1.25 pk case NCR_IDLE:
2391 1.25 pk case NCR_SELECTING:
2392 1.25 pk ecb = sc->sc_nexus;
2393 1.25 pk if (sc->sc_espintr & NCRINTR_RESEL) {
2394 1.36.2.11 bouyer sc->sc_msgpriq = sc->sc_msgout = sc->sc_msgoutq = 0;
2395 1.36.2.11 bouyer sc->sc_flags = 0;
2396 1.1 thorpej /*
2397 1.25 pk * If we're trying to select a
2398 1.25 pk * target ourselves, push our command
2399 1.25 pk * back into the ready list.
2400 1.1 thorpej */
2401 1.25 pk if (sc->sc_state == NCR_SELECTING) {
2402 1.25 pk NCR_MISC(("backoff selector "));
2403 1.36.2.4 bouyer callout_stop(&ecb->xs->xs_callout);
2404 1.25 pk TAILQ_INSERT_HEAD(&sc->ready_list, ecb, chain);
2405 1.36.2.6 bouyer ecb->flags |= ECB_READY;
2406 1.25 pk ecb = sc->sc_nexus = NULL;
2407 1.25 pk }
2408 1.25 pk sc->sc_state = NCR_RESELECTED;
2409 1.1 thorpej if (sc->sc_phase != MESSAGE_IN_PHASE) {
2410 1.25 pk /*
2411 1.25 pk * Things are seriously fucked up.
2412 1.25 pk * Pull the brakes, i.e. reset
2413 1.25 pk */
2414 1.1 thorpej printf("%s: target didn't identify\n",
2415 1.36.2.16 bouyer sc->sc_dev.dv_xname);
2416 1.1 thorpej ncr53c9x_init(sc, 1);
2417 1.25 pk return (1);
2418 1.1 thorpej }
2419 1.25 pk /*
2420 1.25 pk * The C90 only inhibits FIFO writes until
2421 1.25 pk * reselection is complete, instead of
2422 1.25 pk * waiting until the interrupt status register
2423 1.25 pk * has been read. So, if the reselect happens
2424 1.25 pk * while we were entering a command bytes (for
2425 1.25 pk * another target) some of those bytes can
2426 1.25 pk * appear in the FIFO here, after the
2427 1.25 pk * interrupt is taken.
2428 1.25 pk */
2429 1.36.2.15 bouyer nfifo = ncr53c9x_rdfifo(sc, NCR_RDFIFO_START);
2430 1.36.2.15 bouyer
2431 1.25 pk if (nfifo < 2 ||
2432 1.36.2.16 bouyer (nfifo > 2 && sc->sc_rev != NCR_VARIANT_ESP100)) {
2433 1.25 pk printf("%s: RESELECT: %d bytes in FIFO! "
2434 1.36.2.16 bouyer "[intr %x, stat %x, step %d, "
2435 1.36.2.16 bouyer "prevphase %x]\n",
2436 1.36.2.16 bouyer sc->sc_dev.dv_xname,
2437 1.36.2.16 bouyer nfifo,
2438 1.36.2.16 bouyer sc->sc_espintr,
2439 1.36.2.16 bouyer sc->sc_espstat,
2440 1.36.2.16 bouyer sc->sc_espstep,
2441 1.36.2.16 bouyer sc->sc_prevphase);
2442 1.25 pk ncr53c9x_init(sc, 1);
2443 1.25 pk return (1);
2444 1.25 pk }
2445 1.36.2.15 bouyer sc->sc_selid = sc->sc_imess[0];
2446 1.36.2.15 bouyer NCR_MISC(("selid=%02x ", sc->sc_selid));
2447 1.25 pk
2448 1.25 pk /* Handle identify message */
2449 1.1 thorpej ncr53c9x_msgin(sc);
2450 1.25 pk if (nfifo != 2) {
2451 1.25 pk /*
2452 1.25 pk * Note: this should not happen
2453 1.25 pk * with `dmaselect' on.
2454 1.25 pk */
2455 1.25 pk sc->sc_flags |= NCR_EXPECT_ILLCMD;
2456 1.25 pk NCRCMD(sc, NCRCMD_FLUSH);
2457 1.36.2.15 bouyer } else if (sc->sc_features & NCR_F_DMASELECT &&
2458 1.36.2.16 bouyer sc->sc_rev == NCR_VARIANT_ESP100) {
2459 1.25 pk sc->sc_flags |= NCR_EXPECT_ILLCMD;
2460 1.25 pk }
2461 1.25 pk
2462 1.36.2.6 bouyer if (sc->sc_state != NCR_CONNECTED &&
2463 1.36.2.6 bouyer sc->sc_state != NCR_IDENTIFIED) {
2464 1.1 thorpej /* IDENTIFY fail?! */
2465 1.36.2.16 bouyer printf("%s: identify failed, "
2466 1.36.2.16 bouyer "state %d, intr %02x\n",
2467 1.36.2.15 bouyer sc->sc_dev.dv_xname, sc->sc_state,
2468 1.36.2.15 bouyer sc->sc_espintr);
2469 1.1 thorpej ncr53c9x_init(sc, 1);
2470 1.25 pk return (1);
2471 1.1 thorpej }
2472 1.25 pk goto shortcut; /* ie. next phase expected soon */
2473 1.25 pk }
2474 1.1 thorpej
2475 1.25 pk #define NCRINTR_DONE (NCRINTR_FC|NCRINTR_BS)
2476 1.25 pk if ((sc->sc_espintr & NCRINTR_DONE) == NCRINTR_DONE) {
2477 1.25 pk /*
2478 1.25 pk * Arbitration won; examine the `step' register
2479 1.25 pk * to determine how far the selection could progress.
2480 1.25 pk */
2481 1.7 gwr ecb = sc->sc_nexus;
2482 1.36.2.6 bouyer if (ecb == NULL)
2483 1.30 pk panic("ncr53c9x: no nexus");
2484 1.25 pk
2485 1.36.2.1 thorpej periph = ecb->xs->xs_periph;
2486 1.36.2.1 thorpej ti = &sc->sc_tinfo[periph->periph_target];
2487 1.1 thorpej
2488 1.25 pk switch (sc->sc_espstep) {
2489 1.25 pk case 0:
2490 1.1 thorpej /*
2491 1.25 pk * The target did not respond with a
2492 1.25 pk * message out phase - probably an old
2493 1.25 pk * device that doesn't recognize ATN.
2494 1.25 pk * Clear ATN and just continue, the
2495 1.25 pk * target should be in the command
2496 1.25 pk * phase.
2497 1.25 pk * XXXX check for command phase?
2498 1.1 thorpej */
2499 1.25 pk NCRCMD(sc, NCRCMD_RSTATN);
2500 1.25 pk break;
2501 1.25 pk case 1:
2502 1.36.2.16 bouyer if ((ti->flags & T_NEGOTIATE) == 0 &&
2503 1.36.2.7 bouyer ecb->tag[0] == 0) {
2504 1.25 pk printf("%s: step 1 & !NEG\n",
2505 1.36.2.16 bouyer sc->sc_dev.dv_xname);
2506 1.25 pk goto reset;
2507 1.1 thorpej }
2508 1.25 pk if (sc->sc_phase != MESSAGE_OUT_PHASE) {
2509 1.25 pk printf("%s: !MSGOUT\n",
2510 1.36.2.16 bouyer sc->sc_dev.dv_xname);
2511 1.25 pk goto reset;
2512 1.1 thorpej }
2513 1.36.2.15 bouyer if (ti->flags & T_WIDE) {
2514 1.36.2.15 bouyer ncr53c9x_sched_msgout(SEND_WDTR);
2515 1.36.2.15 bouyer }
2516 1.36.2.7 bouyer if (ti->flags & T_NEGOTIATE) {
2517 1.36.2.7 bouyer /* Start negotiating */
2518 1.36.2.7 bouyer ti->period = sc->sc_minsync;
2519 1.36.2.7 bouyer ti->offset = 15;
2520 1.36.2.7 bouyer sc->sc_flags |= NCR_SYNCHNEGO;
2521 1.36.2.7 bouyer if (ecb->tag[0])
2522 1.36.2.16 bouyer ncr53c9x_sched_msgout(
2523 1.36.2.16 bouyer SEND_TAG|SEND_SDTR);
2524 1.36.2.7 bouyer else
2525 1.36.2.16 bouyer ncr53c9x_sched_msgout(
2526 1.36.2.16 bouyer SEND_SDTR);
2527 1.36.2.7 bouyer } else {
2528 1.36.2.7 bouyer /* Could not do ATN3 so send TAG */
2529 1.36.2.7 bouyer ncr53c9x_sched_msgout(SEND_TAG);
2530 1.36.2.7 bouyer }
2531 1.36.2.6 bouyer sc->sc_prevphase = MESSAGE_OUT_PHASE; /* XXXX */
2532 1.25 pk break;
2533 1.25 pk case 3:
2534 1.5 pk /*
2535 1.25 pk * Grr, this is supposed to mean
2536 1.25 pk * "target left command phase prematurely".
2537 1.25 pk * It seems to happen regularly when
2538 1.25 pk * sync mode is on.
2539 1.25 pk * Look at FIFO to see if command went out.
2540 1.25 pk * (Timing problems?)
2541 1.5 pk */
2542 1.36.2.15 bouyer if (sc->sc_features & NCR_F_DMASELECT) {
2543 1.25 pk if (sc->sc_cmdlen == 0)
2544 1.8 pk /* Hope for the best.. */
2545 1.8 pk break;
2546 1.25 pk } else if ((NCR_READ_REG(sc, NCR_FFLAG)
2547 1.36.2.16 bouyer & NCRFIFO_FF) == 0) {
2548 1.25 pk /* Hope for the best.. */
2549 1.1 thorpej break;
2550 1.1 thorpej }
2551 1.25 pk printf("(%s:%d:%d): selection failed;"
2552 1.36.2.16 bouyer " %d left in FIFO "
2553 1.36.2.16 bouyer "[intr %x, stat %x, step %d]\n",
2554 1.36.2.16 bouyer sc->sc_dev.dv_xname,
2555 1.36.2.16 bouyer periph->periph_target,
2556 1.36.2.16 bouyer periph->periph_lun,
2557 1.36.2.16 bouyer NCR_READ_REG(sc, NCR_FFLAG)
2558 1.36.2.16 bouyer & NCRFIFO_FF,
2559 1.36.2.16 bouyer sc->sc_espintr, sc->sc_espstat,
2560 1.36.2.16 bouyer sc->sc_espstep);
2561 1.1 thorpej NCRCMD(sc, NCRCMD_FLUSH);
2562 1.25 pk ncr53c9x_sched_msgout(SEND_ABORT);
2563 1.25 pk return (1);
2564 1.25 pk case 2:
2565 1.25 pk /* Select stuck at Command Phase */
2566 1.25 pk NCRCMD(sc, NCRCMD_FLUSH);
2567 1.36.2.4 bouyer break;
2568 1.25 pk case 4:
2569 1.36.2.15 bouyer if (sc->sc_features & NCR_F_DMASELECT &&
2570 1.25 pk sc->sc_cmdlen != 0)
2571 1.25 pk printf("(%s:%d:%d): select; "
2572 1.36.2.16 bouyer "%lu left in DMA buffer "
2573 1.36.2.16 bouyer "[intr %x, stat %x, step %d]\n",
2574 1.36.2.16 bouyer sc->sc_dev.dv_xname,
2575 1.36.2.16 bouyer periph->periph_target,
2576 1.36.2.16 bouyer periph->periph_lun,
2577 1.36.2.16 bouyer (u_long)sc->sc_cmdlen,
2578 1.36.2.16 bouyer sc->sc_espintr,
2579 1.36.2.16 bouyer sc->sc_espstat,
2580 1.36.2.16 bouyer sc->sc_espstep);
2581 1.25 pk /* So far, everything went fine */
2582 1.25 pk break;
2583 1.1 thorpej }
2584 1.25 pk
2585 1.25 pk sc->sc_prevphase = INVALID_PHASE; /* ?? */
2586 1.25 pk /* Do an implicit RESTORE POINTERS. */
2587 1.25 pk sc->sc_dp = ecb->daddr;
2588 1.25 pk sc->sc_dleft = ecb->dleft;
2589 1.25 pk sc->sc_state = NCR_CONNECTED;
2590 1.1 thorpej break;
2591 1.1 thorpej
2592 1.25 pk } else {
2593 1.1 thorpej
2594 1.25 pk printf("%s: unexpected status after select"
2595 1.36.2.16 bouyer ": [intr %x, stat %x, step %x]\n",
2596 1.36.2.16 bouyer sc->sc_dev.dv_xname,
2597 1.36.2.16 bouyer sc->sc_espintr, sc->sc_espstat, sc->sc_espstep);
2598 1.25 pk NCRCMD(sc, NCRCMD_FLUSH);
2599 1.25 pk DELAY(1);
2600 1.25 pk goto reset;
2601 1.1 thorpej }
2602 1.25 pk if (sc->sc_state == NCR_IDLE) {
2603 1.36.2.6 bouyer printf("%s: stray interrupt\n", sc->sc_dev.dv_xname);
2604 1.36.2.6 bouyer return (0);
2605 1.1 thorpej }
2606 1.25 pk break;
2607 1.1 thorpej
2608 1.25 pk case NCR_CONNECTED:
2609 1.36.2.6 bouyer if ((sc->sc_flags & NCR_ICCS) != 0) {
2610 1.25 pk /* "Initiate Command Complete Steps" in progress */
2611 1.25 pk u_char msg;
2612 1.25 pk
2613 1.25 pk sc->sc_flags &= ~NCR_ICCS;
2614 1.25 pk
2615 1.25 pk if (!(sc->sc_espintr & NCRINTR_DONE)) {
2616 1.25 pk printf("%s: ICCS: "
2617 1.36.2.16 bouyer ": [intr %x, stat %x, step %x]\n",
2618 1.36.2.16 bouyer sc->sc_dev.dv_xname,
2619 1.36.2.16 bouyer sc->sc_espintr, sc->sc_espstat,
2620 1.36.2.16 bouyer sc->sc_espstep);
2621 1.1 thorpej }
2622 1.36.2.15 bouyer ncr53c9x_rdfifo(sc, NCR_RDFIFO_START);
2623 1.36.2.15 bouyer if (sc->sc_imlen < 2)
2624 1.36.2.15 bouyer printf("%s: can't get status, only %d bytes\n",
2625 1.36.2.16 bouyer sc->sc_dev.dv_xname, (int)sc->sc_imlen);
2626 1.36.2.15 bouyer ecb->stat = sc->sc_imess[sc->sc_imlen - 2];
2627 1.36.2.15 bouyer msg = sc->sc_imess[sc->sc_imlen - 1];
2628 1.25 pk NCR_PHASE(("<stat:(%x,%x)>", ecb->stat, msg));
2629 1.25 pk if (msg == MSG_CMDCOMPLETE) {
2630 1.25 pk ecb->dleft = (ecb->flags & ECB_TENTATIVE_DONE)
2631 1.36.2.16 bouyer ? 0 : sc->sc_dleft;
2632 1.25 pk if ((ecb->flags & ECB_SENSE) == 0)
2633 1.25 pk ecb->xs->resid = ecb->dleft;
2634 1.25 pk sc->sc_state = NCR_CMDCOMPLETE;
2635 1.25 pk } else
2636 1.25 pk printf("%s: STATUS_PHASE: msg %d\n",
2637 1.36.2.16 bouyer sc->sc_dev.dv_xname, msg);
2638 1.36.2.15 bouyer sc->sc_imlen = 0;
2639 1.25 pk NCRCMD(sc, NCRCMD_MSGOK);
2640 1.25 pk goto shortcut; /* ie. wait for disconnect */
2641 1.25 pk }
2642 1.25 pk break;
2643 1.36.2.6 bouyer
2644 1.25 pk default:
2645 1.36.2.15 bouyer /* Don't panic: reset. */
2646 1.36.2.15 bouyer printf("%s: invalid state: %d",
2647 1.36.2.16 bouyer sc->sc_dev.dv_xname, sc->sc_state);
2648 1.36.2.15 bouyer ncr53c9x_scsi_reset(sc);
2649 1.36.2.15 bouyer goto out;
2650 1.36.2.15 bouyer #if 0
2651 1.25 pk panic("%s: invalid state: %d",
2652 1.36.2.16 bouyer sc->sc_dev.dv_xname, sc->sc_state);
2653 1.36.2.15 bouyer #endif
2654 1.36.2.15 bouyer break;
2655 1.25 pk }
2656 1.8 pk
2657 1.25 pk /*
2658 1.25 pk * Driver is now in state NCR_CONNECTED, i.e. we
2659 1.25 pk * have a current command working the SCSI bus.
2660 1.25 pk */
2661 1.25 pk if (sc->sc_state != NCR_CONNECTED || ecb == NULL) {
2662 1.30 pk panic("ncr53c9x: no nexus");
2663 1.25 pk }
2664 1.22 pk
2665 1.25 pk switch (sc->sc_phase) {
2666 1.25 pk case MESSAGE_OUT_PHASE:
2667 1.25 pk NCR_PHASE(("MESSAGE_OUT_PHASE "));
2668 1.25 pk ncr53c9x_msgout(sc);
2669 1.25 pk sc->sc_prevphase = MESSAGE_OUT_PHASE;
2670 1.25 pk break;
2671 1.36.2.6 bouyer
2672 1.25 pk case MESSAGE_IN_PHASE:
2673 1.36.2.6 bouyer msgin:
2674 1.25 pk NCR_PHASE(("MESSAGE_IN_PHASE "));
2675 1.36.2.6 bouyer if ((sc->sc_espintr & NCRINTR_BS) != 0) {
2676 1.36.2.15 bouyer if ((sc->sc_rev != NCR_VARIANT_FAS366) ||
2677 1.36.2.15 bouyer !(sc->sc_espstat2 & FAS_STAT2_EMPTY)) {
2678 1.36.2.15 bouyer NCRCMD(sc, NCRCMD_FLUSH);
2679 1.36.2.15 bouyer }
2680 1.25 pk sc->sc_flags |= NCR_WAITI;
2681 1.25 pk NCRCMD(sc, NCRCMD_TRANS);
2682 1.36.2.6 bouyer } else if ((sc->sc_espintr & NCRINTR_FC) != 0) {
2683 1.25 pk if ((sc->sc_flags & NCR_WAITI) == 0) {
2684 1.25 pk printf("%s: MSGIN: unexpected FC bit: "
2685 1.36.2.16 bouyer "[intr %x, stat %x, step %x]\n",
2686 1.36.2.16 bouyer sc->sc_dev.dv_xname,
2687 1.36.2.16 bouyer sc->sc_espintr, sc->sc_espstat,
2688 1.36.2.16 bouyer sc->sc_espstep);
2689 1.8 pk }
2690 1.25 pk sc->sc_flags &= ~NCR_WAITI;
2691 1.36.2.15 bouyer ncr53c9x_rdfifo(sc,
2692 1.36.2.15 bouyer (sc->sc_prevphase == sc->sc_phase) ?
2693 1.36.2.15 bouyer NCR_RDFIFO_CONTINUE : NCR_RDFIFO_START);
2694 1.25 pk ncr53c9x_msgin(sc);
2695 1.25 pk } else {
2696 1.25 pk printf("%s: MSGIN: weird bits: "
2697 1.36.2.16 bouyer "[intr %x, stat %x, step %x]\n",
2698 1.36.2.16 bouyer sc->sc_dev.dv_xname,
2699 1.36.2.16 bouyer sc->sc_espintr, sc->sc_espstat, sc->sc_espstep);
2700 1.25 pk }
2701 1.36.2.15 bouyer sc->sc_prevphase = MESSAGE_IN_PHASE;
2702 1.25 pk goto shortcut; /* i.e. expect data to be ready */
2703 1.25 pk break;
2704 1.36.2.6 bouyer
2705 1.25 pk case COMMAND_PHASE:
2706 1.25 pk /*
2707 1.25 pk * Send the command block. Normally we don't see this
2708 1.25 pk * phase because the SEL_ATN command takes care of
2709 1.25 pk * all this. However, we end up here if either the
2710 1.25 pk * target or we wanted to exchange some more messages
2711 1.25 pk * first (e.g. to start negotiations).
2712 1.25 pk */
2713 1.25 pk
2714 1.25 pk NCR_PHASE(("COMMAND_PHASE 0x%02x (%d) ",
2715 1.36.2.16 bouyer ecb->cmd.cmd.opcode, ecb->clen));
2716 1.25 pk if (NCR_READ_REG(sc, NCR_FFLAG) & NCRFIFO_FF) {
2717 1.1 thorpej NCRCMD(sc, NCRCMD_FLUSH);
2718 1.36.2.11 bouyer /* DELAY(1);*/
2719 1.25 pk }
2720 1.36.2.15 bouyer if (sc->sc_features & NCR_F_DMASELECT) {
2721 1.25 pk size_t size;
2722 1.25 pk /* setup DMA transfer for command */
2723 1.25 pk size = ecb->clen;
2724 1.25 pk sc->sc_cmdlen = size;
2725 1.25 pk sc->sc_cmdp = (caddr_t)&ecb->cmd.cmd;
2726 1.25 pk NCRDMA_SETUP(sc, &sc->sc_cmdp, &sc->sc_cmdlen,
2727 1.36.2.16 bouyer 0, &size);
2728 1.1 thorpej /* Program the SCSI counter */
2729 1.36.2.15 bouyer NCR_SET_COUNT(sc, size);
2730 1.25 pk
2731 1.1 thorpej /* load the count in */
2732 1.1 thorpej NCRCMD(sc, NCRCMD_NOP|NCRCMD_DMA);
2733 1.1 thorpej
2734 1.25 pk /* start the command transfer */
2735 1.25 pk NCRCMD(sc, NCRCMD_TRANS | NCRCMD_DMA);
2736 1.1 thorpej NCRDMA_GO(sc);
2737 1.25 pk } else {
2738 1.36.2.15 bouyer ncr53c9x_wrfifo(sc, (u_char *)&ecb->cmd.cmd, ecb->clen);
2739 1.25 pk NCRCMD(sc, NCRCMD_TRANS);
2740 1.25 pk }
2741 1.25 pk sc->sc_prevphase = COMMAND_PHASE;
2742 1.25 pk break;
2743 1.36.2.6 bouyer
2744 1.25 pk case DATA_OUT_PHASE:
2745 1.25 pk NCR_PHASE(("DATA_OUT_PHASE [%ld] ",(long)sc->sc_dleft));
2746 1.25 pk NCRCMD(sc, NCRCMD_FLUSH);
2747 1.25 pk size = min(sc->sc_dleft, sc->sc_maxxfer);
2748 1.36.2.16 bouyer NCRDMA_SETUP(sc, &sc->sc_dp, &sc->sc_dleft, 0, &size);
2749 1.25 pk sc->sc_prevphase = DATA_OUT_PHASE;
2750 1.25 pk goto setup_xfer;
2751 1.36.2.6 bouyer
2752 1.25 pk case DATA_IN_PHASE:
2753 1.25 pk NCR_PHASE(("DATA_IN_PHASE "));
2754 1.25 pk if (sc->sc_rev == NCR_VARIANT_ESP100)
2755 1.25 pk NCRCMD(sc, NCRCMD_FLUSH);
2756 1.25 pk size = min(sc->sc_dleft, sc->sc_maxxfer);
2757 1.36.2.16 bouyer NCRDMA_SETUP(sc, &sc->sc_dp, &sc->sc_dleft, 1, &size);
2758 1.25 pk sc->sc_prevphase = DATA_IN_PHASE;
2759 1.25 pk setup_xfer:
2760 1.25 pk /* Target returned to data phase: wipe "done" memory */
2761 1.25 pk ecb->flags &= ~ECB_TENTATIVE_DONE;
2762 1.25 pk
2763 1.25 pk /* Program the SCSI counter */
2764 1.36.2.15 bouyer NCR_SET_COUNT(sc, size);
2765 1.36.2.15 bouyer
2766 1.25 pk /* load the count in */
2767 1.25 pk NCRCMD(sc, NCRCMD_NOP|NCRCMD_DMA);
2768 1.25 pk
2769 1.25 pk /*
2770 1.25 pk * Note that if `size' is 0, we've already transceived
2771 1.25 pk * all the bytes we want but we're still in DATA PHASE.
2772 1.25 pk * Apparently, the device needs padding. Also, a
2773 1.25 pk * transfer size of 0 means "maximum" to the chip
2774 1.25 pk * DMA logic.
2775 1.25 pk */
2776 1.25 pk NCRCMD(sc,
2777 1.36.2.16 bouyer (size == 0 ? NCRCMD_TRPAD : NCRCMD_TRANS) | NCRCMD_DMA);
2778 1.25 pk NCRDMA_GO(sc);
2779 1.25 pk return (1);
2780 1.36.2.6 bouyer
2781 1.25 pk case STATUS_PHASE:
2782 1.25 pk NCR_PHASE(("STATUS_PHASE "));
2783 1.25 pk sc->sc_flags |= NCR_ICCS;
2784 1.25 pk NCRCMD(sc, NCRCMD_ICCS);
2785 1.25 pk sc->sc_prevphase = STATUS_PHASE;
2786 1.25 pk goto shortcut; /* i.e. expect status results soon */
2787 1.25 pk break;
2788 1.36.2.6 bouyer
2789 1.25 pk case INVALID_PHASE:
2790 1.25 pk break;
2791 1.36.2.6 bouyer
2792 1.25 pk default:
2793 1.25 pk printf("%s: unexpected bus phase; resetting\n",
2794 1.36.2.16 bouyer sc->sc_dev.dv_xname);
2795 1.25 pk goto reset;
2796 1.1 thorpej }
2797 1.25 pk
2798 1.25 pk out:
2799 1.25 pk return (1);
2800 1.1 thorpej
2801 1.1 thorpej reset:
2802 1.1 thorpej ncr53c9x_init(sc, 1);
2803 1.25 pk goto out;
2804 1.1 thorpej
2805 1.1 thorpej finish:
2806 1.1 thorpej ncr53c9x_done(sc, ecb);
2807 1.1 thorpej goto out;
2808 1.1 thorpej
2809 1.1 thorpej sched:
2810 1.1 thorpej sc->sc_state = NCR_IDLE;
2811 1.1 thorpej ncr53c9x_sched(sc);
2812 1.1 thorpej goto out;
2813 1.1 thorpej
2814 1.25 pk shortcut:
2815 1.25 pk /*
2816 1.25 pk * The idea is that many of the SCSI operations take very little
2817 1.25 pk * time, and going away and getting interrupted is too high an
2818 1.25 pk * overhead to pay. For example, selecting, sending a message
2819 1.25 pk * and command and then doing some work can be done in one "pass".
2820 1.25 pk *
2821 1.36.2.16 bouyer * The delay is a heuristic. It is 2 when at 20MHz, 2 at 25MHz and 1
2822 1.36.2.16 bouyer * at 40MHz. This needs testing.
2823 1.25 pk */
2824 1.36.2.16 bouyer {
2825 1.36.2.11 bouyer struct timeval wait, cur;
2826 1.36.2.11 bouyer
2827 1.36.2.11 bouyer microtime(&wait);
2828 1.36.2.16 bouyer wait.tv_usec += 50 / sc->sc_freq;
2829 1.36.2.11 bouyer if (wait.tv_usec > 1000000) {
2830 1.36.2.11 bouyer wait.tv_sec++;
2831 1.36.2.11 bouyer wait.tv_usec -= 1000000;
2832 1.36.2.11 bouyer }
2833 1.36.2.11 bouyer do {
2834 1.36.2.11 bouyer if (NCRDMA_ISINTR(sc))
2835 1.36.2.11 bouyer goto again;
2836 1.36.2.11 bouyer microtime(&cur);
2837 1.36.2.16 bouyer } while (cur.tv_sec <= wait.tv_sec &&
2838 1.36.2.11 bouyer cur.tv_usec <= wait.tv_usec);
2839 1.36.2.11 bouyer }
2840 1.25 pk goto out;
2841 1.1 thorpej }
2842 1.1 thorpej
2843 1.1 thorpej void
2844 1.1 thorpej ncr53c9x_abort(sc, ecb)
2845 1.1 thorpej struct ncr53c9x_softc *sc;
2846 1.1 thorpej struct ncr53c9x_ecb *ecb;
2847 1.1 thorpej {
2848 1.1 thorpej
2849 1.1 thorpej /* 2 secs for the abort */
2850 1.1 thorpej ecb->timeout = NCR_ABORT_TIMEOUT;
2851 1.1 thorpej ecb->flags |= ECB_ABORT;
2852 1.1 thorpej
2853 1.1 thorpej if (ecb == sc->sc_nexus) {
2854 1.36.2.4 bouyer int timeout;
2855 1.36.2.4 bouyer
2856 1.1 thorpej /*
2857 1.1 thorpej * If we're still selecting, the message will be scheduled
2858 1.1 thorpej * after selection is complete.
2859 1.1 thorpej */
2860 1.1 thorpej if (sc->sc_state == NCR_CONNECTED)
2861 1.1 thorpej ncr53c9x_sched_msgout(SEND_ABORT);
2862 1.1 thorpej
2863 1.1 thorpej /*
2864 1.36.2.4 bouyer * Reschedule timeout.
2865 1.1 thorpej */
2866 1.36.2.4 bouyer timeout = ecb->timeout;
2867 1.36.2.4 bouyer if (hz > 100 && timeout > 1000)
2868 1.36.2.4 bouyer timeout = (timeout / 1000) * hz;
2869 1.36.2.4 bouyer else
2870 1.36.2.4 bouyer timeout = (timeout * hz) / 1000;
2871 1.36.2.4 bouyer callout_reset(&ecb->xs->xs_callout, timeout,
2872 1.36.2.4 bouyer ncr53c9x_timeout, ecb);
2873 1.1 thorpej } else {
2874 1.23 pk /*
2875 1.36.2.6 bouyer * Just leave the command where it is.
2876 1.23 pk * XXX - what choice do we have but to reset the SCSI
2877 1.23 pk * eventually?
2878 1.23 pk */
2879 1.1 thorpej if (sc->sc_state == NCR_IDLE)
2880 1.1 thorpej ncr53c9x_sched(sc);
2881 1.1 thorpej }
2882 1.1 thorpej }
2883 1.1 thorpej
2884 1.1 thorpej void
2885 1.1 thorpej ncr53c9x_timeout(arg)
2886 1.1 thorpej void *arg;
2887 1.1 thorpej {
2888 1.1 thorpej struct ncr53c9x_ecb *ecb = arg;
2889 1.18 bouyer struct scsipi_xfer *xs = ecb->xs;
2890 1.36.2.1 thorpej struct scsipi_periph *periph = xs->xs_periph;
2891 1.36.2.1 thorpej struct ncr53c9x_softc *sc =
2892 1.36.2.1 thorpej (void *)periph->periph_channel->chan_adapter->adapt_dev;
2893 1.36.2.1 thorpej struct ncr53c9x_tinfo *ti = &sc->sc_tinfo[periph->periph_target];
2894 1.1 thorpej int s;
2895 1.1 thorpej
2896 1.36.2.1 thorpej scsipi_printaddr(periph);
2897 1.1 thorpej printf("%s: timed out [ecb %p (flags 0x%x, dleft %x, stat %x)], "
2898 1.36.2.16 bouyer "<state %d, nexus %p, phase(l %x, c %x, p %x), resid %lx, "
2899 1.36.2.16 bouyer "msg(q %x,o %x) %s>",
2900 1.36.2.16 bouyer sc->sc_dev.dv_xname,
2901 1.36.2.16 bouyer ecb, ecb->flags, ecb->dleft, ecb->stat,
2902 1.36.2.16 bouyer sc->sc_state, sc->sc_nexus,
2903 1.36.2.16 bouyer NCR_READ_REG(sc, NCR_STAT),
2904 1.36.2.16 bouyer sc->sc_phase, sc->sc_prevphase,
2905 1.36.2.16 bouyer (long)sc->sc_dleft, sc->sc_msgpriq, sc->sc_msgout,
2906 1.36.2.16 bouyer NCRDMA_ISACTIVE(sc) ? "DMA active" : "");
2907 1.7 gwr #if NCR53C9X_DEBUG > 1
2908 1.1 thorpej printf("TRACE: %s.", ecb->trace);
2909 1.1 thorpej #endif
2910 1.1 thorpej
2911 1.1 thorpej s = splbio();
2912 1.1 thorpej
2913 1.1 thorpej if (ecb->flags & ECB_ABORT) {
2914 1.1 thorpej /* abort timed out */
2915 1.1 thorpej printf(" AGAIN\n");
2916 1.16 pk
2917 1.1 thorpej ncr53c9x_init(sc, 1);
2918 1.1 thorpej } else {
2919 1.1 thorpej /* abort the operation that has timed out */
2920 1.1 thorpej printf("\n");
2921 1.1 thorpej xs->error = XS_TIMEOUT;
2922 1.1 thorpej ncr53c9x_abort(sc, ecb);
2923 1.16 pk
2924 1.16 pk /* Disable sync mode if stuck in a data phase */
2925 1.16 pk if (ecb == sc->sc_nexus &&
2926 1.16 pk (ti->flags & T_SYNCMODE) != 0 &&
2927 1.16 pk (sc->sc_phase & (MSGI|CDI)) == 0) {
2928 1.36.2.1 thorpej /* XXX ASYNC CALLBACK! */
2929 1.36.2.1 thorpej scsipi_printaddr(periph);
2930 1.16 pk printf("sync negotiation disabled\n");
2931 1.36.2.16 bouyer sc->sc_cfflags |= (1 << (periph->periph_target + 8));
2932 1.36.2.10 bouyer ncr53c9x_update_xfer_mode(sc, periph->periph_target);
2933 1.16 pk }
2934 1.1 thorpej }
2935 1.1 thorpej
2936 1.1 thorpej splx(s);
2937 1.1 thorpej }
2938 1.36.2.6 bouyer
2939 1.36.2.6 bouyer void
2940 1.36.2.6 bouyer ncr53c9x_watch(arg)
2941 1.36.2.6 bouyer void *arg;
2942 1.36.2.6 bouyer {
2943 1.36.2.6 bouyer struct ncr53c9x_softc *sc = (struct ncr53c9x_softc *)arg;
2944 1.36.2.6 bouyer struct ncr53c9x_tinfo *ti;
2945 1.36.2.6 bouyer struct ncr53c9x_linfo *li;
2946 1.36.2.6 bouyer int t, s;
2947 1.36.2.6 bouyer /* Delete any structures that have not been used in 10min. */
2948 1.36.2.16 bouyer time_t old = time.tv_sec - (10 * 60);
2949 1.36.2.6 bouyer
2950 1.36.2.6 bouyer s = splbio();
2951 1.36.2.16 bouyer for (t = 0; t < NCR_NTARG; t++) {
2952 1.36.2.6 bouyer ti = &sc->sc_tinfo[t];
2953 1.36.2.6 bouyer li = LIST_FIRST(&ti->luns);
2954 1.36.2.6 bouyer while (li) {
2955 1.36.2.16 bouyer if (li->last_used < old &&
2956 1.36.2.16 bouyer li->untagged == NULL &&
2957 1.36.2.6 bouyer li->used == 0) {
2958 1.36.2.6 bouyer if (li->lun < NCR_NLUN)
2959 1.36.2.6 bouyer ti->lun[li->lun] = NULL;
2960 1.36.2.6 bouyer LIST_REMOVE(li, link);
2961 1.36.2.6 bouyer free(li, M_DEVBUF);
2962 1.36.2.6 bouyer /* Restart the search at the beginning */
2963 1.36.2.6 bouyer li = LIST_FIRST(&ti->luns);
2964 1.36.2.16 bouyer continue;
2965 1.36.2.6 bouyer }
2966 1.36.2.6 bouyer li = LIST_NEXT(li, link);
2967 1.36.2.6 bouyer }
2968 1.36.2.6 bouyer }
2969 1.36.2.6 bouyer splx(s);
2970 1.36.2.16 bouyer callout_reset(&sc->sc_watchdog, 60 * hz, ncr53c9x_watch, sc);
2971 1.36.2.6 bouyer }
2972 1.36.2.6 bouyer
2973