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