ncr53c9x.c revision 1.36.2.10 1 1.36.2.10 bouyer /* $NetBSD: ncr53c9x.c,v 1.36.2.10 2000/12/19 21:59:08 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.6 bouyer if (ecb->tag[0]) {
661 1.36.2.6 bouyer /* We'll use tags */
662 1.36.2.6 bouyer ecb->cmd.msg[0] = MSG_IDENTIFY(lun, 1);
663 1.36.2.6 bouyer ecb->cmd.msg[1] = ecb->tag[0];
664 1.36.2.6 bouyer ecb->cmd.msg[2] = ecb->tag[1];
665 1.36.2.6 bouyer cmd = (u_char *)&ecb->cmd.msg[0];
666 1.36.2.6 bouyer clen = ecb->clen + 3;
667 1.36.2.7 bouyer
668 1.36.2.7 bouyer if (!selatn3)
669 1.36.2.7 bouyer selandstop = 1;
670 1.36.2.6 bouyer } else {
671 1.36.2.6 bouyer ecb->cmd.msg[2] =
672 1.36.2.6 bouyer MSG_IDENTIFY(lun, (tiflags & T_RSELECTOFF)?0:1);
673 1.36.2.6 bouyer cmd = (u_char *)&ecb->cmd.msg[2];
674 1.36.2.6 bouyer clen = ecb->clen + 1;
675 1.36.2.6 bouyer }
676 1.36.2.6 bouyer
677 1.36.2.7 bouyer if (ncr53c9x_dmaselect && !selandstop) {
678 1.22 pk
679 1.8 pk /* setup DMA transfer for command */
680 1.36.2.6 bouyer dmasize = clen;
681 1.8 pk sc->sc_cmdlen = clen;
682 1.36.2.6 bouyer sc->sc_cmdp = cmd;
683 1.22 pk NCRDMA_SETUP(sc, &sc->sc_cmdp, &sc->sc_cmdlen, 0, &dmasize);
684 1.22 pk
685 1.8 pk /* Program the SCSI counter */
686 1.22 pk NCR_WRITE_REG(sc, NCR_TCL, dmasize);
687 1.22 pk NCR_WRITE_REG(sc, NCR_TCM, dmasize >> 8);
688 1.8 pk if (sc->sc_cfg2 & NCRCFG2_FE) {
689 1.22 pk NCR_WRITE_REG(sc, NCR_TCH, dmasize >> 16);
690 1.8 pk }
691 1.8 pk
692 1.22 pk /* load the count in */
693 1.22 pk NCRCMD(sc, NCRCMD_NOP|NCRCMD_DMA);
694 1.22 pk
695 1.8 pk /* And get the targets attention */
696 1.36.2.6 bouyer if (ecb->tag[0])
697 1.36.2.6 bouyer NCRCMD(sc, NCRCMD_SELATN3 | NCRCMD_DMA);
698 1.36.2.6 bouyer else
699 1.36.2.6 bouyer NCRCMD(sc, NCRCMD_SELATN | NCRCMD_DMA);
700 1.8 pk NCRDMA_GO(sc);
701 1.8 pk return;
702 1.8 pk }
703 1.22 pk
704 1.1 thorpej /*
705 1.1 thorpej * Who am I. This is where we tell the target that we are
706 1.1 thorpej * happy for it to disconnect etc.
707 1.1 thorpej */
708 1.36.2.6 bouyer NCR_WRITE_REG(sc, NCR_FIFO, *cmd++);
709 1.36.2.6 bouyer clen --;
710 1.1 thorpej
711 1.36.2.7 bouyer if (selandstop) {
712 1.1 thorpej /* Arbitrate, select and stop after IDENTIFY message */
713 1.1 thorpej NCRCMD(sc, NCRCMD_SELATNS);
714 1.1 thorpej return;
715 1.1 thorpej }
716 1.1 thorpej
717 1.36.2.6 bouyer /* If we want to send a tag, get it into the fifo */
718 1.36.2.6 bouyer if (ecb->tag[0]) {
719 1.36.2.6 bouyer NCR_WRITE_REG(sc, NCR_FIFO, *cmd++);
720 1.36.2.6 bouyer clen --;
721 1.36.2.6 bouyer NCR_WRITE_REG(sc, NCR_FIFO, *cmd++);
722 1.36.2.6 bouyer clen --;
723 1.36.2.6 bouyer }
724 1.36.2.6 bouyer
725 1.36.2.6 bouyer /* Now get the command into the FIFO */
726 1.1 thorpej while (clen--)
727 1.1 thorpej NCR_WRITE_REG(sc, NCR_FIFO, *cmd++);
728 1.1 thorpej
729 1.1 thorpej /* And get the targets attention */
730 1.36.2.6 bouyer if (ecb->tag[0])
731 1.36.2.6 bouyer NCRCMD(sc, NCRCMD_SELATN3);
732 1.36.2.6 bouyer else
733 1.36.2.6 bouyer NCRCMD(sc, NCRCMD_SELATN);
734 1.1 thorpej }
735 1.1 thorpej
736 1.1 thorpej void
737 1.36.2.2 thorpej ncr53c9x_free_ecb(sc, ecb)
738 1.1 thorpej struct ncr53c9x_softc *sc;
739 1.1 thorpej struct ncr53c9x_ecb *ecb;
740 1.1 thorpej {
741 1.1 thorpej int s;
742 1.1 thorpej
743 1.1 thorpej s = splbio();
744 1.1 thorpej ecb->flags = 0;
745 1.36.2.6 bouyer pool_put(&ecb_pool, (void *)ecb);
746 1.1 thorpej splx(s);
747 1.36.2.6 bouyer return;
748 1.1 thorpej }
749 1.1 thorpej
750 1.1 thorpej struct ncr53c9x_ecb *
751 1.36.2.6 bouyer ncr53c9x_get_ecb(sc, flags)
752 1.1 thorpej struct ncr53c9x_softc *sc;
753 1.36.2.6 bouyer int flags;
754 1.1 thorpej {
755 1.1 thorpej struct ncr53c9x_ecb *ecb;
756 1.36.2.6 bouyer int s, wait = 0;
757 1.36.2.6 bouyer
758 1.36.2.6 bouyer if ((curproc != NULL) && ((flags & XS_CTL_NOSLEEP) == 0))
759 1.36.2.6 bouyer wait = PR_WAITOK;
760 1.1 thorpej
761 1.1 thorpej s = splbio();
762 1.36.2.6 bouyer ecb = (struct ncr53c9x_ecb *)pool_get(&ecb_pool, wait);
763 1.1 thorpej splx(s);
764 1.36.2.6 bouyer bzero(ecb, sizeof(*ecb));
765 1.36.2.6 bouyer if (ecb)
766 1.36.2.6 bouyer ecb->flags |= ECB_ALLOC;
767 1.25 pk return (ecb);
768 1.1 thorpej }
769 1.1 thorpej
770 1.1 thorpej /*
771 1.1 thorpej * DRIVER FUNCTIONS CALLABLE FROM HIGHER LEVEL DRIVERS
772 1.1 thorpej */
773 1.1 thorpej
774 1.1 thorpej /*
775 1.1 thorpej * Start a SCSI-command
776 1.1 thorpej * This function is called by the higher level SCSI-driver to queue/run
777 1.1 thorpej * SCSI-commands.
778 1.1 thorpej */
779 1.36.2.4 bouyer
780 1.36.2.1 thorpej void
781 1.36.2.1 thorpej ncr53c9x_scsipi_request(chan, req, arg)
782 1.36.2.1 thorpej struct scsipi_channel *chan;
783 1.36.2.1 thorpej scsipi_adapter_req_t req;
784 1.36.2.1 thorpej void *arg;
785 1.1 thorpej {
786 1.36.2.1 thorpej struct scsipi_xfer *xs;
787 1.36.2.1 thorpej struct scsipi_periph *periph;
788 1.36.2.1 thorpej struct ncr53c9x_softc *sc = (void *)chan->chan_adapter->adapt_dev;
789 1.1 thorpej struct ncr53c9x_ecb *ecb;
790 1.1 thorpej int s, flags;
791 1.1 thorpej
792 1.36.2.1 thorpej NCR_TRACE(("[ncr53c9x_scsipi_request] "));
793 1.1 thorpej
794 1.36.2.1 thorpej switch (req) {
795 1.36.2.1 thorpej case ADAPTER_REQ_RUN_XFER:
796 1.36.2.1 thorpej xs = arg;
797 1.36.2.1 thorpej periph = xs->xs_periph;
798 1.36.2.1 thorpej flags = xs->xs_control;
799 1.36.2.1 thorpej
800 1.36.2.1 thorpej NCR_CMDS(("[0x%x, %d]->%d ", (int)xs->cmd->opcode, xs->cmdlen,
801 1.36.2.1 thorpej periph->periph_target));
802 1.36.2.1 thorpej
803 1.36.2.1 thorpej /* Get an ECB to use. */
804 1.36.2.6 bouyer ecb = ncr53c9x_get_ecb(sc, xs->xs_control);
805 1.36.2.1 thorpej #ifdef DIAGNOSTIC
806 1.36.2.1 thorpej /*
807 1.36.2.1 thorpej * This should never happen as we track resources
808 1.36.2.1 thorpej * in the mid-layer.
809 1.36.2.1 thorpej */
810 1.36.2.1 thorpej if (ecb == NULL) {
811 1.36.2.1 thorpej scsipi_printaddr(periph);
812 1.36.2.1 thorpej printf("unable to allocate ecb\n");
813 1.36.2.1 thorpej panic("ncr53c9x_scsipi_request");
814 1.36.2.1 thorpej }
815 1.36.2.1 thorpej #endif
816 1.1 thorpej
817 1.36.2.1 thorpej /* Initialize ecb */
818 1.36.2.1 thorpej ecb->xs = xs;
819 1.36.2.1 thorpej ecb->timeout = xs->timeout;
820 1.36.2.1 thorpej
821 1.36.2.1 thorpej if (flags & XS_CTL_RESET) {
822 1.36.2.1 thorpej ecb->flags |= ECB_RESET;
823 1.36.2.1 thorpej ecb->clen = 0;
824 1.36.2.1 thorpej ecb->dleft = 0;
825 1.36.2.1 thorpej } else {
826 1.36.2.1 thorpej bcopy(xs->cmd, &ecb->cmd.cmd, xs->cmdlen);
827 1.36.2.1 thorpej ecb->clen = xs->cmdlen;
828 1.36.2.1 thorpej ecb->daddr = xs->data;
829 1.36.2.1 thorpej ecb->dleft = xs->datalen;
830 1.36.2.1 thorpej }
831 1.36.2.1 thorpej ecb->stat = 0;
832 1.1 thorpej
833 1.36.2.1 thorpej s = splbio();
834 1.36.2.1 thorpej
835 1.36.2.1 thorpej TAILQ_INSERT_TAIL(&sc->ready_list, ecb, chain);
836 1.36.2.1 thorpej if (sc->sc_state == NCR_IDLE)
837 1.36.2.1 thorpej ncr53c9x_sched(sc);
838 1.1 thorpej
839 1.36.2.1 thorpej splx(s);
840 1.1 thorpej
841 1.36.2.1 thorpej if ((flags & XS_CTL_POLL) == 0)
842 1.36.2.1 thorpej return;
843 1.36.2.1 thorpej
844 1.36.2.1 thorpej /* Not allowed to use interrupts, use polling instead */
845 1.36.2.1 thorpej if (ncr53c9x_poll(sc, xs, ecb->timeout)) {
846 1.1 thorpej ncr53c9x_timeout(ecb);
847 1.36.2.1 thorpej if (ncr53c9x_poll(sc, xs, ecb->timeout))
848 1.36.2.1 thorpej ncr53c9x_timeout(ecb);
849 1.36.2.1 thorpej }
850 1.36.2.1 thorpej return;
851 1.36.2.1 thorpej
852 1.36.2.1 thorpej case ADAPTER_REQ_GROW_RESOURCES:
853 1.36.2.1 thorpej /* XXX Not supported. */
854 1.36.2.1 thorpej return;
855 1.36.2.1 thorpej
856 1.36.2.1 thorpej case ADAPTER_REQ_SET_XFER_MODE:
857 1.36.2.1 thorpej {
858 1.36.2.1 thorpej struct ncr53c9x_tinfo *ti;
859 1.36.2.3 thorpej struct scsipi_xfer_mode *xm = arg;
860 1.36.2.3 thorpej
861 1.36.2.3 thorpej ti = &sc->sc_tinfo[xm->xm_target];
862 1.36.2.3 thorpej ti->flags &= ~(T_NEGOTIATE|T_SYNCMODE);
863 1.36.2.3 thorpej ti->period = 0;
864 1.36.2.3 thorpej ti->offset = 0;
865 1.36.2.3 thorpej
866 1.36.2.8 bouyer if ((sc->sc_cfflags & (1<<(xm->xm_target+16))) == 0 &&
867 1.36.2.8 bouyer (xm->xm_mode & PERIPH_CAP_TQING))
868 1.36.2.8 bouyer ti->flags &= ~T_TAGOFF;
869 1.36.2.8 bouyer else
870 1.36.2.8 bouyer ti->flags |= T_TAGOFF;
871 1.36.2.8 bouyer
872 1.36.2.3 thorpej if ((xm->xm_mode & PERIPH_CAP_SYNC) != 0 &&
873 1.36.2.8 bouyer (ti->flags & T_SYNCHOFF) == 0) {
874 1.36.2.1 thorpej ti->flags |= T_NEGOTIATE;
875 1.36.2.1 thorpej ti->period = sc->sc_minsync;
876 1.36.2.1 thorpej }
877 1.36.2.10 bouyer printf("target %d flags 0x%x sc_minsync %d period %d\n",
878 1.36.2.10 bouyer xm->xm_target, ti->flags, sc->sc_minsync, ti->period);
879 1.36.2.3 thorpej /*
880 1.36.2.3 thorpej * If we're not going to negotiate, send the notification
881 1.36.2.3 thorpej * now, since it won't happen later.
882 1.36.2.3 thorpej */
883 1.36.2.3 thorpej if ((ti->flags & T_NEGOTIATE) == 0)
884 1.36.2.3 thorpej ncr53c9x_update_xfer_mode(sc, xm->xm_target);
885 1.36.2.1 thorpej return;
886 1.36.2.1 thorpej }
887 1.36.2.3 thorpej }
888 1.36.2.3 thorpej }
889 1.36.2.1 thorpej
890 1.36.2.3 thorpej void
891 1.36.2.3 thorpej ncr53c9x_update_xfer_mode(sc, target)
892 1.36.2.3 thorpej struct ncr53c9x_softc *sc;
893 1.36.2.3 thorpej int target;
894 1.36.2.3 thorpej {
895 1.36.2.3 thorpej struct scsipi_xfer_mode xm;
896 1.36.2.3 thorpej struct ncr53c9x_tinfo *ti = &sc->sc_tinfo[target];
897 1.36.2.1 thorpej
898 1.36.2.3 thorpej xm.xm_target = target;
899 1.36.2.3 thorpej xm.xm_mode = 0;
900 1.36.2.3 thorpej xm.xm_period = 0;
901 1.36.2.3 thorpej xm.xm_offset = 0;
902 1.36.2.3 thorpej
903 1.36.2.3 thorpej if (ti->flags & T_SYNCMODE) {
904 1.36.2.3 thorpej xm.xm_mode |= PERIPH_CAP_SYNC;
905 1.36.2.3 thorpej xm.xm_period = ti->period;
906 1.36.2.3 thorpej xm.xm_offset = ti->offset;
907 1.1 thorpej }
908 1.36.2.8 bouyer if ((ti->flags & (T_RSELECTOFF|T_TAGOFF)) == 0)
909 1.36.2.8 bouyer xm.xm_mode |= PERIPH_CAP_TQING;
910 1.36.2.3 thorpej
911 1.36.2.3 thorpej scsipi_async_event(&sc->sc_channel, ASYNC_EVENT_XFER_MODE, &xm);
912 1.1 thorpej }
913 1.1 thorpej
914 1.1 thorpej /*
915 1.1 thorpej * Used when interrupt driven I/O isn't allowed, e.g. during boot.
916 1.1 thorpej */
917 1.1 thorpej int
918 1.1 thorpej ncr53c9x_poll(sc, xs, count)
919 1.1 thorpej struct ncr53c9x_softc *sc;
920 1.18 bouyer struct scsipi_xfer *xs;
921 1.1 thorpej int count;
922 1.1 thorpej {
923 1.1 thorpej
924 1.1 thorpej NCR_TRACE(("[ncr53c9x_poll] "));
925 1.1 thorpej while (count) {
926 1.1 thorpej if (NCRDMA_ISINTR(sc)) {
927 1.1 thorpej ncr53c9x_intr(sc);
928 1.1 thorpej }
929 1.1 thorpej #if alternatively
930 1.1 thorpej if (NCR_READ_REG(sc, NCR_STAT) & NCRSTAT_INT)
931 1.1 thorpej ncr53c9x_intr(sc);
932 1.1 thorpej #endif
933 1.36 thorpej if ((xs->xs_status & XS_STS_DONE) != 0)
934 1.25 pk return (0);
935 1.1 thorpej if (sc->sc_state == NCR_IDLE) {
936 1.1 thorpej NCR_TRACE(("[ncr53c9x_poll: rescheduling] "));
937 1.1 thorpej ncr53c9x_sched(sc);
938 1.1 thorpej }
939 1.1 thorpej DELAY(1000);
940 1.1 thorpej count--;
941 1.1 thorpej }
942 1.25 pk return (1);
943 1.1 thorpej }
944 1.1 thorpej
945 1.36.2.5 bouyer int
946 1.36.2.5 bouyer ncr53c9x_ioctl(chan, cmd, arg, flag, p)
947 1.36.2.5 bouyer struct scsipi_channel *chan;
948 1.36.2.5 bouyer u_long cmd;
949 1.36.2.5 bouyer caddr_t arg;
950 1.36.2.5 bouyer int flag;
951 1.36.2.5 bouyer struct proc *p;
952 1.36.2.5 bouyer {
953 1.36.2.8 bouyer /* struct ncr53c9x_softc *sc = (void *)chan->chan_adapter->adapt_dev; */
954 1.36.2.6 bouyer int s, error = 0;
955 1.36.2.5 bouyer
956 1.36.2.5 bouyer s = splbio();
957 1.36.2.5 bouyer
958 1.36.2.5 bouyer switch (cmd) {
959 1.36.2.5 bouyer default:
960 1.36.2.5 bouyer error = ENOTTY;
961 1.36.2.5 bouyer break;
962 1.36.2.5 bouyer }
963 1.36.2.5 bouyer splx(s);
964 1.36.2.5 bouyer return (error);
965 1.36.2.5 bouyer }
966 1.36.2.5 bouyer
967 1.1 thorpej
968 1.1 thorpej /*
969 1.1 thorpej * LOW LEVEL SCSI UTILITIES
970 1.1 thorpej */
971 1.1 thorpej
972 1.1 thorpej /*
973 1.1 thorpej * Schedule a scsi operation. This has now been pulled out of the interrupt
974 1.36.2.1 thorpej * handler so that we may call it from ncr53c9x_scsipi_request and
975 1.36.2.1 thorpej * ncr53c9x_done. This may save us an unecessary interrupt just to get
976 1.36.2.1 thorpej * things going. Should only be called when state == NCR_IDLE and at bio pl.
977 1.1 thorpej */
978 1.1 thorpej void
979 1.1 thorpej ncr53c9x_sched(sc)
980 1.1 thorpej struct ncr53c9x_softc *sc;
981 1.1 thorpej {
982 1.1 thorpej struct ncr53c9x_ecb *ecb;
983 1.36.2.1 thorpej struct scsipi_periph *periph;
984 1.1 thorpej struct ncr53c9x_tinfo *ti;
985 1.36.2.6 bouyer int lun;
986 1.36.2.6 bouyer struct ncr53c9x_linfo *li;
987 1.36.2.6 bouyer int s, tag;
988 1.1 thorpej
989 1.1 thorpej NCR_TRACE(("[ncr53c9x_sched] "));
990 1.1 thorpej if (sc->sc_state != NCR_IDLE)
991 1.1 thorpej panic("ncr53c9x_sched: not IDLE (state=%d)", sc->sc_state);
992 1.1 thorpej
993 1.1 thorpej /*
994 1.1 thorpej * Find first ecb in ready queue that is for a target/lunit
995 1.1 thorpej * combinations that is not busy.
996 1.1 thorpej */
997 1.36.2.6 bouyer for (ecb = TAILQ_FIRST(&sc->ready_list); ecb != NULL;
998 1.36.2.6 bouyer ecb = TAILQ_NEXT(ecb, chain)) {
999 1.36.2.1 thorpej periph = ecb->xs->xs_periph;
1000 1.36.2.1 thorpej ti = &sc->sc_tinfo[periph->periph_target];
1001 1.36.2.6 bouyer lun = periph->periph_lun;
1002 1.36.2.6 bouyer
1003 1.36.2.6 bouyer /* Select type of tag for this command */
1004 1.36.2.6 bouyer if ((ti->flags & (T_RSELECTOFF|T_TAGOFF)) != 0)
1005 1.36.2.6 bouyer tag = 0;
1006 1.36.2.6 bouyer else if ((ecb->flags & ECB_SENSE) != 0)
1007 1.36.2.6 bouyer tag = 0;
1008 1.36.2.6 bouyer else
1009 1.36.2.6 bouyer tag = ecb->xs->xs_tag_type;
1010 1.36.2.6 bouyer #if 0
1011 1.36.2.6 bouyer /* XXXX Use tags for polled commands? */
1012 1.36.2.6 bouyer if (ecb->xs->xs_control & XS_CTL_POLL)
1013 1.36.2.6 bouyer tag = 0;
1014 1.36.2.6 bouyer #endif
1015 1.36.2.6 bouyer
1016 1.36.2.6 bouyer s = splbio();
1017 1.36.2.6 bouyer li = TINFO_LUN(ti, lun);
1018 1.36.2.6 bouyer if (li == NULL) {
1019 1.36.2.6 bouyer int wait = M_NOWAIT;
1020 1.36.2.6 bouyer int flags = ecb->xs->xs_control;
1021 1.36.2.6 bouyer
1022 1.36.2.6 bouyer /* Initialize LUN info and add to list. */
1023 1.36.2.6 bouyer if ((curproc != NULL) && ((flags & XS_CTL_NOSLEEP) == 0))
1024 1.36.2.6 bouyer wait = M_WAITOK;
1025 1.36.2.6 bouyer if ((li = malloc(sizeof(*li), M_DEVBUF, M_NOWAIT)) == NULL) {
1026 1.36.2.6 bouyer splx(s);
1027 1.36.2.6 bouyer continue;
1028 1.36.2.6 bouyer }
1029 1.36.2.6 bouyer bzero(li, sizeof(*li));
1030 1.36.2.6 bouyer li->lun = lun;
1031 1.36.2.6 bouyer
1032 1.36.2.6 bouyer LIST_INSERT_HEAD(&ti->luns, li, link);
1033 1.36.2.6 bouyer if (lun < NCR_NLUN)
1034 1.36.2.6 bouyer ti->lun[lun] = li;
1035 1.36.2.6 bouyer }
1036 1.36.2.6 bouyer li->last_used = time.tv_sec;
1037 1.36.2.6 bouyer if (tag == 0) {
1038 1.36.2.6 bouyer /* Try to issue this as an un-tagged command */
1039 1.36.2.6 bouyer if (li->untagged == NULL)
1040 1.36.2.6 bouyer li->untagged = ecb;
1041 1.36.2.6 bouyer }
1042 1.36.2.6 bouyer if (li->untagged != NULL) {
1043 1.36.2.6 bouyer tag = 0;
1044 1.36.2.6 bouyer if ((li->busy != 1) && li->used == 0) {
1045 1.36.2.6 bouyer /* We need to issue this untagged command now */
1046 1.36.2.6 bouyer ecb = li->untagged;
1047 1.36.2.6 bouyer periph = ecb->xs->xs_periph;
1048 1.36.2.6 bouyer }
1049 1.36.2.6 bouyer else {
1050 1.36.2.6 bouyer /* Not ready yet */
1051 1.36.2.6 bouyer splx(s);
1052 1.36.2.6 bouyer continue;
1053 1.36.2.6 bouyer }
1054 1.36.2.6 bouyer }
1055 1.36.2.6 bouyer ecb->tag[0] = tag;
1056 1.36.2.6 bouyer if (tag != 0) {
1057 1.36.2.6 bouyer li->queued[ecb->xs->xs_tag_id] = ecb;
1058 1.36.2.6 bouyer ecb->tag[1] = ecb->xs->xs_tag_id;
1059 1.36.2.6 bouyer }
1060 1.36.2.6 bouyer splx(s);
1061 1.36.2.6 bouyer if (li->untagged != NULL && (li->busy != 1)) {
1062 1.36.2.6 bouyer li->busy = 1;
1063 1.36.2.6 bouyer TAILQ_REMOVE(&sc->ready_list, ecb, chain);
1064 1.36.2.6 bouyer ecb->flags &= ~ECB_READY;
1065 1.36.2.6 bouyer sc->sc_nexus = ecb;
1066 1.36.2.6 bouyer ncr53c9x_select(sc, ecb);
1067 1.36.2.6 bouyer break;
1068 1.36.2.6 bouyer }
1069 1.36.2.6 bouyer if (li->untagged == NULL && tag != 0) {
1070 1.1 thorpej TAILQ_REMOVE(&sc->ready_list, ecb, chain);
1071 1.36.2.6 bouyer ecb->flags &= ~ECB_READY;
1072 1.1 thorpej sc->sc_nexus = ecb;
1073 1.1 thorpej ncr53c9x_select(sc, ecb);
1074 1.1 thorpej break;
1075 1.1 thorpej } else
1076 1.1 thorpej NCR_MISC(("%d:%d busy\n",
1077 1.36.2.1 thorpej periph->periph_target,
1078 1.36.2.1 thorpej periph->periph_lun));
1079 1.1 thorpej }
1080 1.1 thorpej }
1081 1.1 thorpej
1082 1.1 thorpej void
1083 1.1 thorpej ncr53c9x_sense(sc, ecb)
1084 1.1 thorpej struct ncr53c9x_softc *sc;
1085 1.1 thorpej struct ncr53c9x_ecb *ecb;
1086 1.1 thorpej {
1087 1.18 bouyer struct scsipi_xfer *xs = ecb->xs;
1088 1.36.2.1 thorpej struct scsipi_periph *periph = xs->xs_periph;
1089 1.36.2.1 thorpej struct ncr53c9x_tinfo *ti = &sc->sc_tinfo[periph->periph_target];
1090 1.18 bouyer struct scsipi_sense *ss = (void *)&ecb->cmd.cmd;
1091 1.36.2.6 bouyer struct ncr53c9x_linfo *li;
1092 1.36.2.6 bouyer int lun = periph->periph_lun;
1093 1.1 thorpej
1094 1.1 thorpej NCR_MISC(("requesting sense "));
1095 1.1 thorpej /* Next, setup a request sense command block */
1096 1.1 thorpej bzero(ss, sizeof(*ss));
1097 1.1 thorpej ss->opcode = REQUEST_SENSE;
1098 1.36.2.1 thorpej ss->byte2 = periph->periph_lun << 5;
1099 1.18 bouyer ss->length = sizeof(struct scsipi_sense_data);
1100 1.1 thorpej ecb->clen = sizeof(*ss);
1101 1.18 bouyer ecb->daddr = (char *)&xs->sense.scsi_sense;
1102 1.18 bouyer ecb->dleft = sizeof(struct scsipi_sense_data);
1103 1.1 thorpej ecb->flags |= ECB_SENSE;
1104 1.7 gwr ecb->timeout = NCR_SENSE_TIMEOUT;
1105 1.1 thorpej ti->senses++;
1106 1.36.2.6 bouyer li = TINFO_LUN(ti, lun);
1107 1.36.2.6 bouyer if (li->busy) li->busy = 0;
1108 1.36.2.6 bouyer ncr53c9x_dequeue(sc, ecb);
1109 1.36.2.6 bouyer li->untagged = ecb; /* must be executed first to fix C/A */
1110 1.36.2.6 bouyer li->busy = 2;
1111 1.1 thorpej if (ecb == sc->sc_nexus) {
1112 1.1 thorpej ncr53c9x_select(sc, ecb);
1113 1.1 thorpej } else {
1114 1.1 thorpej TAILQ_INSERT_HEAD(&sc->ready_list, ecb, chain);
1115 1.36.2.6 bouyer ecb->flags |= ECB_READY;
1116 1.1 thorpej if (sc->sc_state == NCR_IDLE)
1117 1.1 thorpej ncr53c9x_sched(sc);
1118 1.1 thorpej }
1119 1.1 thorpej }
1120 1.1 thorpej
1121 1.1 thorpej /*
1122 1.1 thorpej * POST PROCESSING OF SCSI_CMD (usually current)
1123 1.1 thorpej */
1124 1.1 thorpej void
1125 1.1 thorpej ncr53c9x_done(sc, ecb)
1126 1.1 thorpej struct ncr53c9x_softc *sc;
1127 1.1 thorpej struct ncr53c9x_ecb *ecb;
1128 1.1 thorpej {
1129 1.18 bouyer struct scsipi_xfer *xs = ecb->xs;
1130 1.36.2.1 thorpej struct scsipi_periph *periph = xs->xs_periph;
1131 1.36.2.1 thorpej struct ncr53c9x_tinfo *ti = &sc->sc_tinfo[periph->periph_target];
1132 1.36.2.6 bouyer int lun = periph->periph_lun;
1133 1.36.2.6 bouyer struct ncr53c9x_linfo *li = TINFO_LUN(ti, lun);
1134 1.1 thorpej
1135 1.1 thorpej NCR_TRACE(("[ncr53c9x_done(error:%x)] ", xs->error));
1136 1.1 thorpej
1137 1.36.2.4 bouyer callout_stop(&ecb->xs->xs_callout);
1138 1.7 gwr
1139 1.1 thorpej /*
1140 1.1 thorpej * Now, if we've come here with no error code, i.e. we've kept the
1141 1.1 thorpej * initial XS_NOERROR, and the status code signals that we should
1142 1.1 thorpej * check sense, we'll need to set up a request sense cmd block and
1143 1.1 thorpej * push the command back into the ready queue *before* any other
1144 1.1 thorpej * commands for this target/lunit, else we lose the sense info.
1145 1.1 thorpej * We don't support chk sense conditions for the request sense cmd.
1146 1.1 thorpej */
1147 1.1 thorpej if (xs->error == XS_NOERROR) {
1148 1.12 pk xs->status = ecb->stat;
1149 1.1 thorpej if ((ecb->flags & ECB_ABORT) != 0) {
1150 1.16 pk xs->error = XS_TIMEOUT;
1151 1.1 thorpej } else if ((ecb->flags & ECB_SENSE) != 0) {
1152 1.1 thorpej xs->error = XS_SENSE;
1153 1.1 thorpej } else if ((ecb->stat & ST_MASK) == SCSI_CHECK) {
1154 1.1 thorpej /* First, save the return values */
1155 1.1 thorpej xs->resid = ecb->dleft;
1156 1.1 thorpej ncr53c9x_sense(sc, ecb);
1157 1.1 thorpej return;
1158 1.1 thorpej } else {
1159 1.1 thorpej xs->resid = ecb->dleft;
1160 1.36.2.8 bouyer }
1161 1.36.2.9 bouyer if (xs->status == SCSI_QUEUE_FULL)
1162 1.36.2.8 bouyer xs->error = XS_BUSY;
1163 1.1 thorpej }
1164 1.1 thorpej
1165 1.1 thorpej #ifdef NCR53C9X_DEBUG
1166 1.1 thorpej if (ncr53c9x_debug & NCR_SHOWMISC) {
1167 1.1 thorpej if (xs->resid != 0)
1168 1.1 thorpej printf("resid=%d ", xs->resid);
1169 1.1 thorpej if (xs->error == XS_SENSE)
1170 1.18 bouyer printf("sense=0x%02x\n", xs->sense.scsi_sense.error_code);
1171 1.1 thorpej else
1172 1.1 thorpej printf("error=%d\n", xs->error);
1173 1.1 thorpej }
1174 1.1 thorpej #endif
1175 1.1 thorpej
1176 1.1 thorpej /*
1177 1.1 thorpej * Remove the ECB from whatever queue it's on.
1178 1.1 thorpej */
1179 1.36.2.6 bouyer ncr53c9x_dequeue(sc, ecb);
1180 1.1 thorpej if (ecb == sc->sc_nexus) {
1181 1.1 thorpej sc->sc_nexus = NULL;
1182 1.15 pk if (sc->sc_state != NCR_CLEANING) {
1183 1.15 pk sc->sc_state = NCR_IDLE;
1184 1.15 pk ncr53c9x_sched(sc);
1185 1.15 pk }
1186 1.36.2.6 bouyer }
1187 1.36.2.6 bouyer
1188 1.36.2.6 bouyer if (xs->error == XS_SELTIMEOUT) {
1189 1.36.2.6 bouyer /* Selection timeout -- discard this LUN if empty */
1190 1.36.2.6 bouyer if (li->untagged == NULL && li->used == 0) {
1191 1.36.2.6 bouyer if (lun < NCR_NLUN)
1192 1.36.2.6 bouyer ti->lun[lun] = NULL;
1193 1.36.2.6 bouyer LIST_REMOVE(li, link);
1194 1.36.2.6 bouyer free(li, M_DEVBUF);
1195 1.36.2.6 bouyer }
1196 1.36.2.6 bouyer }
1197 1.36.2.6 bouyer
1198 1.36.2.2 thorpej ncr53c9x_free_ecb(sc, ecb);
1199 1.1 thorpej ti->cmds++;
1200 1.18 bouyer scsipi_done(xs);
1201 1.1 thorpej }
1202 1.1 thorpej
1203 1.1 thorpej void
1204 1.1 thorpej ncr53c9x_dequeue(sc, ecb)
1205 1.1 thorpej struct ncr53c9x_softc *sc;
1206 1.1 thorpej struct ncr53c9x_ecb *ecb;
1207 1.1 thorpej {
1208 1.36.2.6 bouyer struct ncr53c9x_tinfo *ti =
1209 1.36.2.6 bouyer &sc->sc_tinfo[ecb->xs->xs_periph->periph_target];
1210 1.36.2.6 bouyer struct ncr53c9x_linfo *li;
1211 1.36.2.6 bouyer int64_t lun = ecb->xs->xs_periph->periph_lun;
1212 1.36.2.6 bouyer
1213 1.36.2.6 bouyer li = TINFO_LUN(ti, lun);
1214 1.36.2.6 bouyer #ifdef DIAGNOSTIC
1215 1.36.2.6 bouyer if (li == NULL || li->lun != lun)
1216 1.36.2.6 bouyer panic("ncr53c9x_dequeue: lun %qx for ecb %p does not exist\n",
1217 1.36.2.6 bouyer (long long) lun, ecb);
1218 1.36.2.6 bouyer #endif
1219 1.36.2.6 bouyer if (li->untagged == ecb) {
1220 1.36.2.6 bouyer li->busy = 0;
1221 1.36.2.6 bouyer li->untagged = NULL;
1222 1.36.2.6 bouyer }
1223 1.36.2.6 bouyer if (ecb->tag[0] && li->queued[ecb->tag[1]] != NULL) {
1224 1.36.2.6 bouyer #ifdef DIAGNOSTIC
1225 1.36.2.6 bouyer if (li->queued[ecb->tag[1]] != NULL &&
1226 1.36.2.6 bouyer (li->queued[ecb->tag[1]] != ecb))
1227 1.36.2.6 bouyer panic("ncr53c9x_dequeue: slot %d for lun %qx has %p "
1228 1.36.2.6 bouyer "instead of ecb %p\n", ecb->tag[1],
1229 1.36.2.6 bouyer (long long) lun,
1230 1.36.2.6 bouyer li->queued[ecb->tag[1]], ecb);
1231 1.36.2.6 bouyer #endif
1232 1.36.2.6 bouyer li->queued[ecb->tag[1]] = NULL;
1233 1.36.2.6 bouyer li->used --;
1234 1.36.2.6 bouyer }
1235 1.1 thorpej
1236 1.36.2.6 bouyer if ((ecb->flags & ECB_READY) != 0) {
1237 1.36.2.6 bouyer ecb->flags &= ~ECB_READY;
1238 1.1 thorpej TAILQ_REMOVE(&sc->ready_list, ecb, chain);
1239 1.1 thorpej }
1240 1.1 thorpej }
1241 1.1 thorpej
1242 1.1 thorpej /*
1243 1.1 thorpej * INTERRUPT/PROTOCOL ENGINE
1244 1.1 thorpej */
1245 1.1 thorpej
1246 1.1 thorpej /*
1247 1.1 thorpej * Schedule an outgoing message by prioritizing it, and asserting
1248 1.1 thorpej * attention on the bus. We can only do this when we are the initiator
1249 1.1 thorpej * else there will be an illegal command interrupt.
1250 1.1 thorpej */
1251 1.1 thorpej #define ncr53c9x_sched_msgout(m) \
1252 1.1 thorpej do { \
1253 1.36.2.6 bouyer NCR_MISC(("ncr53c9x_sched_msgout %x %d", m, __LINE__)); \
1254 1.1 thorpej NCRCMD(sc, NCRCMD_SETATN); \
1255 1.1 thorpej sc->sc_flags |= NCR_ATN; \
1256 1.1 thorpej sc->sc_msgpriq |= (m); \
1257 1.1 thorpej } while (0)
1258 1.1 thorpej
1259 1.1 thorpej int
1260 1.36.2.6 bouyer ncr53c9x_reselect(sc, message, tagtype, tagid)
1261 1.1 thorpej struct ncr53c9x_softc *sc;
1262 1.1 thorpej int message;
1263 1.36.2.6 bouyer int tagtype, tagid;
1264 1.1 thorpej {
1265 1.1 thorpej u_char selid, target, lun;
1266 1.36.2.6 bouyer struct ncr53c9x_ecb *ecb = NULL;
1267 1.1 thorpej struct ncr53c9x_tinfo *ti;
1268 1.36.2.6 bouyer struct ncr53c9x_linfo *li;
1269 1.1 thorpej
1270 1.1 thorpej /*
1271 1.1 thorpej * The SCSI chip made a snapshot of the data bus while the reselection
1272 1.1 thorpej * was being negotiated. This enables us to determine which target did
1273 1.1 thorpej * the reselect.
1274 1.1 thorpej */
1275 1.1 thorpej selid = sc->sc_selid & ~(1 << sc->sc_id);
1276 1.1 thorpej if (selid & (selid - 1)) {
1277 1.1 thorpej printf("%s: reselect with invalid selid %02x;"
1278 1.1 thorpej " sending DEVICE RESET\n", sc->sc_dev.dv_xname, selid);
1279 1.1 thorpej goto reset;
1280 1.1 thorpej }
1281 1.1 thorpej
1282 1.1 thorpej /*
1283 1.1 thorpej * Search wait queue for disconnected cmd
1284 1.1 thorpej * The list should be short, so I haven't bothered with
1285 1.1 thorpej * any more sophisticated structures than a simple
1286 1.1 thorpej * singly linked list.
1287 1.1 thorpej */
1288 1.1 thorpej target = ffs(selid) - 1;
1289 1.1 thorpej lun = message & 0x07;
1290 1.36.2.6 bouyer ti = &sc->sc_tinfo[target];
1291 1.36.2.6 bouyer li = TINFO_LUN(ti, lun);
1292 1.36.2.6 bouyer
1293 1.36.2.6 bouyer /*
1294 1.36.2.6 bouyer * We can get as far as the LUN with the IDENTIFY
1295 1.36.2.6 bouyer * message. Check to see if we're running an
1296 1.36.2.6 bouyer * un-tagged command. Otherwise ack the IDENTIFY
1297 1.36.2.6 bouyer * and wait for a tag message.
1298 1.36.2.6 bouyer */
1299 1.36.2.6 bouyer
1300 1.36.2.6 bouyer if (li != NULL) {
1301 1.36.2.6 bouyer if (li->untagged != NULL && li->busy)
1302 1.36.2.6 bouyer ecb = li->untagged;
1303 1.36.2.6 bouyer else if (tagtype != MSG_SIMPLE_Q_TAG) {
1304 1.36.2.6 bouyer /* Wait for tag to come by */
1305 1.36.2.6 bouyer sc->sc_state = NCR_IDENTIFIED;
1306 1.36.2.6 bouyer return (0);
1307 1.36.2.6 bouyer } else if (tagtype)
1308 1.36.2.6 bouyer ecb = li->queued[tagid];
1309 1.1 thorpej }
1310 1.1 thorpej if (ecb == NULL) {
1311 1.36.2.6 bouyer printf("%s: reselect from target %d lun %d tag %x:%x with no nexus;"
1312 1.36.2.6 bouyer " sending ABORT\n",
1313 1.36.2.6 bouyer sc->sc_dev.dv_xname, target, lun, tagtype, tagid);
1314 1.1 thorpej goto abort;
1315 1.1 thorpej }
1316 1.1 thorpej
1317 1.1 thorpej /* Make this nexus active again. */
1318 1.1 thorpej sc->sc_state = NCR_CONNECTED;
1319 1.1 thorpej sc->sc_nexus = ecb;
1320 1.1 thorpej ncr53c9x_setsync(sc, ti);
1321 1.1 thorpej
1322 1.1 thorpej if (ecb->flags & ECB_RESET)
1323 1.1 thorpej ncr53c9x_sched_msgout(SEND_DEV_RESET);
1324 1.1 thorpej else if (ecb->flags & ECB_ABORT)
1325 1.1 thorpej ncr53c9x_sched_msgout(SEND_ABORT);
1326 1.1 thorpej
1327 1.1 thorpej /* Do an implicit RESTORE POINTERS. */
1328 1.1 thorpej sc->sc_dp = ecb->daddr;
1329 1.1 thorpej sc->sc_dleft = ecb->dleft;
1330 1.1 thorpej
1331 1.1 thorpej return (0);
1332 1.1 thorpej
1333 1.1 thorpej reset:
1334 1.1 thorpej ncr53c9x_sched_msgout(SEND_DEV_RESET);
1335 1.1 thorpej return (1);
1336 1.1 thorpej
1337 1.1 thorpej abort:
1338 1.1 thorpej ncr53c9x_sched_msgout(SEND_ABORT);
1339 1.1 thorpej return (1);
1340 1.1 thorpej }
1341 1.1 thorpej
1342 1.1 thorpej #define IS1BYTEMSG(m) (((m) != 1 && (m) < 0x20) || (m) & 0x80)
1343 1.1 thorpej #define IS2BYTEMSG(m) (((m) & 0xf0) == 0x20)
1344 1.1 thorpej #define ISEXTMSG(m) ((m) == 1)
1345 1.1 thorpej
1346 1.1 thorpej /*
1347 1.1 thorpej * Get an incoming message as initiator.
1348 1.1 thorpej *
1349 1.1 thorpej * The SCSI bus must already be in MESSAGE_IN_PHASE and there is a
1350 1.1 thorpej * byte in the FIFO
1351 1.1 thorpej */
1352 1.1 thorpej void
1353 1.1 thorpej ncr53c9x_msgin(sc)
1354 1.36.2.4 bouyer struct ncr53c9x_softc *sc;
1355 1.1 thorpej {
1356 1.36.2.4 bouyer int v;
1357 1.1 thorpej
1358 1.36.2.6 bouyer v = (NCR_READ_REG(sc, NCR_FFLAG) & NCRFIFO_FF);
1359 1.36.2.6 bouyer NCR_TRACE(("[ncr53c9x_msgin(curmsglen:%ld fifo:%d)] ",
1360 1.36.2.6 bouyer (long)sc->sc_imlen, v));
1361 1.1 thorpej
1362 1.36.2.6 bouyer if (v == 0) {
1363 1.1 thorpej printf("%s: msgin: no msg byte available\n",
1364 1.1 thorpej sc->sc_dev.dv_xname);
1365 1.1 thorpej return;
1366 1.1 thorpej }
1367 1.1 thorpej
1368 1.1 thorpej /*
1369 1.1 thorpej * Prepare for a new message. A message should (according
1370 1.1 thorpej * to the SCSI standard) be transmitted in one single
1371 1.1 thorpej * MESSAGE_IN_PHASE. If we have been in some other phase,
1372 1.1 thorpej * then this is a new message.
1373 1.1 thorpej */
1374 1.1 thorpej if (sc->sc_prevphase != MESSAGE_IN_PHASE) {
1375 1.1 thorpej sc->sc_flags &= ~NCR_DROP_MSGI;
1376 1.1 thorpej sc->sc_imlen = 0;
1377 1.1 thorpej }
1378 1.1 thorpej
1379 1.1 thorpej v = NCR_READ_REG(sc, NCR_FIFO);
1380 1.1 thorpej NCR_MISC(("<msgbyte:0x%02x>", v));
1381 1.1 thorpej
1382 1.1 thorpej #if 0
1383 1.1 thorpej if (sc->sc_state == NCR_RESELECTED && sc->sc_imlen == 0) {
1384 1.1 thorpej /*
1385 1.1 thorpej * Which target is reselecting us? (The ID bit really)
1386 1.1 thorpej */
1387 1.1 thorpej sc->sc_selid = v;
1388 1.1 thorpej NCR_MISC(("selid=0x%2x ", sc->sc_selid));
1389 1.1 thorpej return;
1390 1.1 thorpej }
1391 1.1 thorpej #endif
1392 1.1 thorpej
1393 1.1 thorpej sc->sc_imess[sc->sc_imlen] = v;
1394 1.1 thorpej
1395 1.1 thorpej /*
1396 1.1 thorpej * If we're going to reject the message, don't bother storing
1397 1.1 thorpej * the incoming bytes. But still, we need to ACK them.
1398 1.1 thorpej */
1399 1.1 thorpej
1400 1.36.2.6 bouyer if ((sc->sc_flags & NCR_DROP_MSGI) != 0) {
1401 1.1 thorpej NCRCMD(sc, NCRCMD_MSGOK);
1402 1.1 thorpej printf("<dropping msg byte %x>",
1403 1.1 thorpej sc->sc_imess[sc->sc_imlen]);
1404 1.1 thorpej return;
1405 1.1 thorpej }
1406 1.1 thorpej
1407 1.1 thorpej if (sc->sc_imlen >= NCR_MAX_MSG_LEN) {
1408 1.1 thorpej ncr53c9x_sched_msgout(SEND_REJECT);
1409 1.1 thorpej sc->sc_flags |= NCR_DROP_MSGI;
1410 1.1 thorpej } else {
1411 1.1 thorpej sc->sc_imlen++;
1412 1.1 thorpej /*
1413 1.1 thorpej * This testing is suboptimal, but most
1414 1.1 thorpej * messages will be of the one byte variety, so
1415 1.1 thorpej * it should not effect performance
1416 1.1 thorpej * significantly.
1417 1.1 thorpej */
1418 1.1 thorpej if (sc->sc_imlen == 1 && IS1BYTEMSG(sc->sc_imess[0]))
1419 1.1 thorpej goto gotit;
1420 1.1 thorpej if (sc->sc_imlen == 2 && IS2BYTEMSG(sc->sc_imess[0]))
1421 1.1 thorpej goto gotit;
1422 1.1 thorpej if (sc->sc_imlen >= 3 && ISEXTMSG(sc->sc_imess[0]) &&
1423 1.1 thorpej sc->sc_imlen == sc->sc_imess[1] + 2)
1424 1.1 thorpej goto gotit;
1425 1.1 thorpej }
1426 1.1 thorpej /* Ack what we have so far */
1427 1.1 thorpej NCRCMD(sc, NCRCMD_MSGOK);
1428 1.1 thorpej return;
1429 1.1 thorpej
1430 1.1 thorpej gotit:
1431 1.1 thorpej NCR_MSGS(("gotmsg(%x)", sc->sc_imess[0]));
1432 1.1 thorpej /*
1433 1.1 thorpej * Now we should have a complete message (1 byte, 2 byte
1434 1.1 thorpej * and moderately long extended messages). We only handle
1435 1.1 thorpej * extended messages which total length is shorter than
1436 1.1 thorpej * NCR_MAX_MSG_LEN. Longer messages will be amputated.
1437 1.1 thorpej */
1438 1.1 thorpej switch (sc->sc_state) {
1439 1.1 thorpej struct ncr53c9x_ecb *ecb;
1440 1.1 thorpej struct ncr53c9x_tinfo *ti;
1441 1.1 thorpej
1442 1.1 thorpej case NCR_CONNECTED:
1443 1.1 thorpej ecb = sc->sc_nexus;
1444 1.36.2.1 thorpej ti = &sc->sc_tinfo[ecb->xs->xs_periph->periph_target];
1445 1.1 thorpej
1446 1.1 thorpej switch (sc->sc_imess[0]) {
1447 1.1 thorpej case MSG_CMDCOMPLETE:
1448 1.1 thorpej NCR_MSGS(("cmdcomplete "));
1449 1.1 thorpej if (sc->sc_dleft < 0) {
1450 1.36.2.1 thorpej scsipi_printaddr(ecb->xs->xs_periph);
1451 1.30 pk printf("got %ld extra bytes\n",
1452 1.31 pk -(long)sc->sc_dleft);
1453 1.1 thorpej sc->sc_dleft = 0;
1454 1.1 thorpej }
1455 1.13 pk ecb->dleft = (ecb->flags & ECB_TENTATIVE_DONE)
1456 1.13 pk ? 0
1457 1.13 pk : sc->sc_dleft;
1458 1.13 pk if ((ecb->flags & ECB_SENSE) == 0)
1459 1.13 pk ecb->xs->resid = ecb->dleft;
1460 1.1 thorpej sc->sc_state = NCR_CMDCOMPLETE;
1461 1.1 thorpej break;
1462 1.1 thorpej
1463 1.1 thorpej case MSG_MESSAGE_REJECT:
1464 1.23 pk NCR_MSGS(("msg reject (msgout=%x) ", sc->sc_msgout));
1465 1.1 thorpej switch (sc->sc_msgout) {
1466 1.1 thorpej case SEND_SDTR:
1467 1.1 thorpej sc->sc_flags &= ~NCR_SYNCHNEGO;
1468 1.1 thorpej ti->flags &= ~(T_NEGOTIATE | T_SYNCMODE);
1469 1.1 thorpej ncr53c9x_setsync(sc, ti);
1470 1.36.2.10 bouyer ncr53c9x_update_xfer_mode(sc,
1471 1.36.2.10 bouyer ecb->xs->xs_periph->periph_target);
1472 1.1 thorpej break;
1473 1.1 thorpej case SEND_INIT_DET_ERR:
1474 1.1 thorpej goto abort;
1475 1.1 thorpej }
1476 1.1 thorpej break;
1477 1.1 thorpej
1478 1.1 thorpej case MSG_NOOP:
1479 1.1 thorpej NCR_MSGS(("noop "));
1480 1.1 thorpej break;
1481 1.1 thorpej
1482 1.36.2.6 bouyer case MSG_HEAD_OF_Q_TAG:
1483 1.36.2.6 bouyer case MSG_SIMPLE_Q_TAG:
1484 1.36.2.6 bouyer case MSG_ORDERED_Q_TAG:
1485 1.36.2.6 bouyer NCR_MSGS(("TAG %x:%x", sc->sc_imess[0], sc->sc_imess[1]));
1486 1.36.2.6 bouyer break;
1487 1.36.2.6 bouyer
1488 1.1 thorpej case MSG_DISCONNECT:
1489 1.1 thorpej NCR_MSGS(("disconnect "));
1490 1.1 thorpej ti->dconns++;
1491 1.1 thorpej sc->sc_state = NCR_DISCONNECT;
1492 1.8 pk
1493 1.13 pk /*
1494 1.13 pk * Mark the fact that all bytes have moved. The
1495 1.13 pk * target may not bother to do a SAVE POINTERS
1496 1.13 pk * at this stage. This flag will set the residual
1497 1.13 pk * count to zero on MSG COMPLETE.
1498 1.13 pk */
1499 1.13 pk if (sc->sc_dleft == 0)
1500 1.13 pk ecb->flags |= ECB_TENTATIVE_DONE;
1501 1.13 pk
1502 1.13 pk break;
1503 1.1 thorpej
1504 1.1 thorpej case MSG_SAVEDATAPOINTER:
1505 1.1 thorpej NCR_MSGS(("save datapointer "));
1506 1.1 thorpej ecb->daddr = sc->sc_dp;
1507 1.1 thorpej ecb->dleft = sc->sc_dleft;
1508 1.1 thorpej break;
1509 1.1 thorpej
1510 1.1 thorpej case MSG_RESTOREPOINTERS:
1511 1.1 thorpej NCR_MSGS(("restore datapointer "));
1512 1.1 thorpej sc->sc_dp = ecb->daddr;
1513 1.1 thorpej sc->sc_dleft = ecb->dleft;
1514 1.1 thorpej break;
1515 1.1 thorpej
1516 1.1 thorpej case MSG_EXTENDED:
1517 1.1 thorpej NCR_MSGS(("extended(%x) ", sc->sc_imess[2]));
1518 1.1 thorpej switch (sc->sc_imess[2]) {
1519 1.1 thorpej case MSG_EXT_SDTR:
1520 1.1 thorpej NCR_MSGS(("SDTR period %d, offset %d ",
1521 1.1 thorpej sc->sc_imess[3], sc->sc_imess[4]));
1522 1.1 thorpej if (sc->sc_imess[1] != 3)
1523 1.1 thorpej goto reject;
1524 1.1 thorpej ti->period = sc->sc_imess[3];
1525 1.1 thorpej ti->offset = sc->sc_imess[4];
1526 1.1 thorpej ti->flags &= ~T_NEGOTIATE;
1527 1.1 thorpej if (sc->sc_minsync == 0 ||
1528 1.1 thorpej ti->offset == 0 ||
1529 1.1 thorpej ti->period > 124) {
1530 1.36.2.1 thorpej #if 0
1531 1.29 pk #ifdef NCR53C9X_DEBUG
1532 1.36.2.1 thorpej scsipi_printaddr(ecb->xs->xs_periph);
1533 1.29 pk printf("async mode\n");
1534 1.29 pk #endif
1535 1.36.2.1 thorpej #endif
1536 1.36.2.10 bouyer ti->flags &= ~T_SYNCMODE;
1537 1.36.2.6 bouyer if ((sc->sc_flags&NCR_SYNCHNEGO) == 0) {
1538 1.1 thorpej /*
1539 1.1 thorpej * target initiated negotiation
1540 1.1 thorpej */
1541 1.1 thorpej ti->offset = 0;
1542 1.1 thorpej ncr53c9x_sched_msgout(
1543 1.1 thorpej SEND_SDTR);
1544 1.1 thorpej }
1545 1.1 thorpej } else {
1546 1.36.2.1 thorpej #if 0
1547 1.1 thorpej int r = 250/ti->period;
1548 1.1 thorpej int s = (100*250)/ti->period - 100*r;
1549 1.36.2.1 thorpej #endif
1550 1.1 thorpej int p;
1551 1.1 thorpej
1552 1.1 thorpej p = ncr53c9x_stp2cpb(sc, ti->period);
1553 1.1 thorpej ti->period = ncr53c9x_cpb2stp(sc, p);
1554 1.36.2.1 thorpej #if 0
1555 1.1 thorpej #ifdef NCR53C9X_DEBUG
1556 1.36.2.1 thorpej scsipi_printaddr(ecb->xs->xs_periph);
1557 1.36.2.4 bouyer printf("max sync rate %d.%02dMB/s\n",
1558 1.1 thorpej r, s);
1559 1.1 thorpej #endif
1560 1.36.2.1 thorpej #endif
1561 1.22 pk if ((sc->sc_flags&NCR_SYNCHNEGO) == 0) {
1562 1.1 thorpej /*
1563 1.1 thorpej * target initiated negotiation
1564 1.1 thorpej */
1565 1.1 thorpej if (ti->period <
1566 1.1 thorpej sc->sc_minsync)
1567 1.1 thorpej ti->period =
1568 1.1 thorpej sc->sc_minsync;
1569 1.1 thorpej if (ti->offset > 15)
1570 1.1 thorpej ti->offset = 15;
1571 1.1 thorpej ti->flags &= ~T_SYNCMODE;
1572 1.1 thorpej ncr53c9x_sched_msgout(
1573 1.1 thorpej SEND_SDTR);
1574 1.1 thorpej } else {
1575 1.1 thorpej /* we are sync */
1576 1.1 thorpej ti->flags |= T_SYNCMODE;
1577 1.1 thorpej }
1578 1.1 thorpej }
1579 1.36.2.10 bouyer ncr53c9x_update_xfer_mode(sc,
1580 1.36.2.10 bouyer ecb->xs->xs_periph->periph_target);
1581 1.1 thorpej sc->sc_flags &= ~NCR_SYNCHNEGO;
1582 1.1 thorpej ncr53c9x_setsync(sc, ti);
1583 1.1 thorpej break;
1584 1.1 thorpej
1585 1.1 thorpej default:
1586 1.36.2.1 thorpej scsipi_printaddr(ecb->xs->xs_periph);
1587 1.30 pk printf("unrecognized MESSAGE EXTENDED;"
1588 1.30 pk " sending REJECT\n");
1589 1.1 thorpej goto reject;
1590 1.1 thorpej }
1591 1.1 thorpej break;
1592 1.1 thorpej
1593 1.1 thorpej default:
1594 1.1 thorpej NCR_MSGS(("ident "));
1595 1.36.2.1 thorpej scsipi_printaddr(ecb->xs->xs_periph);
1596 1.30 pk printf("unrecognized MESSAGE; sending REJECT\n");
1597 1.1 thorpej reject:
1598 1.1 thorpej ncr53c9x_sched_msgout(SEND_REJECT);
1599 1.1 thorpej break;
1600 1.1 thorpej }
1601 1.1 thorpej break;
1602 1.1 thorpej
1603 1.1 thorpej case NCR_RESELECTED:
1604 1.36.2.6 bouyer case NCR_IDENTIFIED:
1605 1.36.2.6 bouyer if (MSG_ISIDENTIFY(sc->sc_imess[0])) {
1606 1.36.2.6 bouyer sc->sc_msgify = sc->sc_imess[0];
1607 1.36.2.6 bouyer } else if (sc->sc_imess[0] == MSG_SIMPLE_Q_TAG) {
1608 1.36.2.6 bouyer if (sc->sc_msgify == 0) {
1609 1.36.2.6 bouyer printf("%s: TAG reselect without IDENTIFY;"
1610 1.36.2.6 bouyer " MSG %x;"
1611 1.36.2.6 bouyer " sending DEVICE RESET\n",
1612 1.36.2.6 bouyer sc->sc_dev.dv_xname,
1613 1.36.2.6 bouyer sc->sc_imess[0]);
1614 1.36.2.6 bouyer goto reset;
1615 1.36.2.6 bouyer }
1616 1.36.2.6 bouyer } else {
1617 1.31 pk printf("%s: reselect without IDENTIFY;"
1618 1.36.2.6 bouyer " MSG %x;"
1619 1.31 pk " sending DEVICE RESET\n",
1620 1.36.2.6 bouyer sc->sc_dev.dv_xname,
1621 1.36.2.6 bouyer sc->sc_imess[0]);
1622 1.1 thorpej goto reset;
1623 1.1 thorpej }
1624 1.1 thorpej
1625 1.36.2.6 bouyer (void) ncr53c9x_reselect(sc, sc->sc_msgify,
1626 1.36.2.6 bouyer sc->sc_imess[0],
1627 1.36.2.6 bouyer sc->sc_imess[1]);
1628 1.1 thorpej break;
1629 1.1 thorpej
1630 1.1 thorpej default:
1631 1.31 pk printf("%s: unexpected MESSAGE IN; sending DEVICE RESET\n",
1632 1.31 pk sc->sc_dev.dv_xname);
1633 1.1 thorpej reset:
1634 1.1 thorpej ncr53c9x_sched_msgout(SEND_DEV_RESET);
1635 1.1 thorpej break;
1636 1.1 thorpej
1637 1.1 thorpej abort:
1638 1.1 thorpej ncr53c9x_sched_msgout(SEND_ABORT);
1639 1.1 thorpej break;
1640 1.1 thorpej }
1641 1.1 thorpej
1642 1.1 thorpej /* Ack last message byte */
1643 1.1 thorpej NCRCMD(sc, NCRCMD_MSGOK);
1644 1.1 thorpej
1645 1.1 thorpej /* Done, reset message pointer. */
1646 1.1 thorpej sc->sc_flags &= ~NCR_DROP_MSGI;
1647 1.1 thorpej sc->sc_imlen = 0;
1648 1.1 thorpej }
1649 1.1 thorpej
1650 1.1 thorpej
1651 1.1 thorpej /*
1652 1.1 thorpej * Send the highest priority, scheduled message
1653 1.1 thorpej */
1654 1.1 thorpej void
1655 1.1 thorpej ncr53c9x_msgout(sc)
1656 1.36.2.4 bouyer struct ncr53c9x_softc *sc;
1657 1.1 thorpej {
1658 1.1 thorpej struct ncr53c9x_tinfo *ti;
1659 1.1 thorpej struct ncr53c9x_ecb *ecb;
1660 1.1 thorpej size_t size;
1661 1.1 thorpej
1662 1.1 thorpej NCR_TRACE(("[ncr53c9x_msgout(priq:%x, prevphase:%x)]",
1663 1.1 thorpej sc->sc_msgpriq, sc->sc_prevphase));
1664 1.1 thorpej
1665 1.22 pk /*
1666 1.22 pk * XXX - the NCR_ATN flag is not in sync with the actual ATN
1667 1.22 pk * condition on the SCSI bus. The 53c9x chip
1668 1.22 pk * automatically turns off ATN before sending the
1669 1.22 pk * message byte. (see also the comment below in the
1670 1.22 pk * default case when picking out a message to send)
1671 1.22 pk */
1672 1.1 thorpej if (sc->sc_flags & NCR_ATN) {
1673 1.1 thorpej if (sc->sc_prevphase != MESSAGE_OUT_PHASE) {
1674 1.1 thorpej new:
1675 1.1 thorpej NCRCMD(sc, NCRCMD_FLUSH);
1676 1.1 thorpej DELAY(1);
1677 1.1 thorpej sc->sc_msgoutq = 0;
1678 1.1 thorpej sc->sc_omlen = 0;
1679 1.1 thorpej }
1680 1.1 thorpej } else {
1681 1.1 thorpej if (sc->sc_prevphase == MESSAGE_OUT_PHASE) {
1682 1.1 thorpej ncr53c9x_sched_msgout(sc->sc_msgoutq);
1683 1.1 thorpej goto new;
1684 1.1 thorpej } else {
1685 1.1 thorpej printf("%s at line %d: unexpected MESSAGE OUT phase\n",
1686 1.1 thorpej sc->sc_dev.dv_xname, __LINE__);
1687 1.1 thorpej }
1688 1.1 thorpej }
1689 1.1 thorpej
1690 1.1 thorpej if (sc->sc_omlen == 0) {
1691 1.1 thorpej /* Pick up highest priority message */
1692 1.1 thorpej sc->sc_msgout = sc->sc_msgpriq & -sc->sc_msgpriq;
1693 1.1 thorpej sc->sc_msgoutq |= sc->sc_msgout;
1694 1.1 thorpej sc->sc_msgpriq &= ~sc->sc_msgout;
1695 1.1 thorpej sc->sc_omlen = 1; /* "Default" message len */
1696 1.1 thorpej switch (sc->sc_msgout) {
1697 1.1 thorpej case SEND_SDTR:
1698 1.1 thorpej ecb = sc->sc_nexus;
1699 1.36.2.1 thorpej ti = &sc->sc_tinfo[ecb->xs->xs_periph->periph_target];
1700 1.1 thorpej sc->sc_omess[0] = MSG_EXTENDED;
1701 1.1 thorpej sc->sc_omess[1] = 3;
1702 1.1 thorpej sc->sc_omess[2] = MSG_EXT_SDTR;
1703 1.1 thorpej sc->sc_omess[3] = ti->period;
1704 1.1 thorpej sc->sc_omess[4] = ti->offset;
1705 1.1 thorpej sc->sc_omlen = 5;
1706 1.1 thorpej if ((sc->sc_flags & NCR_SYNCHNEGO) == 0) {
1707 1.1 thorpej ti->flags |= T_SYNCMODE;
1708 1.1 thorpej ncr53c9x_setsync(sc, ti);
1709 1.1 thorpej }
1710 1.1 thorpej break;
1711 1.36.2.6 bouyer case SEND_IDENTIFY:
1712 1.36.2.6 bouyer if (sc->sc_state != NCR_CONNECTED) {
1713 1.36.2.6 bouyer printf("%s at line %d: no nexus\n",
1714 1.36.2.6 bouyer sc->sc_dev.dv_xname, __LINE__);
1715 1.36.2.6 bouyer }
1716 1.36.2.6 bouyer ecb = sc->sc_nexus;
1717 1.36.2.6 bouyer sc->sc_omess[0] =
1718 1.36.2.6 bouyer MSG_IDENTIFY(ecb->xs->xs_periph->periph_lun, 0);
1719 1.36.2.6 bouyer break;
1720 1.36.2.6 bouyer case SEND_TAG:
1721 1.1 thorpej if (sc->sc_state != NCR_CONNECTED) {
1722 1.1 thorpej printf("%s at line %d: no nexus\n",
1723 1.1 thorpej sc->sc_dev.dv_xname, __LINE__);
1724 1.1 thorpej }
1725 1.1 thorpej ecb = sc->sc_nexus;
1726 1.36.2.6 bouyer sc->sc_omess[0] = ecb->tag[0];
1727 1.36.2.6 bouyer sc->sc_omess[1] = ecb->tag[1];
1728 1.36.2.6 bouyer sc->sc_omlen = 2;
1729 1.1 thorpej break;
1730 1.1 thorpej case SEND_DEV_RESET:
1731 1.1 thorpej sc->sc_flags |= NCR_ABORTING;
1732 1.1 thorpej sc->sc_omess[0] = MSG_BUS_DEV_RESET;
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 ti->flags &= ~T_SYNCMODE;
1736 1.36.2.10 bouyer ncr53c9x_update_xfer_mode(sc,
1737 1.36.2.10 bouyer ecb->xs->xs_periph->periph_target);
1738 1.36.2.5 bouyer if ((ti->flags & T_SYNCHOFF) == 0)
1739 1.36.2.5 bouyer /* We can re-start sync negotiation */
1740 1.36.2.5 bouyer ti->flags |= T_NEGOTIATE;
1741 1.1 thorpej break;
1742 1.1 thorpej case SEND_PARITY_ERROR:
1743 1.1 thorpej sc->sc_omess[0] = MSG_PARITY_ERROR;
1744 1.1 thorpej break;
1745 1.1 thorpej case SEND_ABORT:
1746 1.1 thorpej sc->sc_flags |= NCR_ABORTING;
1747 1.1 thorpej sc->sc_omess[0] = MSG_ABORT;
1748 1.1 thorpej break;
1749 1.1 thorpej case SEND_INIT_DET_ERR:
1750 1.1 thorpej sc->sc_omess[0] = MSG_INITIATOR_DET_ERR;
1751 1.1 thorpej break;
1752 1.1 thorpej case SEND_REJECT:
1753 1.1 thorpej sc->sc_omess[0] = MSG_MESSAGE_REJECT;
1754 1.1 thorpej break;
1755 1.1 thorpej default:
1756 1.22 pk /*
1757 1.22 pk * We normally do not get here, since the chip
1758 1.22 pk * automatically turns off ATN before the last
1759 1.22 pk * byte of a message is sent to the target.
1760 1.22 pk * However, if the target rejects our (multi-byte)
1761 1.22 pk * message early by switching to MSG IN phase
1762 1.22 pk * ATN remains on, so the target may return to
1763 1.22 pk * MSG OUT phase. If there are no scheduled messages
1764 1.22 pk * left we send a NO-OP.
1765 1.22 pk *
1766 1.22 pk * XXX - Note that this leaves no useful purpose for
1767 1.22 pk * the NCR_ATN flag.
1768 1.22 pk */
1769 1.1 thorpej sc->sc_flags &= ~NCR_ATN;
1770 1.1 thorpej sc->sc_omess[0] = MSG_NOOP;
1771 1.1 thorpej break;
1772 1.1 thorpej }
1773 1.1 thorpej sc->sc_omp = sc->sc_omess;
1774 1.1 thorpej }
1775 1.1 thorpej
1776 1.36.2.6 bouyer #ifdef DEBUG
1777 1.36.2.6 bouyer {
1778 1.36.2.6 bouyer int i;
1779 1.36.2.6 bouyer
1780 1.36.2.6 bouyer for (i = 0; i < sc->sc_omlen; i++)
1781 1.36.2.6 bouyer NCR_MISC(("<msgbyte:0x%02x>", sc->sc_omess[i]));
1782 1.36.2.6 bouyer }
1783 1.36.2.6 bouyer #endif
1784 1.1 thorpej /* (re)send the message */
1785 1.1 thorpej size = min(sc->sc_omlen, sc->sc_maxxfer);
1786 1.1 thorpej NCRDMA_SETUP(sc, &sc->sc_omp, &sc->sc_omlen, 0, &size);
1787 1.1 thorpej /* Program the SCSI counter */
1788 1.1 thorpej NCR_WRITE_REG(sc, NCR_TCL, size);
1789 1.1 thorpej NCR_WRITE_REG(sc, NCR_TCM, size >> 8);
1790 1.1 thorpej if (sc->sc_cfg2 & NCRCFG2_FE) {
1791 1.1 thorpej NCR_WRITE_REG(sc, NCR_TCH, size >> 16);
1792 1.1 thorpej }
1793 1.22 pk /* Load the count in and start the message-out transfer */
1794 1.1 thorpej NCRCMD(sc, NCRCMD_NOP|NCRCMD_DMA);
1795 1.1 thorpej NCRCMD(sc, NCRCMD_TRANS|NCRCMD_DMA);
1796 1.1 thorpej NCRDMA_GO(sc);
1797 1.1 thorpej }
1798 1.1 thorpej
1799 1.1 thorpej /*
1800 1.1 thorpej * This is the most critical part of the driver, and has to know
1801 1.1 thorpej * how to deal with *all* error conditions and phases from the SCSI
1802 1.1 thorpej * bus. If there are no errors and the DMA was active, then call the
1803 1.1 thorpej * DMA pseudo-interrupt handler. If this returns 1, then that was it
1804 1.1 thorpej * and we can return from here without further processing.
1805 1.1 thorpej *
1806 1.1 thorpej * Most of this needs verifying.
1807 1.1 thorpej */
1808 1.1 thorpej int
1809 1.36.2.4 bouyer ncr53c9x_intr(arg)
1810 1.36.2.4 bouyer void *arg;
1811 1.1 thorpej {
1812 1.36.2.4 bouyer struct ncr53c9x_softc *sc = arg;
1813 1.36.2.4 bouyer struct ncr53c9x_ecb *ecb;
1814 1.36.2.4 bouyer struct scsipi_periph *periph;
1815 1.1 thorpej struct ncr53c9x_tinfo *ti;
1816 1.1 thorpej size_t size;
1817 1.5 pk int nfifo;
1818 1.1 thorpej
1819 1.10 pk NCR_TRACE(("[ncr53c9x_intr] "));
1820 1.1 thorpej
1821 1.25 pk if (!NCRDMA_ISINTR(sc))
1822 1.25 pk return (0);
1823 1.25 pk
1824 1.25 pk again:
1825 1.25 pk /* and what do the registers say... */
1826 1.25 pk ncr53c9x_readregs(sc);
1827 1.25 pk
1828 1.25 pk sc->sc_intrcnt.ev_count++;
1829 1.25 pk
1830 1.1 thorpej /*
1831 1.25 pk * At the moment, only a SCSI Bus Reset or Illegal
1832 1.25 pk * Command are classed as errors. A disconnect is a
1833 1.25 pk * valid condition, and we let the code check is the
1834 1.25 pk * "NCR_BUSFREE_OK" flag was set before declaring it
1835 1.25 pk * and error.
1836 1.1 thorpej *
1837 1.25 pk * Also, the status register tells us about "Gross
1838 1.25 pk * Errors" and "Parity errors". Only the Gross Error
1839 1.25 pk * is really bad, and the parity errors are dealt
1840 1.25 pk * with later
1841 1.1 thorpej *
1842 1.25 pk * TODO
1843 1.25 pk * If there are too many parity error, go to slow
1844 1.25 pk * cable mode ?
1845 1.1 thorpej */
1846 1.25 pk
1847 1.25 pk /* SCSI Reset */
1848 1.36.2.6 bouyer if ((sc->sc_espintr & NCRINTR_SBR) != 0) {
1849 1.36.2.6 bouyer if ((NCR_READ_REG(sc, NCR_FFLAG) & NCRFIFO_FF) != 0) {
1850 1.25 pk NCRCMD(sc, NCRCMD_FLUSH);
1851 1.25 pk DELAY(1);
1852 1.25 pk }
1853 1.25 pk if (sc->sc_state != NCR_SBR) {
1854 1.25 pk printf("%s: SCSI bus reset\n",
1855 1.25 pk sc->sc_dev.dv_xname);
1856 1.25 pk ncr53c9x_init(sc, 0); /* Restart everything */
1857 1.25 pk return (1);
1858 1.25 pk }
1859 1.1 thorpej #if 0
1860 1.25 pk /*XXX*/ printf("<expected bus reset: "
1861 1.25 pk "[intr %x, stat %x, step %d]>\n",
1862 1.25 pk sc->sc_espintr, sc->sc_espstat,
1863 1.25 pk sc->sc_espstep);
1864 1.1 thorpej #endif
1865 1.36.2.6 bouyer if (sc->sc_nexus != NULL)
1866 1.25 pk panic("%s: nexus in reset state",
1867 1.25 pk sc->sc_dev.dv_xname);
1868 1.25 pk goto sched;
1869 1.25 pk }
1870 1.1 thorpej
1871 1.25 pk ecb = sc->sc_nexus;
1872 1.1 thorpej
1873 1.25 pk #define NCRINTR_ERR (NCRINTR_SBR|NCRINTR_ILL)
1874 1.25 pk if (sc->sc_espintr & NCRINTR_ERR ||
1875 1.25 pk sc->sc_espstat & NCRSTAT_GE) {
1876 1.1 thorpej
1877 1.36.2.6 bouyer if ((sc->sc_espstat & NCRSTAT_GE) != 0) {
1878 1.25 pk /* Gross Error; no target ? */
1879 1.1 thorpej if (NCR_READ_REG(sc, NCR_FFLAG) & NCRFIFO_FF) {
1880 1.1 thorpej NCRCMD(sc, NCRCMD_FLUSH);
1881 1.1 thorpej DELAY(1);
1882 1.1 thorpej }
1883 1.25 pk if (sc->sc_state == NCR_CONNECTED ||
1884 1.25 pk sc->sc_state == NCR_SELECTING) {
1885 1.25 pk ecb->xs->error = XS_TIMEOUT;
1886 1.25 pk ncr53c9x_done(sc, ecb);
1887 1.1 thorpej }
1888 1.25 pk return (1);
1889 1.1 thorpej }
1890 1.1 thorpej
1891 1.36.2.6 bouyer if ((sc->sc_espintr & NCRINTR_ILL) != 0) {
1892 1.36.2.6 bouyer if ((sc->sc_flags & NCR_EXPECT_ILLCMD) != 0) {
1893 1.25 pk /*
1894 1.25 pk * Eat away "Illegal command" interrupt
1895 1.25 pk * on a ESP100 caused by a re-selection
1896 1.25 pk * while we were trying to select
1897 1.25 pk * another target.
1898 1.25 pk */
1899 1.19 pk #ifdef DEBUG
1900 1.25 pk printf("%s: ESP100 work-around activated\n",
1901 1.25 pk sc->sc_dev.dv_xname);
1902 1.19 pk #endif
1903 1.25 pk sc->sc_flags &= ~NCR_EXPECT_ILLCMD;
1904 1.25 pk return (1);
1905 1.25 pk }
1906 1.25 pk /* illegal command, out of sync ? */
1907 1.25 pk printf("%s: illegal command: 0x%x "
1908 1.25 pk "(state %d, phase %x, prevphase %x)\n",
1909 1.25 pk sc->sc_dev.dv_xname, sc->sc_lastcmd,
1910 1.25 pk sc->sc_state, sc->sc_phase,
1911 1.25 pk sc->sc_prevphase);
1912 1.25 pk if (NCR_READ_REG(sc, NCR_FFLAG) & NCRFIFO_FF) {
1913 1.25 pk NCRCMD(sc, NCRCMD_FLUSH);
1914 1.25 pk DELAY(1);
1915 1.1 thorpej }
1916 1.25 pk ncr53c9x_init(sc, 1); /* Restart everything */
1917 1.25 pk return (1);
1918 1.1 thorpej }
1919 1.25 pk }
1920 1.25 pk sc->sc_flags &= ~NCR_EXPECT_ILLCMD;
1921 1.1 thorpej
1922 1.25 pk /*
1923 1.25 pk * Call if DMA is active.
1924 1.25 pk *
1925 1.25 pk * If DMA_INTR returns true, then maybe go 'round the loop
1926 1.25 pk * again in case there is no more DMA queued, but a phase
1927 1.25 pk * change is expected.
1928 1.25 pk */
1929 1.25 pk if (NCRDMA_ISACTIVE(sc)) {
1930 1.25 pk int r = NCRDMA_INTR(sc);
1931 1.25 pk if (r == -1) {
1932 1.25 pk printf("%s: DMA error; resetting\n",
1933 1.25 pk sc->sc_dev.dv_xname);
1934 1.25 pk ncr53c9x_init(sc, 1);
1935 1.25 pk }
1936 1.25 pk /* If DMA active here, then go back to work... */
1937 1.25 pk if (NCRDMA_ISACTIVE(sc))
1938 1.25 pk return (1);
1939 1.1 thorpej
1940 1.25 pk if ((sc->sc_espstat & NCRSTAT_TC) == 0) {
1941 1.25 pk /*
1942 1.25 pk * DMA not completed. If we can not find a
1943 1.25 pk * acceptable explanation, print a diagnostic.
1944 1.25 pk */
1945 1.25 pk if (sc->sc_state == NCR_SELECTING)
1946 1.25 pk /*
1947 1.25 pk * This can happen if we are reselected
1948 1.25 pk * while using DMA to select a target.
1949 1.25 pk */
1950 1.25 pk /*void*/;
1951 1.25 pk else if (sc->sc_prevphase == MESSAGE_OUT_PHASE) {
1952 1.25 pk /*
1953 1.25 pk * Our (multi-byte) message (eg SDTR) was
1954 1.25 pk * interrupted by the target to send
1955 1.25 pk * a MSG REJECT.
1956 1.25 pk * Print diagnostic if current phase
1957 1.25 pk * is not MESSAGE IN.
1958 1.25 pk */
1959 1.25 pk if (sc->sc_phase != MESSAGE_IN_PHASE)
1960 1.25 pk printf("%s: !TC on MSG OUT"
1961 1.25 pk " [intr %x, stat %x, step %d]"
1962 1.34 thorpej " prevphase %x, resid %lx\n",
1963 1.25 pk sc->sc_dev.dv_xname,
1964 1.25 pk sc->sc_espintr,
1965 1.25 pk sc->sc_espstat,
1966 1.25 pk sc->sc_espstep,
1967 1.25 pk sc->sc_prevphase,
1968 1.34 thorpej (u_long)sc->sc_omlen);
1969 1.25 pk } else if (sc->sc_dleft == 0) {
1970 1.22 pk /*
1971 1.25 pk * The DMA operation was started for
1972 1.25 pk * a DATA transfer. Print a diagnostic
1973 1.25 pk * if the DMA counter and TC bit
1974 1.25 pk * appear to be out of sync.
1975 1.22 pk */
1976 1.25 pk printf("%s: !TC on DATA XFER"
1977 1.25 pk " [intr %x, stat %x, step %d]"
1978 1.25 pk " prevphase %x, resid %x\n",
1979 1.25 pk sc->sc_dev.dv_xname,
1980 1.25 pk sc->sc_espintr,
1981 1.25 pk sc->sc_espstat,
1982 1.25 pk sc->sc_espstep,
1983 1.25 pk sc->sc_prevphase,
1984 1.25 pk ecb?ecb->dleft:-1);
1985 1.22 pk }
1986 1.1 thorpej }
1987 1.25 pk }
1988 1.25 pk
1989 1.25 pk /*
1990 1.25 pk * Check for less serious errors.
1991 1.25 pk */
1992 1.36.2.6 bouyer if ((sc->sc_espstat & NCRSTAT_PE) != 0) {
1993 1.25 pk printf("%s: SCSI bus parity error\n", sc->sc_dev.dv_xname);
1994 1.25 pk if (sc->sc_prevphase == MESSAGE_IN_PHASE)
1995 1.25 pk ncr53c9x_sched_msgout(SEND_PARITY_ERROR);
1996 1.25 pk else
1997 1.25 pk ncr53c9x_sched_msgout(SEND_INIT_DET_ERR);
1998 1.25 pk }
1999 1.1 thorpej
2000 1.36.2.6 bouyer if ((sc->sc_espintr & NCRINTR_DIS) != 0) {
2001 1.36.2.6 bouyer sc->sc_msgify = 0;
2002 1.25 pk NCR_MISC(("<DISC [intr %x, stat %x, step %d]>",
2003 1.25 pk sc->sc_espintr,sc->sc_espstat,sc->sc_espstep));
2004 1.25 pk if (NCR_READ_REG(sc, NCR_FFLAG) & NCRFIFO_FF) {
2005 1.25 pk NCRCMD(sc, NCRCMD_FLUSH);
2006 1.25 pk DELAY(1);
2007 1.1 thorpej }
2008 1.1 thorpej /*
2009 1.25 pk * This command must (apparently) be issued within
2010 1.25 pk * 250mS of a disconnect. So here you are...
2011 1.1 thorpej */
2012 1.25 pk NCRCMD(sc, NCRCMD_ENSEL);
2013 1.1 thorpej
2014 1.25 pk switch (sc->sc_state) {
2015 1.25 pk case NCR_RESELECTED:
2016 1.25 pk goto sched;
2017 1.22 pk
2018 1.36.2.6 bouyer case NCR_SELECTING:
2019 1.36.2.6 bouyer {
2020 1.36.2.6 bouyer struct ncr53c9x_linfo *li;
2021 1.36.2.6 bouyer
2022 1.25 pk ecb->xs->error = XS_SELTIMEOUT;
2023 1.1 thorpej
2024 1.36.2.6 bouyer /* Selection timeout -- discard all LUNs if empty */
2025 1.36.2.6 bouyer periph = ecb->xs->xs_periph;
2026 1.36.2.6 bouyer ti = &sc->sc_tinfo[periph->periph_target];
2027 1.36.2.6 bouyer li = LIST_FIRST(&ti->luns);
2028 1.36.2.6 bouyer while (li != NULL) {
2029 1.36.2.6 bouyer if (li->untagged == NULL && li->used == 0) {
2030 1.36.2.6 bouyer if (li->lun < NCR_NLUN)
2031 1.36.2.6 bouyer ti->lun[li->lun] = NULL;
2032 1.36.2.6 bouyer LIST_REMOVE(li, link);
2033 1.36.2.6 bouyer free(li, M_DEVBUF);
2034 1.36.2.6 bouyer /* Restart the search at the beginning */
2035 1.36.2.6 bouyer li = LIST_FIRST(&ti->luns);
2036 1.36.2.6 bouyer continue;
2037 1.36.2.6 bouyer }
2038 1.36.2.6 bouyer li = LIST_NEXT(li, link);
2039 1.36.2.6 bouyer }
2040 1.36.2.6 bouyer goto finish;
2041 1.36.2.6 bouyer }
2042 1.25 pk case NCR_CONNECTED:
2043 1.36.2.6 bouyer if ((sc->sc_flags & NCR_SYNCHNEGO) != 0) {
2044 1.1 thorpej #ifdef NCR53C9X_DEBUG
2045 1.36.2.6 bouyer if (ecb != NULL)
2046 1.36.2.1 thorpej scsipi_printaddr(ecb->xs->xs_periph);
2047 1.25 pk printf("sync nego not completed!\n");
2048 1.1 thorpej #endif
2049 1.36.2.1 thorpej ti = &sc->sc_tinfo[ecb->xs->xs_periph->periph_target];
2050 1.25 pk sc->sc_flags &= ~NCR_SYNCHNEGO;
2051 1.25 pk ti->flags &= ~(T_NEGOTIATE | T_SYNCMODE);
2052 1.25 pk }
2053 1.1 thorpej
2054 1.25 pk /* it may be OK to disconnect */
2055 1.25 pk if ((sc->sc_flags & NCR_ABORTING) == 0) {
2056 1.25 pk /*
2057 1.25 pk * Section 5.1.1 of the SCSI 2 spec
2058 1.25 pk * suggests issuing a REQUEST SENSE
2059 1.25 pk * following an unexpected disconnect.
2060 1.25 pk * Some devices go into a contingent
2061 1.25 pk * allegiance condition when
2062 1.25 pk * disconnecting, and this is necessary
2063 1.25 pk * to clean up their state.
2064 1.25 pk */
2065 1.25 pk printf("%s: unexpected disconnect; ",
2066 1.25 pk sc->sc_dev.dv_xname);
2067 1.36.2.6 bouyer if ((ecb->flags & ECB_SENSE) != 0) {
2068 1.25 pk printf("resetting\n");
2069 1.25 pk goto reset;
2070 1.1 thorpej }
2071 1.25 pk printf("sending REQUEST SENSE\n");
2072 1.36.2.4 bouyer callout_stop(&ecb->xs->xs_callout);
2073 1.25 pk ncr53c9x_sense(sc, ecb);
2074 1.25 pk goto out;
2075 1.25 pk }
2076 1.1 thorpej
2077 1.25 pk ecb->xs->error = XS_TIMEOUT;
2078 1.25 pk goto finish;
2079 1.1 thorpej
2080 1.25 pk case NCR_DISCONNECT:
2081 1.25 pk sc->sc_nexus = NULL;
2082 1.25 pk goto sched;
2083 1.1 thorpej
2084 1.25 pk case NCR_CMDCOMPLETE:
2085 1.25 pk goto finish;
2086 1.1 thorpej }
2087 1.25 pk }
2088 1.1 thorpej
2089 1.25 pk switch (sc->sc_state) {
2090 1.25 pk
2091 1.25 pk case NCR_SBR:
2092 1.25 pk printf("%s: waiting for SCSI Bus Reset to happen\n",
2093 1.25 pk sc->sc_dev.dv_xname);
2094 1.25 pk return (1);
2095 1.1 thorpej
2096 1.25 pk case NCR_RESELECTED:
2097 1.25 pk /*
2098 1.25 pk * we must be continuing a message ?
2099 1.25 pk */
2100 1.25 pk if (sc->sc_phase != MESSAGE_IN_PHASE) {
2101 1.25 pk printf("%s: target didn't identify\n",
2102 1.1 thorpej sc->sc_dev.dv_xname);
2103 1.25 pk ncr53c9x_init(sc, 1);
2104 1.25 pk return (1);
2105 1.25 pk }
2106 1.25 pk printf("<<RESELECT CONT'd>>");
2107 1.25 pk #if XXXX
2108 1.25 pk ncr53c9x_msgin(sc);
2109 1.25 pk if (sc->sc_state != NCR_CONNECTED) {
2110 1.25 pk /* IDENTIFY fail?! */
2111 1.25 pk printf("%s: identify failed\n",
2112 1.25 pk sc->sc_dev.dv_xname);
2113 1.25 pk ncr53c9x_init(sc, 1);
2114 1.25 pk return (1);
2115 1.25 pk }
2116 1.25 pk #endif
2117 1.25 pk break;
2118 1.25 pk
2119 1.36.2.6 bouyer case NCR_IDENTIFIED:
2120 1.36.2.6 bouyer ecb = sc->sc_nexus;
2121 1.36.2.6 bouyer if (sc->sc_phase != MESSAGE_IN_PHASE) {
2122 1.36.2.6 bouyer int i = (NCR_READ_REG(sc, NCR_FFLAG)
2123 1.36.2.6 bouyer & NCRFIFO_FF);
2124 1.36.2.6 bouyer /*
2125 1.36.2.6 bouyer * Things are seriously fucked up.
2126 1.36.2.6 bouyer * Pull the brakes, i.e. reset
2127 1.36.2.6 bouyer */
2128 1.36.2.6 bouyer printf("%s: target didn't send tag: %d bytes in fifo\n",
2129 1.36.2.6 bouyer sc->sc_dev.dv_xname, i);
2130 1.36.2.6 bouyer /* Drain and display fifo */
2131 1.36.2.6 bouyer while (i-- > 0)
2132 1.36.2.6 bouyer printf("[%d] ", NCR_READ_REG(sc, NCR_FIFO));
2133 1.36.2.6 bouyer
2134 1.36.2.6 bouyer ncr53c9x_init(sc, 1);
2135 1.36.2.6 bouyer return (1);
2136 1.36.2.6 bouyer } else
2137 1.36.2.6 bouyer goto msgin;
2138 1.36.2.6 bouyer
2139 1.36.2.6 bouyer break;
2140 1.36.2.6 bouyer
2141 1.25 pk case NCR_IDLE:
2142 1.25 pk case NCR_SELECTING:
2143 1.25 pk sc->sc_msgpriq = sc->sc_msgout = sc->sc_msgoutq = 0;
2144 1.25 pk sc->sc_flags = 0;
2145 1.25 pk ecb = sc->sc_nexus;
2146 1.25 pk if (sc->sc_espintr & NCRINTR_RESEL) {
2147 1.1 thorpej /*
2148 1.25 pk * If we're trying to select a
2149 1.25 pk * target ourselves, push our command
2150 1.25 pk * back into the ready list.
2151 1.1 thorpej */
2152 1.25 pk if (sc->sc_state == NCR_SELECTING) {
2153 1.25 pk NCR_MISC(("backoff selector "));
2154 1.36.2.4 bouyer callout_stop(&ecb->xs->xs_callout);
2155 1.25 pk TAILQ_INSERT_HEAD(&sc->ready_list, ecb, chain);
2156 1.36.2.6 bouyer ecb->flags |= ECB_READY;
2157 1.25 pk ecb = sc->sc_nexus = NULL;
2158 1.25 pk }
2159 1.25 pk sc->sc_state = NCR_RESELECTED;
2160 1.1 thorpej if (sc->sc_phase != MESSAGE_IN_PHASE) {
2161 1.25 pk /*
2162 1.25 pk * Things are seriously fucked up.
2163 1.25 pk * Pull the brakes, i.e. reset
2164 1.25 pk */
2165 1.1 thorpej printf("%s: target didn't identify\n",
2166 1.1 thorpej sc->sc_dev.dv_xname);
2167 1.1 thorpej ncr53c9x_init(sc, 1);
2168 1.25 pk return (1);
2169 1.1 thorpej }
2170 1.25 pk /*
2171 1.25 pk * The C90 only inhibits FIFO writes until
2172 1.25 pk * reselection is complete, instead of
2173 1.25 pk * waiting until the interrupt status register
2174 1.25 pk * has been read. So, if the reselect happens
2175 1.25 pk * while we were entering a command bytes (for
2176 1.25 pk * another target) some of those bytes can
2177 1.25 pk * appear in the FIFO here, after the
2178 1.25 pk * interrupt is taken.
2179 1.25 pk */
2180 1.25 pk nfifo = NCR_READ_REG(sc,NCR_FFLAG) & NCRFIFO_FF;
2181 1.25 pk if (nfifo < 2 ||
2182 1.25 pk (nfifo > 2 &&
2183 1.25 pk sc->sc_rev != NCR_VARIANT_ESP100)) {
2184 1.25 pk printf("%s: RESELECT: %d bytes in FIFO! "
2185 1.25 pk "[intr %x, stat %x, step %d, prevphase %x]\n",
2186 1.25 pk sc->sc_dev.dv_xname,
2187 1.25 pk nfifo,
2188 1.25 pk sc->sc_espintr,
2189 1.25 pk sc->sc_espstat,
2190 1.25 pk sc->sc_espstep,
2191 1.25 pk sc->sc_prevphase);
2192 1.25 pk ncr53c9x_init(sc, 1);
2193 1.25 pk return (1);
2194 1.25 pk }
2195 1.25 pk sc->sc_selid = NCR_READ_REG(sc, NCR_FIFO);
2196 1.25 pk NCR_MISC(("selid=0x%2x ", sc->sc_selid));
2197 1.25 pk
2198 1.25 pk /* Handle identify message */
2199 1.1 thorpej ncr53c9x_msgin(sc);
2200 1.25 pk if (nfifo != 2) {
2201 1.25 pk /*
2202 1.25 pk * Note: this should not happen
2203 1.25 pk * with `dmaselect' on.
2204 1.25 pk */
2205 1.25 pk sc->sc_flags |= NCR_EXPECT_ILLCMD;
2206 1.25 pk NCRCMD(sc, NCRCMD_FLUSH);
2207 1.25 pk } else if (ncr53c9x_dmaselect &&
2208 1.25 pk sc->sc_rev == NCR_VARIANT_ESP100) {
2209 1.25 pk sc->sc_flags |= NCR_EXPECT_ILLCMD;
2210 1.25 pk }
2211 1.25 pk
2212 1.36.2.6 bouyer if (sc->sc_state != NCR_CONNECTED &&
2213 1.36.2.6 bouyer sc->sc_state != NCR_IDENTIFIED) {
2214 1.1 thorpej /* IDENTIFY fail?! */
2215 1.1 thorpej printf("%s: identify failed\n",
2216 1.1 thorpej sc->sc_dev.dv_xname);
2217 1.1 thorpej ncr53c9x_init(sc, 1);
2218 1.25 pk return (1);
2219 1.1 thorpej }
2220 1.25 pk goto shortcut; /* ie. next phase expected soon */
2221 1.25 pk }
2222 1.1 thorpej
2223 1.25 pk #define NCRINTR_DONE (NCRINTR_FC|NCRINTR_BS)
2224 1.25 pk if ((sc->sc_espintr & NCRINTR_DONE) == NCRINTR_DONE) {
2225 1.25 pk /*
2226 1.25 pk * Arbitration won; examine the `step' register
2227 1.25 pk * to determine how far the selection could progress.
2228 1.25 pk */
2229 1.7 gwr ecb = sc->sc_nexus;
2230 1.36.2.6 bouyer if (ecb == NULL)
2231 1.30 pk panic("ncr53c9x: no nexus");
2232 1.25 pk
2233 1.36.2.1 thorpej periph = ecb->xs->xs_periph;
2234 1.36.2.1 thorpej ti = &sc->sc_tinfo[periph->periph_target];
2235 1.1 thorpej
2236 1.25 pk switch (sc->sc_espstep) {
2237 1.25 pk case 0:
2238 1.1 thorpej /*
2239 1.25 pk * The target did not respond with a
2240 1.25 pk * message out phase - probably an old
2241 1.25 pk * device that doesn't recognize ATN.
2242 1.25 pk * Clear ATN and just continue, the
2243 1.25 pk * target should be in the command
2244 1.25 pk * phase.
2245 1.25 pk * XXXX check for command phase?
2246 1.1 thorpej */
2247 1.25 pk NCRCMD(sc, NCRCMD_RSTATN);
2248 1.25 pk break;
2249 1.25 pk case 1:
2250 1.36.2.7 bouyer if ((ti->flags & T_NEGOTIATE) == 0 &&
2251 1.36.2.7 bouyer ecb->tag[0] == 0) {
2252 1.25 pk printf("%s: step 1 & !NEG\n",
2253 1.25 pk sc->sc_dev.dv_xname);
2254 1.25 pk goto reset;
2255 1.1 thorpej }
2256 1.25 pk if (sc->sc_phase != MESSAGE_OUT_PHASE) {
2257 1.25 pk printf("%s: !MSGOUT\n",
2258 1.1 thorpej sc->sc_dev.dv_xname);
2259 1.25 pk goto reset;
2260 1.1 thorpej }
2261 1.36.2.7 bouyer if (ti->flags & T_NEGOTIATE) {
2262 1.36.2.7 bouyer /* Start negotiating */
2263 1.36.2.7 bouyer ti->period = sc->sc_minsync;
2264 1.36.2.7 bouyer ti->offset = 15;
2265 1.36.2.7 bouyer sc->sc_flags |= NCR_SYNCHNEGO;
2266 1.36.2.7 bouyer if (ecb->tag[0])
2267 1.36.2.7 bouyer ncr53c9x_sched_msgout(SEND_TAG|SEND_SDTR);
2268 1.36.2.7 bouyer else
2269 1.36.2.7 bouyer ncr53c9x_sched_msgout(SEND_SDTR);
2270 1.36.2.7 bouyer } else {
2271 1.36.2.7 bouyer /* Could not do ATN3 so send TAG */
2272 1.36.2.7 bouyer ncr53c9x_sched_msgout(SEND_TAG);
2273 1.36.2.7 bouyer }
2274 1.36.2.6 bouyer sc->sc_prevphase = MESSAGE_OUT_PHASE; /* XXXX */
2275 1.25 pk break;
2276 1.25 pk case 3:
2277 1.5 pk /*
2278 1.25 pk * Grr, this is supposed to mean
2279 1.25 pk * "target left command phase prematurely".
2280 1.25 pk * It seems to happen regularly when
2281 1.25 pk * sync mode is on.
2282 1.25 pk * Look at FIFO to see if command went out.
2283 1.25 pk * (Timing problems?)
2284 1.5 pk */
2285 1.25 pk if (ncr53c9x_dmaselect) {
2286 1.25 pk if (sc->sc_cmdlen == 0)
2287 1.8 pk /* Hope for the best.. */
2288 1.8 pk break;
2289 1.25 pk } else if ((NCR_READ_REG(sc, NCR_FFLAG)
2290 1.1 thorpej & NCRFIFO_FF) == 0) {
2291 1.25 pk /* Hope for the best.. */
2292 1.1 thorpej break;
2293 1.1 thorpej }
2294 1.25 pk printf("(%s:%d:%d): selection failed;"
2295 1.25 pk " %d left in FIFO "
2296 1.25 pk "[intr %x, stat %x, step %d]\n",
2297 1.1 thorpej sc->sc_dev.dv_xname,
2298 1.36.2.1 thorpej periph->periph_target,
2299 1.36.2.1 thorpej periph->periph_lun,
2300 1.25 pk NCR_READ_REG(sc, NCR_FFLAG)
2301 1.25 pk & NCRFIFO_FF,
2302 1.1 thorpej sc->sc_espintr, sc->sc_espstat,
2303 1.1 thorpej sc->sc_espstep);
2304 1.1 thorpej NCRCMD(sc, NCRCMD_FLUSH);
2305 1.25 pk ncr53c9x_sched_msgout(SEND_ABORT);
2306 1.25 pk return (1);
2307 1.25 pk case 2:
2308 1.25 pk /* Select stuck at Command Phase */
2309 1.25 pk NCRCMD(sc, NCRCMD_FLUSH);
2310 1.36.2.4 bouyer break;
2311 1.25 pk case 4:
2312 1.25 pk if (ncr53c9x_dmaselect &&
2313 1.25 pk sc->sc_cmdlen != 0)
2314 1.25 pk printf("(%s:%d:%d): select; "
2315 1.34 thorpej "%lu left in DMA buffer "
2316 1.25 pk "[intr %x, stat %x, step %d]\n",
2317 1.25 pk sc->sc_dev.dv_xname,
2318 1.36.2.1 thorpej periph->periph_target,
2319 1.36.2.1 thorpej periph->periph_lun,
2320 1.34 thorpej (u_long)sc->sc_cmdlen,
2321 1.25 pk sc->sc_espintr,
2322 1.25 pk sc->sc_espstat,
2323 1.25 pk sc->sc_espstep);
2324 1.25 pk /* So far, everything went fine */
2325 1.25 pk break;
2326 1.1 thorpej }
2327 1.25 pk
2328 1.25 pk sc->sc_prevphase = INVALID_PHASE; /* ?? */
2329 1.25 pk /* Do an implicit RESTORE POINTERS. */
2330 1.25 pk sc->sc_dp = ecb->daddr;
2331 1.25 pk sc->sc_dleft = ecb->dleft;
2332 1.25 pk sc->sc_state = NCR_CONNECTED;
2333 1.1 thorpej break;
2334 1.1 thorpej
2335 1.25 pk } else {
2336 1.1 thorpej
2337 1.25 pk printf("%s: unexpected status after select"
2338 1.25 pk ": [intr %x, stat %x, step %x]\n",
2339 1.25 pk sc->sc_dev.dv_xname,
2340 1.25 pk sc->sc_espintr, sc->sc_espstat,
2341 1.25 pk sc->sc_espstep);
2342 1.25 pk NCRCMD(sc, NCRCMD_FLUSH);
2343 1.25 pk DELAY(1);
2344 1.25 pk goto reset;
2345 1.1 thorpej }
2346 1.25 pk if (sc->sc_state == NCR_IDLE) {
2347 1.36.2.6 bouyer printf("%s: stray interrupt\n", sc->sc_dev.dv_xname);
2348 1.36.2.6 bouyer return (0);
2349 1.1 thorpej }
2350 1.25 pk break;
2351 1.1 thorpej
2352 1.25 pk case NCR_CONNECTED:
2353 1.36.2.6 bouyer if ((sc->sc_flags & NCR_ICCS) != 0) {
2354 1.25 pk /* "Initiate Command Complete Steps" in progress */
2355 1.25 pk u_char msg;
2356 1.25 pk
2357 1.25 pk sc->sc_flags &= ~NCR_ICCS;
2358 1.25 pk
2359 1.25 pk if (!(sc->sc_espintr & NCRINTR_DONE)) {
2360 1.25 pk printf("%s: ICCS: "
2361 1.25 pk ": [intr %x, stat %x, step %x]\n",
2362 1.1 thorpej sc->sc_dev.dv_xname,
2363 1.1 thorpej sc->sc_espintr, sc->sc_espstat,
2364 1.1 thorpej sc->sc_espstep);
2365 1.1 thorpej }
2366 1.25 pk if ((NCR_READ_REG(sc, NCR_FFLAG)
2367 1.25 pk & NCRFIFO_FF) != 2) {
2368 1.36.2.4 bouyer /* Drop excess bytes from the queue */
2369 1.25 pk int i = (NCR_READ_REG(sc, NCR_FFLAG)
2370 1.25 pk & NCRFIFO_FF) - 2;
2371 1.36.2.4 bouyer while (i-- > 0)
2372 1.25 pk (void) NCR_READ_REG(sc, NCR_FIFO);
2373 1.1 thorpej }
2374 1.25 pk ecb->stat = NCR_READ_REG(sc, NCR_FIFO);
2375 1.25 pk msg = NCR_READ_REG(sc, NCR_FIFO);
2376 1.25 pk NCR_PHASE(("<stat:(%x,%x)>", ecb->stat, msg));
2377 1.25 pk if (msg == MSG_CMDCOMPLETE) {
2378 1.25 pk ecb->dleft = (ecb->flags & ECB_TENTATIVE_DONE)
2379 1.25 pk ? 0
2380 1.25 pk : sc->sc_dleft;
2381 1.25 pk if ((ecb->flags & ECB_SENSE) == 0)
2382 1.25 pk ecb->xs->resid = ecb->dleft;
2383 1.25 pk sc->sc_state = NCR_CMDCOMPLETE;
2384 1.25 pk } else
2385 1.25 pk printf("%s: STATUS_PHASE: msg %d\n",
2386 1.25 pk sc->sc_dev.dv_xname, msg);
2387 1.25 pk NCRCMD(sc, NCRCMD_MSGOK);
2388 1.25 pk goto shortcut; /* ie. wait for disconnect */
2389 1.25 pk }
2390 1.25 pk break;
2391 1.36.2.6 bouyer
2392 1.25 pk default:
2393 1.25 pk panic("%s: invalid state: %d",
2394 1.25 pk sc->sc_dev.dv_xname,
2395 1.25 pk sc->sc_state);
2396 1.25 pk }
2397 1.8 pk
2398 1.25 pk /*
2399 1.25 pk * Driver is now in state NCR_CONNECTED, i.e. we
2400 1.25 pk * have a current command working the SCSI bus.
2401 1.25 pk */
2402 1.25 pk if (sc->sc_state != NCR_CONNECTED || ecb == NULL) {
2403 1.30 pk panic("ncr53c9x: no nexus");
2404 1.25 pk }
2405 1.22 pk
2406 1.25 pk switch (sc->sc_phase) {
2407 1.25 pk case MESSAGE_OUT_PHASE:
2408 1.25 pk NCR_PHASE(("MESSAGE_OUT_PHASE "));
2409 1.25 pk ncr53c9x_msgout(sc);
2410 1.25 pk sc->sc_prevphase = MESSAGE_OUT_PHASE;
2411 1.25 pk break;
2412 1.36.2.6 bouyer
2413 1.25 pk case MESSAGE_IN_PHASE:
2414 1.36.2.6 bouyer msgin:
2415 1.25 pk NCR_PHASE(("MESSAGE_IN_PHASE "));
2416 1.25 pk sc->sc_prevphase = MESSAGE_IN_PHASE;
2417 1.36.2.6 bouyer if ((sc->sc_espintr & NCRINTR_BS) != 0) {
2418 1.25 pk NCRCMD(sc, NCRCMD_FLUSH);
2419 1.25 pk sc->sc_flags |= NCR_WAITI;
2420 1.25 pk NCRCMD(sc, NCRCMD_TRANS);
2421 1.36.2.6 bouyer } else if ((sc->sc_espintr & NCRINTR_FC) != 0) {
2422 1.25 pk if ((sc->sc_flags & NCR_WAITI) == 0) {
2423 1.25 pk printf("%s: MSGIN: unexpected FC bit: "
2424 1.25 pk "[intr %x, stat %x, step %x]\n",
2425 1.25 pk sc->sc_dev.dv_xname,
2426 1.25 pk sc->sc_espintr, sc->sc_espstat,
2427 1.25 pk sc->sc_espstep);
2428 1.8 pk }
2429 1.25 pk sc->sc_flags &= ~NCR_WAITI;
2430 1.25 pk ncr53c9x_msgin(sc);
2431 1.25 pk } else {
2432 1.25 pk printf("%s: MSGIN: weird bits: "
2433 1.25 pk "[intr %x, stat %x, step %x]\n",
2434 1.25 pk sc->sc_dev.dv_xname,
2435 1.25 pk sc->sc_espintr, sc->sc_espstat,
2436 1.25 pk sc->sc_espstep);
2437 1.25 pk }
2438 1.25 pk goto shortcut; /* i.e. expect data to be ready */
2439 1.25 pk break;
2440 1.36.2.6 bouyer
2441 1.25 pk case COMMAND_PHASE:
2442 1.25 pk /*
2443 1.25 pk * Send the command block. Normally we don't see this
2444 1.25 pk * phase because the SEL_ATN command takes care of
2445 1.25 pk * all this. However, we end up here if either the
2446 1.25 pk * target or we wanted to exchange some more messages
2447 1.25 pk * first (e.g. to start negotiations).
2448 1.25 pk */
2449 1.25 pk
2450 1.25 pk NCR_PHASE(("COMMAND_PHASE 0x%02x (%d) ",
2451 1.25 pk ecb->cmd.cmd.opcode, ecb->clen));
2452 1.25 pk if (NCR_READ_REG(sc, NCR_FFLAG) & NCRFIFO_FF) {
2453 1.1 thorpej NCRCMD(sc, NCRCMD_FLUSH);
2454 1.25 pk DELAY(1);
2455 1.25 pk }
2456 1.25 pk if (ncr53c9x_dmaselect) {
2457 1.25 pk size_t size;
2458 1.25 pk /* setup DMA transfer for command */
2459 1.25 pk size = ecb->clen;
2460 1.25 pk sc->sc_cmdlen = size;
2461 1.25 pk sc->sc_cmdp = (caddr_t)&ecb->cmd.cmd;
2462 1.25 pk NCRDMA_SETUP(sc, &sc->sc_cmdp, &sc->sc_cmdlen,
2463 1.25 pk 0, &size);
2464 1.1 thorpej /* Program the SCSI counter */
2465 1.1 thorpej NCR_WRITE_REG(sc, NCR_TCL, size);
2466 1.1 thorpej NCR_WRITE_REG(sc, NCR_TCM, size >> 8);
2467 1.1 thorpej if (sc->sc_cfg2 & NCRCFG2_FE) {
2468 1.1 thorpej NCR_WRITE_REG(sc, NCR_TCH, size >> 16);
2469 1.1 thorpej }
2470 1.25 pk
2471 1.1 thorpej /* load the count in */
2472 1.1 thorpej NCRCMD(sc, NCRCMD_NOP|NCRCMD_DMA);
2473 1.1 thorpej
2474 1.25 pk /* start the command transfer */
2475 1.25 pk NCRCMD(sc, NCRCMD_TRANS | NCRCMD_DMA);
2476 1.1 thorpej NCRDMA_GO(sc);
2477 1.25 pk } else {
2478 1.25 pk u_char *cmd = (u_char *)&ecb->cmd.cmd;
2479 1.25 pk int i;
2480 1.25 pk /* Now the command into the FIFO */
2481 1.25 pk for (i = 0; i < ecb->clen; i++)
2482 1.25 pk NCR_WRITE_REG(sc, NCR_FIFO, *cmd++);
2483 1.25 pk NCRCMD(sc, NCRCMD_TRANS);
2484 1.25 pk }
2485 1.25 pk sc->sc_prevphase = COMMAND_PHASE;
2486 1.25 pk break;
2487 1.36.2.6 bouyer
2488 1.25 pk case DATA_OUT_PHASE:
2489 1.25 pk NCR_PHASE(("DATA_OUT_PHASE [%ld] ",(long)sc->sc_dleft));
2490 1.25 pk NCRCMD(sc, NCRCMD_FLUSH);
2491 1.25 pk size = min(sc->sc_dleft, sc->sc_maxxfer);
2492 1.25 pk NCRDMA_SETUP(sc, &sc->sc_dp, &sc->sc_dleft,
2493 1.25 pk 0, &size);
2494 1.25 pk sc->sc_prevphase = DATA_OUT_PHASE;
2495 1.25 pk goto setup_xfer;
2496 1.36.2.6 bouyer
2497 1.25 pk case DATA_IN_PHASE:
2498 1.25 pk NCR_PHASE(("DATA_IN_PHASE "));
2499 1.25 pk if (sc->sc_rev == NCR_VARIANT_ESP100)
2500 1.25 pk NCRCMD(sc, NCRCMD_FLUSH);
2501 1.25 pk size = min(sc->sc_dleft, sc->sc_maxxfer);
2502 1.25 pk NCRDMA_SETUP(sc, &sc->sc_dp, &sc->sc_dleft,
2503 1.25 pk 1, &size);
2504 1.25 pk sc->sc_prevphase = DATA_IN_PHASE;
2505 1.25 pk setup_xfer:
2506 1.25 pk /* Target returned to data phase: wipe "done" memory */
2507 1.25 pk ecb->flags &= ~ECB_TENTATIVE_DONE;
2508 1.25 pk
2509 1.25 pk /* Program the SCSI counter */
2510 1.25 pk NCR_WRITE_REG(sc, NCR_TCL, size);
2511 1.25 pk NCR_WRITE_REG(sc, NCR_TCM, size >> 8);
2512 1.36.2.6 bouyer if ((sc->sc_cfg2 & NCRCFG2_FE) != 0) {
2513 1.25 pk NCR_WRITE_REG(sc, NCR_TCH, size >> 16);
2514 1.1 thorpej }
2515 1.25 pk /* load the count in */
2516 1.25 pk NCRCMD(sc, NCRCMD_NOP|NCRCMD_DMA);
2517 1.25 pk
2518 1.25 pk /*
2519 1.25 pk * Note that if `size' is 0, we've already transceived
2520 1.25 pk * all the bytes we want but we're still in DATA PHASE.
2521 1.25 pk * Apparently, the device needs padding. Also, a
2522 1.25 pk * transfer size of 0 means "maximum" to the chip
2523 1.25 pk * DMA logic.
2524 1.25 pk */
2525 1.25 pk NCRCMD(sc,
2526 1.25 pk (size==0?NCRCMD_TRPAD:NCRCMD_TRANS)|NCRCMD_DMA);
2527 1.25 pk NCRDMA_GO(sc);
2528 1.25 pk return (1);
2529 1.36.2.6 bouyer
2530 1.25 pk case STATUS_PHASE:
2531 1.25 pk NCR_PHASE(("STATUS_PHASE "));
2532 1.25 pk sc->sc_flags |= NCR_ICCS;
2533 1.25 pk NCRCMD(sc, NCRCMD_ICCS);
2534 1.25 pk sc->sc_prevphase = STATUS_PHASE;
2535 1.25 pk goto shortcut; /* i.e. expect status results soon */
2536 1.25 pk break;
2537 1.36.2.6 bouyer
2538 1.25 pk case INVALID_PHASE:
2539 1.25 pk break;
2540 1.36.2.6 bouyer
2541 1.25 pk default:
2542 1.25 pk printf("%s: unexpected bus phase; resetting\n",
2543 1.36.2.6 bouyer sc->sc_dev.dv_xname);
2544 1.25 pk goto reset;
2545 1.1 thorpej }
2546 1.25 pk
2547 1.25 pk out:
2548 1.25 pk return (1);
2549 1.1 thorpej
2550 1.1 thorpej reset:
2551 1.1 thorpej ncr53c9x_init(sc, 1);
2552 1.25 pk goto out;
2553 1.1 thorpej
2554 1.1 thorpej finish:
2555 1.1 thorpej ncr53c9x_done(sc, ecb);
2556 1.1 thorpej goto out;
2557 1.1 thorpej
2558 1.1 thorpej sched:
2559 1.1 thorpej sc->sc_state = NCR_IDLE;
2560 1.1 thorpej ncr53c9x_sched(sc);
2561 1.1 thorpej goto out;
2562 1.1 thorpej
2563 1.25 pk shortcut:
2564 1.25 pk /*
2565 1.25 pk * The idea is that many of the SCSI operations take very little
2566 1.25 pk * time, and going away and getting interrupted is too high an
2567 1.25 pk * overhead to pay. For example, selecting, sending a message
2568 1.25 pk * and command and then doing some work can be done in one "pass".
2569 1.25 pk *
2570 1.25 pk * The delay is a heuristic. It is 2 when at 20Mhz, 2 at 25Mhz and 1
2571 1.25 pk * at 40Mhz. This needs testing.
2572 1.25 pk */
2573 1.25 pk DELAY(50/sc->sc_freq);
2574 1.25 pk if (NCRDMA_ISINTR(sc))
2575 1.25 pk goto again;
2576 1.25 pk goto out;
2577 1.1 thorpej }
2578 1.1 thorpej
2579 1.1 thorpej void
2580 1.1 thorpej ncr53c9x_abort(sc, ecb)
2581 1.1 thorpej struct ncr53c9x_softc *sc;
2582 1.1 thorpej struct ncr53c9x_ecb *ecb;
2583 1.1 thorpej {
2584 1.1 thorpej
2585 1.1 thorpej /* 2 secs for the abort */
2586 1.1 thorpej ecb->timeout = NCR_ABORT_TIMEOUT;
2587 1.1 thorpej ecb->flags |= ECB_ABORT;
2588 1.1 thorpej
2589 1.1 thorpej if (ecb == sc->sc_nexus) {
2590 1.36.2.4 bouyer int timeout;
2591 1.36.2.4 bouyer
2592 1.1 thorpej /*
2593 1.1 thorpej * If we're still selecting, the message will be scheduled
2594 1.1 thorpej * after selection is complete.
2595 1.1 thorpej */
2596 1.1 thorpej if (sc->sc_state == NCR_CONNECTED)
2597 1.1 thorpej ncr53c9x_sched_msgout(SEND_ABORT);
2598 1.1 thorpej
2599 1.1 thorpej /*
2600 1.36.2.4 bouyer * Reschedule timeout.
2601 1.1 thorpej */
2602 1.36.2.4 bouyer timeout = ecb->timeout;
2603 1.36.2.4 bouyer if (hz > 100 && timeout > 1000)
2604 1.36.2.4 bouyer timeout = (timeout / 1000) * hz;
2605 1.36.2.4 bouyer else
2606 1.36.2.4 bouyer timeout = (timeout * hz) / 1000;
2607 1.36.2.4 bouyer callout_reset(&ecb->xs->xs_callout, timeout,
2608 1.36.2.4 bouyer ncr53c9x_timeout, ecb);
2609 1.1 thorpej } else {
2610 1.23 pk /*
2611 1.36.2.6 bouyer * Just leave the command where it is.
2612 1.23 pk * XXX - what choice do we have but to reset the SCSI
2613 1.23 pk * eventually?
2614 1.23 pk */
2615 1.1 thorpej if (sc->sc_state == NCR_IDLE)
2616 1.1 thorpej ncr53c9x_sched(sc);
2617 1.1 thorpej }
2618 1.1 thorpej }
2619 1.1 thorpej
2620 1.1 thorpej void
2621 1.1 thorpej ncr53c9x_timeout(arg)
2622 1.1 thorpej void *arg;
2623 1.1 thorpej {
2624 1.1 thorpej struct ncr53c9x_ecb *ecb = arg;
2625 1.18 bouyer struct scsipi_xfer *xs = ecb->xs;
2626 1.36.2.1 thorpej struct scsipi_periph *periph = xs->xs_periph;
2627 1.36.2.1 thorpej struct ncr53c9x_softc *sc =
2628 1.36.2.1 thorpej (void *)periph->periph_channel->chan_adapter->adapt_dev;
2629 1.36.2.1 thorpej struct ncr53c9x_tinfo *ti = &sc->sc_tinfo[periph->periph_target];
2630 1.1 thorpej int s;
2631 1.1 thorpej
2632 1.36.2.1 thorpej scsipi_printaddr(periph);
2633 1.1 thorpej printf("%s: timed out [ecb %p (flags 0x%x, dleft %x, stat %x)], "
2634 1.23 pk "<state %d, nexus %p, phase(l %x, c %x, p %x), resid %lx, "
2635 1.1 thorpej "msg(q %x,o %x) %s>",
2636 1.1 thorpej sc->sc_dev.dv_xname,
2637 1.1 thorpej ecb, ecb->flags, ecb->dleft, ecb->stat,
2638 1.23 pk sc->sc_state, sc->sc_nexus,
2639 1.23 pk NCR_READ_REG(sc, NCR_STAT),
2640 1.23 pk sc->sc_phase, sc->sc_prevphase,
2641 1.1 thorpej (long)sc->sc_dleft, sc->sc_msgpriq, sc->sc_msgout,
2642 1.1 thorpej NCRDMA_ISACTIVE(sc) ? "DMA active" : "");
2643 1.7 gwr #if NCR53C9X_DEBUG > 1
2644 1.1 thorpej printf("TRACE: %s.", ecb->trace);
2645 1.1 thorpej #endif
2646 1.1 thorpej
2647 1.1 thorpej s = splbio();
2648 1.1 thorpej
2649 1.1 thorpej if (ecb->flags & ECB_ABORT) {
2650 1.1 thorpej /* abort timed out */
2651 1.1 thorpej printf(" AGAIN\n");
2652 1.16 pk
2653 1.1 thorpej ncr53c9x_init(sc, 1);
2654 1.1 thorpej } else {
2655 1.1 thorpej /* abort the operation that has timed out */
2656 1.1 thorpej printf("\n");
2657 1.1 thorpej xs->error = XS_TIMEOUT;
2658 1.1 thorpej ncr53c9x_abort(sc, ecb);
2659 1.16 pk
2660 1.16 pk /* Disable sync mode if stuck in a data phase */
2661 1.16 pk if (ecb == sc->sc_nexus &&
2662 1.16 pk (ti->flags & T_SYNCMODE) != 0 &&
2663 1.16 pk (sc->sc_phase & (MSGI|CDI)) == 0) {
2664 1.36.2.1 thorpej /* XXX ASYNC CALLBACK! */
2665 1.36.2.1 thorpej scsipi_printaddr(periph);
2666 1.16 pk printf("sync negotiation disabled\n");
2667 1.36.2.1 thorpej sc->sc_cfflags |= (1<<(periph->periph_target+8));
2668 1.36.2.10 bouyer ncr53c9x_update_xfer_mode(sc, periph->periph_target);
2669 1.16 pk }
2670 1.1 thorpej }
2671 1.1 thorpej
2672 1.1 thorpej splx(s);
2673 1.1 thorpej }
2674 1.36.2.6 bouyer
2675 1.36.2.6 bouyer void
2676 1.36.2.6 bouyer ncr53c9x_watch(arg)
2677 1.36.2.6 bouyer void *arg;
2678 1.36.2.6 bouyer {
2679 1.36.2.6 bouyer struct ncr53c9x_softc *sc = (struct ncr53c9x_softc *)arg;
2680 1.36.2.6 bouyer struct ncr53c9x_tinfo *ti;
2681 1.36.2.6 bouyer struct ncr53c9x_linfo *li;
2682 1.36.2.6 bouyer int t, s;
2683 1.36.2.6 bouyer /* Delete any structures that have not been used in 10min. */
2684 1.36.2.6 bouyer time_t old = time.tv_sec - (10*60);
2685 1.36.2.6 bouyer
2686 1.36.2.6 bouyer s = splbio();
2687 1.36.2.6 bouyer for (t=0; t<NCR_NTARG; t++) {
2688 1.36.2.6 bouyer ti = &sc->sc_tinfo[t];
2689 1.36.2.6 bouyer li = LIST_FIRST(&ti->luns);
2690 1.36.2.6 bouyer while (li) {
2691 1.36.2.6 bouyer if (li->last_used < old && li->untagged == NULL &&
2692 1.36.2.6 bouyer li->used == 0) {
2693 1.36.2.6 bouyer if (li->lun < NCR_NLUN)
2694 1.36.2.6 bouyer ti->lun[li->lun] = NULL;
2695 1.36.2.6 bouyer LIST_REMOVE(li, link);
2696 1.36.2.6 bouyer free(li, M_DEVBUF);
2697 1.36.2.6 bouyer /* Restart the search at the beginning */
2698 1.36.2.6 bouyer li = LIST_FIRST(&ti->luns);
2699 1.36.2.6 bouyer continue;
2700 1.36.2.6 bouyer }
2701 1.36.2.6 bouyer li = LIST_NEXT(li, link);
2702 1.36.2.6 bouyer }
2703 1.36.2.6 bouyer }
2704 1.36.2.6 bouyer splx(s);
2705 1.36.2.6 bouyer callout_reset(&sc->sc_watchdog, 60*hz, ncr53c9x_watch, sc);
2706 1.36.2.6 bouyer }
2707 1.36.2.6 bouyer
2708