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