Line data Source code
1 : /* $OpenBSD: siop.c,v 1.71 2015/09/09 18:24:26 deraadt Exp $ */
2 : /* $NetBSD: siop.c,v 1.79 2005/11/18 23:10:32 bouyer Exp $ */
3 :
4 : /*
5 : * Copyright (c) 2000 Manuel Bouyer.
6 : *
7 : * Redistribution and use in source and binary forms, with or without
8 : * modification, are permitted provided that the following conditions
9 : * are met:
10 : * 1. Redistributions of source code must retain the above copyright
11 : * notice, this list of conditions and the following disclaimer.
12 : * 2. Redistributions in binary form must reproduce the above copyright
13 : * notice, this list of conditions and the following disclaimer in the
14 : * documentation and/or other materials provided with the distribution.
15 : *
16 : * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 : * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 : * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 : * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 : * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 : * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 : * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 : * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 : * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 : * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 : *
27 : */
28 :
29 : /* SYM53c7/8xx PCI-SCSI I/O Processors driver */
30 :
31 : #include <sys/param.h>
32 : #include <sys/systm.h>
33 : #include <sys/device.h>
34 : #include <sys/malloc.h>
35 : #include <sys/kernel.h>
36 : #include <sys/endian.h>
37 :
38 : #include <machine/bus.h>
39 :
40 : #include <dev/microcode/siop/siop.out>
41 :
42 : #include <scsi/scsi_all.h>
43 : #include <scsi/scsi_message.h>
44 : #include <scsi/scsiconf.h>
45 :
46 : #include <dev/ic/siopreg.h>
47 : #include <dev/ic/siopvar_common.h>
48 : #include <dev/ic/siopvar.h>
49 :
50 : #ifndef SIOP_DEBUG
51 : #undef SIOP_DEBUG
52 : #undef SIOP_DEBUG_DR
53 : #undef SIOP_DEBUG_INTR
54 : #undef SIOP_DEBUG_SCHED
55 : #undef DUMP_SCRIPT
56 : #else
57 : #define SIOP_DEBUG_DR
58 : #define SIOP_DEBUG_INTR
59 : #define SIOP_DEBUG_SCHED
60 : #define DUMP_SCRIPT
61 : #endif
62 :
63 :
64 : #undef SIOP_STATS
65 :
66 : #ifndef SIOP_DEFAULT_TARGET
67 : #define SIOP_DEFAULT_TARGET 7
68 : #endif
69 :
70 : /* number of cmd descriptors per block */
71 : #define SIOP_NCMDPB (PAGE_SIZE / sizeof(struct siop_xfer))
72 :
73 : /* Number of scheduler slot (needs to match script) */
74 : #define SIOP_NSLOTS 40
75 :
76 : void siop_table_sync(struct siop_cmd *, int);
77 : void siop_script_sync(struct siop_softc *, int);
78 : u_int32_t siop_script_read(struct siop_softc *, u_int);
79 : void siop_script_write(struct siop_softc *, u_int, u_int32_t);
80 : void siop_reset(struct siop_softc *);
81 : void siop_handle_reset(struct siop_softc *);
82 : int siop_handle_qtag_reject(struct siop_cmd *);
83 : void siop_scsicmd_end(struct siop_cmd *);
84 : void siop_start(struct siop_softc *);
85 : void siop_timeout(void *);
86 : void siop_scsicmd(struct scsi_xfer *);
87 : void * siop_cmd_get(void *);
88 : void siop_cmd_put(void *, void *);
89 : int siop_scsiprobe(struct scsi_link *);
90 : void siop_scsifree(struct scsi_link *);
91 : #ifdef DUMP_SCRIPT
92 : void siop_dump_script(struct siop_softc *);
93 : #endif
94 : void siop_morecbd(struct siop_softc *);
95 : struct siop_lunsw *siop_get_lunsw(struct siop_softc *);
96 : void siop_add_reselsw(struct siop_softc *, int);
97 : void siop_update_scntl3(struct siop_softc *, struct siop_common_target *);
98 :
99 : struct siop_dmamem *siop_dmamem_alloc(struct siop_softc *, size_t);
100 : void siop_dmamem_free(struct siop_softc *, struct siop_dmamem *);
101 :
102 : struct cfdriver siop_cd = {
103 : NULL, "siop", DV_DULL
104 : };
105 :
106 : struct scsi_adapter siop_adapter = {
107 : siop_scsicmd,
108 : siop_minphys,
109 : siop_scsiprobe,
110 : siop_scsifree
111 : };
112 :
113 : #ifdef SIOP_STATS
114 : static int siop_stat_intr = 0;
115 : static int siop_stat_intr_shortxfer = 0;
116 : static int siop_stat_intr_sdp = 0;
117 : static int siop_stat_intr_saveoffset = 0;
118 : static int siop_stat_intr_done = 0;
119 : static int siop_stat_intr_xferdisc = 0;
120 : static int siop_stat_intr_lunresel = 0;
121 : static int siop_stat_intr_qfull = 0;
122 : void siop_printstats(void);
123 : #define INCSTAT(x) x++
124 : #else
125 : #define INCSTAT(x)
126 : #endif
127 :
128 : void
129 0 : siop_table_sync(siop_cmd, ops)
130 : struct siop_cmd *siop_cmd;
131 : int ops;
132 : {
133 0 : struct siop_common_softc *sc = siop_cmd->cmd_c.siop_sc;
134 : bus_addr_t offset;
135 :
136 0 : offset = siop_cmd->cmd_c.dsa -
137 0 : SIOP_DMA_DVA(siop_cmd->siop_cbdp->xfers);
138 0 : bus_dmamap_sync(sc->sc_dmat,
139 : SIOP_DMA_MAP(siop_cmd->siop_cbdp->xfers), offset,
140 : sizeof(struct siop_xfer), ops);
141 0 : }
142 :
143 : void
144 0 : siop_script_sync(sc, ops)
145 : struct siop_softc *sc;
146 : int ops;
147 : {
148 0 : if ((sc->sc_c.features & SF_CHIP_RAM) == 0)
149 0 : bus_dmamap_sync(sc->sc_c.sc_dmat, sc->sc_c.sc_scriptdma, 0,
150 : PAGE_SIZE, ops);
151 0 : }
152 :
153 : u_int32_t
154 0 : siop_script_read(sc, offset)
155 : struct siop_softc *sc;
156 : u_int offset;
157 : {
158 0 : if (sc->sc_c.features & SF_CHIP_RAM) {
159 0 : return bus_space_read_4(sc->sc_c.sc_ramt, sc->sc_c.sc_ramh,
160 : offset * 4);
161 : } else {
162 0 : return siop_ctoh32(&sc->sc_c, sc->sc_c.sc_script[offset]);
163 : }
164 0 : }
165 :
166 : void
167 0 : siop_script_write(sc, offset, val)
168 : struct siop_softc *sc;
169 : u_int offset;
170 : u_int32_t val;
171 : {
172 0 : if (sc->sc_c.features & SF_CHIP_RAM) {
173 0 : bus_space_write_4(sc->sc_c.sc_ramt, sc->sc_c.sc_ramh,
174 : offset * 4, val);
175 0 : } else {
176 0 : sc->sc_c.sc_script[offset] = siop_htoc32(&sc->sc_c, val);
177 : }
178 0 : }
179 :
180 : void
181 0 : siop_attach(sc)
182 : struct siop_softc *sc;
183 : {
184 0 : struct scsibus_attach_args saa;
185 :
186 0 : if (siop_common_attach(&sc->sc_c) != 0)
187 0 : return;
188 :
189 0 : TAILQ_INIT(&sc->free_list);
190 0 : TAILQ_INIT(&sc->ready_list);
191 0 : TAILQ_INIT(&sc->urgent_list);
192 0 : TAILQ_INIT(&sc->cmds);
193 0 : TAILQ_INIT(&sc->lunsw_list);
194 0 : scsi_iopool_init(&sc->iopool, sc, siop_cmd_get, siop_cmd_put);
195 0 : sc->sc_currschedslot = 0;
196 0 : sc->sc_c.sc_link.adapter = &siop_adapter;
197 0 : sc->sc_c.sc_link.openings = SIOP_NTAG;
198 0 : sc->sc_c.sc_link.pool = &sc->iopool;
199 :
200 : /* Start with one page worth of commands */
201 0 : siop_morecbd(sc);
202 :
203 : #ifdef SIOP_DEBUG
204 : printf("%s: script size = %d, PHY addr=0x%x, VIRT=%p\n",
205 : sc->sc_c.sc_dev.dv_xname, (int)sizeof(siop_script),
206 : (u_int32_t)sc->sc_c.sc_scriptaddr, sc->sc_c.sc_script);
207 : #endif
208 :
209 : /* Do a bus reset, so that devices fall back to narrow/async */
210 0 : siop_resetbus(&sc->sc_c);
211 : /*
212 : * siop_reset() will reset the chip, thus clearing pending interrupts
213 : */
214 0 : siop_reset(sc);
215 : #ifdef DUMP_SCRIPT
216 : siop_dump_script(sc);
217 : #endif
218 :
219 0 : bzero(&saa, sizeof(saa));
220 0 : saa.saa_sc_link = &sc->sc_c.sc_link;
221 :
222 0 : config_found((struct device*)sc, &saa, scsiprint);
223 0 : }
224 :
225 : void
226 0 : siop_reset(sc)
227 : struct siop_softc *sc;
228 : {
229 : int i, j;
230 : struct siop_lunsw *lunsw;
231 :
232 0 : siop_common_reset(&sc->sc_c);
233 :
234 : /* copy and patch the script */
235 0 : if (sc->sc_c.features & SF_CHIP_RAM) {
236 0 : bus_space_write_region_4(sc->sc_c.sc_ramt, sc->sc_c.sc_ramh, 0,
237 : siop_script, sizeof(siop_script) / sizeof(siop_script[0]));
238 0 : for (j = 0; j <
239 : (sizeof(E_abs_msgin_Used) / sizeof(E_abs_msgin_Used[0]));
240 0 : j++) {
241 0 : bus_space_write_4(sc->sc_c.sc_ramt, sc->sc_c.sc_ramh,
242 : E_abs_msgin_Used[j] * 4,
243 : sc->sc_c.sc_scriptaddr + Ent_msgin_space);
244 : }
245 0 : if (sc->sc_c.features & SF_CHIP_LED0) {
246 0 : bus_space_write_region_4(sc->sc_c.sc_ramt,
247 : sc->sc_c.sc_ramh,
248 : Ent_led_on1, siop_led_on,
249 : sizeof(siop_led_on) / sizeof(siop_led_on[0]));
250 0 : bus_space_write_region_4(sc->sc_c.sc_ramt,
251 : sc->sc_c.sc_ramh,
252 : Ent_led_on2, siop_led_on,
253 : sizeof(siop_led_on) / sizeof(siop_led_on[0]));
254 0 : bus_space_write_region_4(sc->sc_c.sc_ramt,
255 : sc->sc_c.sc_ramh,
256 : Ent_led_off, siop_led_off,
257 : sizeof(siop_led_off) / sizeof(siop_led_off[0]));
258 0 : }
259 : } else {
260 0 : for (j = 0;
261 0 : j < (sizeof(siop_script) / sizeof(siop_script[0])); j++) {
262 0 : sc->sc_c.sc_script[j] =
263 0 : siop_htoc32(&sc->sc_c, siop_script[j]);
264 : }
265 0 : for (j = 0; j <
266 : (sizeof(E_abs_msgin_Used) / sizeof(E_abs_msgin_Used[0]));
267 0 : j++) {
268 0 : sc->sc_c.sc_script[E_abs_msgin_Used[j]] =
269 0 : siop_htoc32(&sc->sc_c,
270 : sc->sc_c.sc_scriptaddr + Ent_msgin_space);
271 : }
272 0 : if (sc->sc_c.features & SF_CHIP_LED0) {
273 0 : for (j = 0; j < (sizeof(siop_led_on) /
274 0 : sizeof(siop_led_on[0])); j++)
275 0 : sc->sc_c.sc_script[
276 0 : Ent_led_on1 / sizeof(siop_led_on[0]) + j
277 0 : ] = siop_htoc32(&sc->sc_c, siop_led_on[j]);
278 0 : for (j = 0; j < (sizeof(siop_led_on) /
279 0 : sizeof(siop_led_on[0])); j++)
280 0 : sc->sc_c.sc_script[
281 0 : Ent_led_on2 / sizeof(siop_led_on[0]) + j
282 0 : ] = siop_htoc32(&sc->sc_c, siop_led_on[j]);
283 0 : for (j = 0; j < (sizeof(siop_led_off) /
284 0 : sizeof(siop_led_off[0])); j++)
285 0 : sc->sc_c.sc_script[
286 0 : Ent_led_off / sizeof(siop_led_off[0]) + j
287 0 : ] = siop_htoc32(&sc->sc_c, siop_led_off[j]);
288 : }
289 : }
290 0 : sc->script_free_lo = sizeof(siop_script) / sizeof(siop_script[0]);
291 0 : sc->script_free_hi = sc->sc_c.ram_size / 4;
292 0 : sc->sc_ntargets = 0;
293 :
294 : /* free used and unused lun switches */
295 0 : while((lunsw = TAILQ_FIRST(&sc->lunsw_list)) != NULL) {
296 : #ifdef SIOP_DEBUG
297 : printf("%s: free lunsw at offset %d\n",
298 : sc->sc_c.sc_dev.dv_xname, lunsw->lunsw_off);
299 : #endif
300 0 : TAILQ_REMOVE(&sc->lunsw_list, lunsw, next);
301 0 : free(lunsw, M_DEVBUF, 0);
302 : }
303 0 : TAILQ_INIT(&sc->lunsw_list);
304 : /* restore reselect switch */
305 0 : for (i = 0; i < sc->sc_c.sc_link.adapter_buswidth; i++) {
306 : struct siop_target *target;
307 0 : if (sc->sc_c.targets[i] == NULL)
308 0 : continue;
309 : #ifdef SIOP_DEBUG
310 : printf("%s: restore sw for target %d\n",
311 : sc->sc_c.sc_dev.dv_xname, i);
312 : #endif
313 0 : target = (struct siop_target *)sc->sc_c.targets[i];
314 0 : free(target->lunsw, M_DEVBUF, 0);
315 0 : target->lunsw = siop_get_lunsw(sc);
316 0 : if (target->lunsw == NULL) {
317 0 : printf("%s: can't alloc lunsw for target %d\n",
318 0 : sc->sc_c.sc_dev.dv_xname, i);
319 0 : break;
320 : }
321 0 : siop_add_reselsw(sc, i);
322 0 : }
323 :
324 : /* start script */
325 0 : if ((sc->sc_c.features & SF_CHIP_RAM) == 0) {
326 0 : bus_dmamap_sync(sc->sc_c.sc_dmat, sc->sc_c.sc_scriptdma, 0,
327 : PAGE_SIZE, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
328 0 : }
329 0 : bus_space_write_4(sc->sc_c.sc_rt, sc->sc_c.sc_rh, SIOP_DSP,
330 : sc->sc_c.sc_scriptaddr + Ent_reselect);
331 0 : }
332 :
333 : #if 0
334 : #define CALL_SCRIPT(ent) do {\
335 : printf ("start script DSA 0x%lx DSP 0x%lx\n", \
336 : siop_cmd->cmd_c.dsa, \
337 : sc->sc_c.sc_scriptaddr + ent); \
338 : bus_space_write_4(sc->sc_c.sc_rt, sc->sc_c.sc_rh, SIOP_DSP, sc->sc_c.sc_scriptaddr + ent); \
339 : } while (0)
340 : #else
341 : #define CALL_SCRIPT(ent) do {\
342 : bus_space_write_4(sc->sc_c.sc_rt, sc->sc_c.sc_rh, SIOP_DSP, sc->sc_c.sc_scriptaddr + ent); \
343 : } while (0)
344 : #endif
345 :
346 : int
347 0 : siop_intr(v)
348 : void *v;
349 : {
350 0 : struct siop_softc *sc = v;
351 : struct siop_target *siop_target;
352 : struct siop_cmd *siop_cmd;
353 : struct siop_lun *siop_lun;
354 : struct scsi_xfer *xs;
355 : int istat, sist, sstat1, dstat = 0;
356 : u_int32_t irqcode;
357 : int need_reset = 0;
358 : int offset, target, lun, tag;
359 : bus_addr_t dsa;
360 : struct siop_cbd *cbdp;
361 : int restart = 0;
362 :
363 0 : istat = bus_space_read_1(sc->sc_c.sc_rt, sc->sc_c.sc_rh, SIOP_ISTAT);
364 0 : if ((istat & (ISTAT_INTF | ISTAT_DIP | ISTAT_SIP)) == 0)
365 0 : return 0;
366 : INCSTAT(siop_stat_intr);
367 0 : if (istat & ISTAT_INTF) {
368 0 : printf("INTRF\n");
369 0 : bus_space_write_1(sc->sc_c.sc_rt, sc->sc_c.sc_rh,
370 : SIOP_ISTAT, ISTAT_INTF);
371 0 : }
372 0 : if ((istat &(ISTAT_DIP | ISTAT_SIP | ISTAT_ABRT)) ==
373 : (ISTAT_DIP | ISTAT_ABRT)) {
374 : /* clear abort */
375 0 : bus_space_write_1(sc->sc_c.sc_rt, sc->sc_c.sc_rh,
376 : SIOP_ISTAT, 0);
377 0 : }
378 : /* use DSA to find the current siop_cmd */
379 : siop_cmd = NULL;
380 0 : dsa = bus_space_read_4(sc->sc_c.sc_rt, sc->sc_c.sc_rh, SIOP_DSA);
381 0 : TAILQ_FOREACH(cbdp, &sc->cmds, next) {
382 0 : if (dsa >= SIOP_DMA_DVA(cbdp->xfers) &&
383 0 : dsa < SIOP_DMA_DVA(cbdp->xfers) + PAGE_SIZE) {
384 0 : dsa -= SIOP_DMA_DVA(cbdp->xfers);
385 0 : siop_cmd = &cbdp->cmds[dsa / sizeof(struct siop_xfer)];
386 0 : siop_table_sync(siop_cmd,
387 : BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
388 0 : break;
389 : }
390 : }
391 0 : if (siop_cmd) {
392 0 : xs = siop_cmd->cmd_c.xs;
393 0 : siop_target = (struct siop_target *)siop_cmd->cmd_c.siop_target;
394 0 : target = siop_cmd->cmd_c.xs->sc_link->target;
395 0 : lun = siop_cmd->cmd_c.xs->sc_link->lun;
396 0 : tag = siop_cmd->cmd_c.tag;
397 0 : siop_lun = siop_target->siop_lun[lun];
398 : #ifdef DIAGNOSTIC
399 0 : if (siop_cmd->cmd_c.status != CMDST_ACTIVE &&
400 0 : siop_cmd->cmd_c.status != CMDST_SENSE_ACTIVE) {
401 0 : printf("siop_cmd (lun %d) for DSA 0x%x "
402 0 : "not active (%d)\n", lun, (u_int)dsa,
403 : siop_cmd->cmd_c.status);
404 : xs = NULL;
405 : siop_target = NULL;
406 : target = -1;
407 : lun = -1;
408 : tag = -1;
409 : siop_lun = NULL;
410 : siop_cmd = NULL;
411 0 : } else if (siop_lun->siop_tag[tag].active != siop_cmd) {
412 0 : printf("siop_cmd (lun %d tag %d) not in siop_lun "
413 : "active (%p != %p)\n", lun, tag, siop_cmd,
414 : siop_lun->siop_tag[tag].active);
415 0 : }
416 : #endif
417 : } else {
418 : xs = NULL;
419 : siop_target = NULL;
420 : target = -1;
421 : lun = -1;
422 : tag = -1;
423 : siop_lun = NULL;
424 : }
425 0 : if (istat & ISTAT_DIP) {
426 0 : dstat = bus_space_read_1(sc->sc_c.sc_rt, sc->sc_c.sc_rh,
427 : SIOP_DSTAT);
428 0 : if (dstat & DSTAT_ABRT) {
429 : /* was probably generated by a bus reset IOCTL */
430 0 : if ((dstat & DSTAT_DFE) == 0)
431 0 : siop_clearfifo(&sc->sc_c);
432 : goto reset;
433 : }
434 0 : if (dstat & DSTAT_SSI) {
435 0 : printf("single step dsp 0x%08x dsa 0x08%x\n",
436 0 : (int)(bus_space_read_4(sc->sc_c.sc_rt,
437 0 : sc->sc_c.sc_rh, SIOP_DSP) -
438 0 : sc->sc_c.sc_scriptaddr),
439 0 : bus_space_read_4(sc->sc_c.sc_rt, sc->sc_c.sc_rh,
440 : SIOP_DSA));
441 0 : if ((dstat & ~(DSTAT_DFE | DSTAT_SSI)) == 0 &&
442 0 : (istat & ISTAT_SIP) == 0) {
443 0 : bus_space_write_1(sc->sc_c.sc_rt,
444 : sc->sc_c.sc_rh, SIOP_DCNTL,
445 : bus_space_read_1(sc->sc_c.sc_rt,
446 : sc->sc_c.sc_rh, SIOP_DCNTL) | DCNTL_STD);
447 0 : }
448 0 : return 1;
449 : }
450 :
451 0 : if (dstat & ~(DSTAT_SIR | DSTAT_DFE | DSTAT_SSI)) {
452 0 : printf("%s: DMA IRQ:", sc->sc_c.sc_dev.dv_xname);
453 0 : if (dstat & DSTAT_IID)
454 0 : printf(" illegal instruction");
455 0 : if (dstat & DSTAT_BF)
456 0 : printf(" bus fault");
457 0 : if (dstat & DSTAT_MDPE)
458 0 : printf(" parity");
459 0 : if (dstat & DSTAT_DFE)
460 0 : printf(" DMA fifo empty");
461 : else
462 0 : siop_clearfifo(&sc->sc_c);
463 0 : printf(", DSP=0x%x DSA=0x%x: ",
464 0 : (int)(bus_space_read_4(sc->sc_c.sc_rt, sc->sc_c.sc_rh,
465 0 : SIOP_DSP) - sc->sc_c.sc_scriptaddr),
466 0 : bus_space_read_4(sc->sc_c.sc_rt, sc->sc_c.sc_rh, SIOP_DSA));
467 0 : if (siop_cmd)
468 0 : printf("last msg_in=0x%x status=0x%x\n",
469 0 : siop_cmd->cmd_tables->msg_in[0],
470 0 : siop_ctoh32(&sc->sc_c,
471 : siop_cmd->cmd_tables->status));
472 : else
473 0 : printf("current DSA invalid\n");
474 : need_reset = 1;
475 0 : }
476 : }
477 0 : if (istat & ISTAT_SIP) {
478 0 : if (istat & ISTAT_DIP)
479 0 : delay(10);
480 : /*
481 : * Can't read sist0 & sist1 independently, or we have to
482 : * insert delay
483 : */
484 0 : sist = bus_space_read_2(sc->sc_c.sc_rt, sc->sc_c.sc_rh,
485 : SIOP_SIST0);
486 0 : sstat1 = bus_space_read_1(sc->sc_c.sc_rt, sc->sc_c.sc_rh,
487 : SIOP_SSTAT1);
488 : #ifdef SIOP_DEBUG_INTR
489 : printf("scsi interrupt, sist=0x%x sstat1=0x%x "
490 : "DSA=0x%x DSP=0x%lx\n", sist, sstat1,
491 : bus_space_read_4(sc->sc_c.sc_rt, sc->sc_c.sc_rh, SIOP_DSA),
492 : (u_long)(bus_space_read_4(sc->sc_c.sc_rt, sc->sc_c.sc_rh,
493 : SIOP_DSP) -
494 : sc->sc_c.sc_scriptaddr));
495 : #endif
496 0 : if (sist & SIST0_RST) {
497 0 : siop_handle_reset(sc);
498 0 : siop_start(sc);
499 : /* no table to flush here */
500 0 : return 1;
501 : }
502 0 : if (sist & SIST0_SGE) {
503 0 : if (siop_cmd)
504 0 : sc_print_addr(xs->sc_link);
505 : else
506 0 : printf("%s: ", sc->sc_c.sc_dev.dv_xname);
507 0 : printf("scsi gross error\n");
508 0 : goto reset;
509 : }
510 0 : if ((sist & SIST0_MA) && need_reset == 0) {
511 0 : if (siop_cmd) {
512 : int scratcha0;
513 : /* XXX Why read DSTAT again? */
514 0 : dstat = bus_space_read_1(sc->sc_c.sc_rt,
515 : sc->sc_c.sc_rh, SIOP_DSTAT);
516 : /*
517 : * first restore DSA, in case we were in a S/G
518 : * operation.
519 : */
520 0 : bus_space_write_4(sc->sc_c.sc_rt,
521 : sc->sc_c.sc_rh,
522 : SIOP_DSA, siop_cmd->cmd_c.dsa);
523 0 : scratcha0 = bus_space_read_1(sc->sc_c.sc_rt,
524 : sc->sc_c.sc_rh, SIOP_SCRATCHA);
525 0 : switch (sstat1 & SSTAT1_PHASE_MASK) {
526 : case SSTAT1_PHASE_STATUS:
527 : /*
528 : * previous phase may be aborted for any reason
529 : * ( for example, the target has less data to
530 : * transfer than requested). Compute resid and
531 : * just go to status, the command should
532 : * terminate.
533 : */
534 : INCSTAT(siop_stat_intr_shortxfer);
535 0 : if (scratcha0 & A_flag_data)
536 0 : siop_ma(&siop_cmd->cmd_c);
537 0 : else if ((dstat & DSTAT_DFE) == 0)
538 0 : siop_clearfifo(&sc->sc_c);
539 0 : CALL_SCRIPT(Ent_status);
540 0 : return 1;
541 : case SSTAT1_PHASE_MSGIN:
542 : /*
543 : * target may be ready to disconnect
544 : * Compute resid which would be used later
545 : * if a save data pointer is needed.
546 : */
547 : INCSTAT(siop_stat_intr_xferdisc);
548 0 : if (scratcha0 & A_flag_data)
549 0 : siop_ma(&siop_cmd->cmd_c);
550 0 : else if ((dstat & DSTAT_DFE) == 0)
551 0 : siop_clearfifo(&sc->sc_c);
552 0 : bus_space_write_1(sc->sc_c.sc_rt,
553 : sc->sc_c.sc_rh, SIOP_SCRATCHA,
554 : scratcha0 & ~A_flag_data);
555 0 : CALL_SCRIPT(Ent_msgin);
556 0 : return 1;
557 : }
558 0 : printf("%s: unexpected phase mismatch %d\n",
559 0 : sc->sc_c.sc_dev.dv_xname,
560 : sstat1 & SSTAT1_PHASE_MASK);
561 0 : } else {
562 0 : printf("%s: phase mismatch without command\n",
563 0 : sc->sc_c.sc_dev.dv_xname);
564 : }
565 : need_reset = 1;
566 0 : }
567 0 : if (sist & SIST0_PAR) {
568 : /* parity error, reset */
569 0 : if (siop_cmd)
570 0 : sc_print_addr(xs->sc_link);
571 : else
572 0 : printf("%s: ", sc->sc_c.sc_dev.dv_xname);
573 0 : printf("parity error\n");
574 0 : goto reset;
575 : }
576 0 : if ((sist & (SIST1_STO << 8)) && need_reset == 0) {
577 : /* selection time out, assume there's no device here */
578 0 : if (siop_cmd) {
579 0 : siop_cmd->cmd_c.status = CMDST_DONE;
580 0 : xs->error = XS_SELTIMEOUT;
581 0 : goto end;
582 : } else {
583 0 : printf("%s: selection timeout without "
584 0 : "command\n", sc->sc_c.sc_dev.dv_xname);
585 : need_reset = 1;
586 : }
587 0 : }
588 0 : if (sist & SIST0_UDC) {
589 : /*
590 : * unexpected disconnect. Usually the target signals
591 : * a fatal condition this way. Attempt to get sense.
592 : */
593 0 : if (siop_cmd) {
594 0 : siop_cmd->cmd_tables->status =
595 0 : siop_htoc32(&sc->sc_c, SCSI_CHECK);
596 0 : goto end;
597 : }
598 0 : printf("%s: unexpected disconnect without "
599 0 : "command\n", sc->sc_c.sc_dev.dv_xname);
600 0 : goto reset;
601 : }
602 0 : if (sist & (SIST1_SBMC << 8)) {
603 : /* SCSI bus mode change */
604 0 : if (siop_modechange(&sc->sc_c) == 0 || need_reset == 1)
605 : goto reset;
606 0 : if ((istat & ISTAT_DIP) && (dstat & DSTAT_SIR)) {
607 : /*
608 : * we have a script interrupt, it will
609 : * restart the script.
610 : */
611 : goto scintr;
612 : }
613 : /*
614 : * else we have to restart it ourselve, at the
615 : * interrupted instruction.
616 : */
617 0 : bus_space_write_4(sc->sc_c.sc_rt, sc->sc_c.sc_rh,
618 : SIOP_DSP,
619 : bus_space_read_4(sc->sc_c.sc_rt, sc->sc_c.sc_rh,
620 : SIOP_DSP) - 8);
621 0 : return 1;
622 : }
623 : /* Else it's an unhandled exception (for now). */
624 0 : printf("%s: unhandled scsi interrupt, sist=0x%x sstat1=0x%x "
625 0 : "DSA=0x%x DSP=0x%x\n", sc->sc_c.sc_dev.dv_xname,
626 : sist, sstat1,
627 0 : bus_space_read_4(sc->sc_c.sc_rt, sc->sc_c.sc_rh, SIOP_DSA),
628 0 : (int)(bus_space_read_4(sc->sc_c.sc_rt, sc->sc_c.sc_rh,
629 0 : SIOP_DSP) - sc->sc_c.sc_scriptaddr));
630 0 : if (siop_cmd) {
631 0 : siop_cmd->cmd_c.status = CMDST_DONE;
632 0 : xs->error = XS_SELTIMEOUT;
633 0 : goto end;
634 : }
635 : need_reset = 1;
636 0 : } else {
637 : sist = sstat1 = 0;
638 : }
639 0 : if (need_reset) {
640 : reset:
641 : /* fatal error, reset the bus */
642 0 : siop_resetbus(&sc->sc_c);
643 : /* no table to flush here */
644 0 : return 1;
645 : }
646 :
647 : scintr:
648 0 : if ((istat & ISTAT_DIP) && (dstat & DSTAT_SIR)) { /* script interrupt */
649 0 : irqcode = bus_space_read_4(sc->sc_c.sc_rt, sc->sc_c.sc_rh,
650 : SIOP_DSPS);
651 : #ifdef SIOP_DEBUG_INTR
652 : printf("script interrupt 0x%x\n", irqcode);
653 : #endif
654 : /*
655 : * no command, or an inactive command is only valid for a
656 : * reselect interrupt
657 : */
658 0 : if ((irqcode & 0x80) == 0) {
659 0 : if (siop_cmd == NULL) {
660 0 : printf(
661 : "%s: script interrupt (0x%x) with invalid DSA !!!\n",
662 0 : sc->sc_c.sc_dev.dv_xname, irqcode);
663 0 : goto reset;
664 : }
665 0 : if (siop_cmd->cmd_c.status != CMDST_ACTIVE &&
666 0 : siop_cmd->cmd_c.status != CMDST_SENSE_ACTIVE) {
667 0 : printf("%s: command with invalid status "
668 : "(IRQ code 0x%x current status %d) !\n",
669 0 : sc->sc_c.sc_dev.dv_xname,
670 : irqcode, siop_cmd->cmd_c.status);
671 : xs = NULL;
672 0 : }
673 : }
674 0 : switch(irqcode) {
675 : case A_int_err:
676 0 : printf("error, DSP=0x%x\n",
677 0 : (int)(bus_space_read_4(sc->sc_c.sc_rt,
678 0 : sc->sc_c.sc_rh, SIOP_DSP) - sc->sc_c.sc_scriptaddr));
679 0 : if (xs) {
680 0 : xs->error = XS_SELTIMEOUT;
681 0 : goto end;
682 : } else {
683 : goto reset;
684 : }
685 : case A_int_reseltarg:
686 0 : printf("%s: reselect with invalid target\n",
687 0 : sc->sc_c.sc_dev.dv_xname);
688 0 : goto reset;
689 : case A_int_resellun:
690 : INCSTAT(siop_stat_intr_lunresel);
691 0 : target = bus_space_read_1(sc->sc_c.sc_rt,
692 0 : sc->sc_c.sc_rh, SIOP_SCRATCHA) & 0xf;
693 0 : lun = bus_space_read_1(sc->sc_c.sc_rt, sc->sc_c.sc_rh,
694 : SIOP_SCRATCHA + 1);
695 0 : tag = bus_space_read_1(sc->sc_c.sc_rt, sc->sc_c.sc_rh,
696 : SIOP_SCRATCHA + 2);
697 : siop_target =
698 0 : (struct siop_target *)sc->sc_c.targets[target];
699 0 : if (siop_target == NULL) {
700 0 : printf("%s: reselect with invalid target %d\n",
701 0 : sc->sc_c.sc_dev.dv_xname, target);
702 0 : goto reset;
703 : }
704 0 : siop_lun = siop_target->siop_lun[lun];
705 0 : if (siop_lun == NULL) {
706 0 : printf("%s: target %d reselect with invalid "
707 0 : "lun %d\n", sc->sc_c.sc_dev.dv_xname,
708 : target, lun);
709 0 : goto reset;
710 : }
711 0 : if (siop_lun->siop_tag[tag].active == NULL) {
712 0 : printf("%s: target %d lun %d tag %d reselect "
713 : "without command\n",
714 0 : sc->sc_c.sc_dev.dv_xname,
715 : target, lun, tag);
716 0 : goto reset;
717 : }
718 : siop_cmd = siop_lun->siop_tag[tag].active;
719 0 : bus_space_write_4(sc->sc_c.sc_rt, sc->sc_c.sc_rh,
720 : SIOP_DSP, siop_cmd->cmd_c.dsa +
721 : sizeof(struct siop_common_xfer) +
722 : Ent_ldsa_reload_dsa);
723 0 : siop_table_sync(siop_cmd, BUS_DMASYNC_PREWRITE);
724 0 : return 1;
725 : case A_int_reseltag:
726 0 : printf("%s: reselect with invalid tag\n",
727 0 : sc->sc_c.sc_dev.dv_xname);
728 0 : goto reset;
729 : case A_int_msgin:
730 : {
731 0 : int msgin = bus_space_read_1(sc->sc_c.sc_rt,
732 : sc->sc_c.sc_rh, SIOP_SFBR);
733 0 : if (msgin == MSG_MESSAGE_REJECT) {
734 : int msg, extmsg;
735 0 : if (siop_cmd->cmd_tables->msg_out[0] & 0x80) {
736 : /*
737 : * message was part of a identify +
738 : * something else. Identify shouldn't
739 : * have been rejected.
740 : */
741 : msg =
742 0 : siop_cmd->cmd_tables->msg_out[1];
743 : extmsg =
744 0 : siop_cmd->cmd_tables->msg_out[3];
745 0 : } else {
746 : msg = siop_cmd->cmd_tables->msg_out[0];
747 : extmsg =
748 0 : siop_cmd->cmd_tables->msg_out[2];
749 : }
750 0 : if (msg == MSG_MESSAGE_REJECT) {
751 : /* MSG_REJECT for a MSG_REJECT !*/
752 0 : if (xs)
753 0 : sc_print_addr(xs->sc_link);
754 : else
755 0 : printf("%s: ",
756 0 : sc->sc_c.sc_dev.dv_xname);
757 0 : printf("our reject message was "
758 : "rejected\n");
759 0 : goto reset;
760 : }
761 0 : if (msg == MSG_EXTENDED &&
762 0 : extmsg == MSG_EXT_WDTR) {
763 : /* WDTR rejected, initiate sync */
764 0 : if ((siop_target->target_c.flags &
765 0 : TARF_SYNC) == 0) {
766 0 : siop_target->target_c.status =
767 : TARST_OK;
768 0 : siop_update_xfer_mode(&sc->sc_c,
769 : target);
770 : /* no table to flush here */
771 0 : CALL_SCRIPT(Ent_msgin_ack);
772 0 : return 1;
773 : }
774 0 : siop_target->target_c.status =
775 : TARST_SYNC_NEG;
776 0 : siop_sdtr_msg(&siop_cmd->cmd_c, 0,
777 0 : sc->sc_c.st_minsync,
778 0 : sc->sc_c.maxoff);
779 0 : siop_table_sync(siop_cmd,
780 : BUS_DMASYNC_PREREAD |
781 : BUS_DMASYNC_PREWRITE);
782 0 : CALL_SCRIPT(Ent_send_msgout);
783 0 : return 1;
784 0 : } else if (msg == MSG_EXTENDED &&
785 0 : extmsg == MSG_EXT_SDTR) {
786 : /* sync rejected */
787 0 : siop_target->target_c.offset = 0;
788 0 : siop_target->target_c.period = 0;
789 0 : siop_target->target_c.status = TARST_OK;
790 0 : siop_update_xfer_mode(&sc->sc_c,
791 : target);
792 : /* no table to flush here */
793 0 : CALL_SCRIPT(Ent_msgin_ack);
794 0 : return 1;
795 0 : } else if (msg == MSG_EXTENDED &&
796 0 : extmsg == MSG_EXT_PPR) {
797 : /* PPR negotiation rejected */
798 0 : siop_target->target_c.offset = 0;
799 0 : siop_target->target_c.period = 0;
800 0 : siop_target->target_c.status = TARST_ASYNC;
801 0 : siop_target->target_c.flags &= ~(TARF_DT | TARF_ISDT);
802 0 : CALL_SCRIPT(Ent_msgin_ack);
803 0 : return 1;
804 0 : } else if (msg == MSG_SIMPLE_Q_TAG ||
805 0 : msg == MSG_HEAD_OF_Q_TAG ||
806 0 : msg == MSG_ORDERED_Q_TAG) {
807 0 : if (siop_handle_qtag_reject(
808 0 : siop_cmd) == -1)
809 0 : goto reset;
810 0 : CALL_SCRIPT(Ent_msgin_ack);
811 0 : return 1;
812 : }
813 0 : if (xs)
814 0 : sc_print_addr(xs->sc_link);
815 : else
816 0 : printf("%s: ",
817 0 : sc->sc_c.sc_dev.dv_xname);
818 0 : if (msg == MSG_EXTENDED) {
819 0 : printf("scsi message reject, extended "
820 : "message sent was 0x%x\n", extmsg);
821 0 : } else {
822 0 : printf("scsi message reject, message "
823 : "sent was 0x%x\n", msg);
824 : }
825 : /* no table to flush here */
826 0 : CALL_SCRIPT(Ent_msgin_ack);
827 0 : return 1;
828 : }
829 0 : if (msgin == MSG_IGN_WIDE_RESIDUE) {
830 : /* use the extmsgdata table to get the second byte */
831 0 : siop_cmd->cmd_tables->t_extmsgdata.count =
832 0 : siop_htoc32(&sc->sc_c, 1);
833 0 : siop_table_sync(siop_cmd,
834 : BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
835 0 : CALL_SCRIPT(Ent_get_extmsgdata);
836 0 : return 1;
837 : }
838 0 : if (xs)
839 0 : sc_print_addr(xs->sc_link);
840 : else
841 0 : printf("%s: ", sc->sc_c.sc_dev.dv_xname);
842 0 : printf("unhandled message 0x%x\n",
843 0 : siop_cmd->cmd_tables->msg_in[0]);
844 0 : siop_cmd->cmd_tables->msg_out[0] = MSG_MESSAGE_REJECT;
845 0 : siop_cmd->cmd_tables->t_msgout.count =
846 0 : siop_htoc32(&sc->sc_c, 1);
847 0 : siop_table_sync(siop_cmd,
848 : BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
849 0 : CALL_SCRIPT(Ent_send_msgout);
850 0 : return 1;
851 : }
852 : case A_int_extmsgin:
853 : #ifdef SIOP_DEBUG_INTR
854 : printf("extended message: msg 0x%x len %d\n",
855 : siop_cmd->cmd_tables->msg_in[2],
856 : siop_cmd->cmd_tables->msg_in[1]);
857 : #endif
858 0 : if (siop_cmd->cmd_tables->msg_in[1] >
859 : sizeof(siop_cmd->cmd_tables->msg_in) - 2)
860 0 : printf("%s: extended message too big (%d)\n",
861 0 : sc->sc_c.sc_dev.dv_xname,
862 0 : siop_cmd->cmd_tables->msg_in[1]);
863 0 : siop_cmd->cmd_tables->t_extmsgdata.count =
864 0 : siop_htoc32(&sc->sc_c,
865 : siop_cmd->cmd_tables->msg_in[1] - 1);
866 0 : siop_table_sync(siop_cmd,
867 : BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
868 0 : CALL_SCRIPT(Ent_get_extmsgdata);
869 0 : return 1;
870 : case A_int_extmsgdata:
871 : #ifdef SIOP_DEBUG_INTR
872 : {
873 : int i;
874 : printf("extended message: 0x%x, data:",
875 : siop_cmd->cmd_tables->msg_in[2]);
876 : for (i = 3; i < 2 + siop_cmd->cmd_tables->msg_in[1];
877 : i++)
878 : printf(" 0x%x",
879 : siop_cmd->cmd_tables->msg_in[i]);
880 : printf("\n");
881 : }
882 : #endif
883 0 : if (siop_cmd->cmd_tables->msg_in[0] ==
884 : MSG_IGN_WIDE_RESIDUE) {
885 : /* we got the second byte of MSG_IGN_WIDE_RESIDUE */
886 0 : if (siop_cmd->cmd_tables->msg_in[3] != 1)
887 0 : printf("MSG_IGN_WIDE_RESIDUE: "
888 : "bad len %d\n",
889 : siop_cmd->cmd_tables->msg_in[3]);
890 0 : switch (siop_iwr(&siop_cmd->cmd_c)) {
891 : case SIOP_NEG_MSGOUT:
892 0 : siop_table_sync(siop_cmd,
893 : BUS_DMASYNC_PREREAD |
894 : BUS_DMASYNC_PREWRITE);
895 0 : CALL_SCRIPT(Ent_send_msgout);
896 0 : return(1);
897 : case SIOP_NEG_ACK:
898 0 : CALL_SCRIPT(Ent_msgin_ack);
899 0 : return(1);
900 : default:
901 0 : panic("invalid retval from "
902 : "siop_iwr()");
903 : }
904 : return(1);
905 : }
906 0 : if (siop_cmd->cmd_tables->msg_in[2] == MSG_EXT_WDTR) {
907 0 : switch (siop_wdtr_neg(&siop_cmd->cmd_c)) {
908 : case SIOP_NEG_MSGOUT:
909 0 : siop_update_scntl3(sc,
910 0 : siop_cmd->cmd_c.siop_target);
911 0 : siop_table_sync(siop_cmd,
912 : BUS_DMASYNC_PREREAD |
913 : BUS_DMASYNC_PREWRITE);
914 0 : CALL_SCRIPT(Ent_send_msgout);
915 0 : return(1);
916 : case SIOP_NEG_ACK:
917 0 : siop_update_scntl3(sc,
918 0 : siop_cmd->cmd_c.siop_target);
919 0 : CALL_SCRIPT(Ent_msgin_ack);
920 0 : return(1);
921 : default:
922 0 : panic("invalid retval from "
923 : "siop_wdtr_neg()");
924 : }
925 : return(1);
926 : }
927 0 : if (siop_cmd->cmd_tables->msg_in[2] == MSG_EXT_SDTR) {
928 0 : switch (siop_sdtr_neg(&siop_cmd->cmd_c)) {
929 : case SIOP_NEG_MSGOUT:
930 0 : siop_update_scntl3(sc,
931 0 : siop_cmd->cmd_c.siop_target);
932 0 : siop_table_sync(siop_cmd,
933 : BUS_DMASYNC_PREREAD |
934 : BUS_DMASYNC_PREWRITE);
935 0 : CALL_SCRIPT(Ent_send_msgout);
936 0 : return(1);
937 : case SIOP_NEG_ACK:
938 0 : siop_update_scntl3(sc,
939 0 : siop_cmd->cmd_c.siop_target);
940 0 : CALL_SCRIPT(Ent_msgin_ack);
941 0 : return(1);
942 : default:
943 0 : panic("invalid retval from "
944 : "siop_sdtr_neg()");
945 : }
946 : return(1);
947 : }
948 0 : if (siop_cmd->cmd_tables->msg_in[2] == MSG_EXT_PPR) {
949 0 : switch (siop_ppr_neg(&siop_cmd->cmd_c)) {
950 : case SIOP_NEG_MSGOUT:
951 0 : siop_update_scntl3(sc,
952 0 : siop_cmd->cmd_c.siop_target);
953 0 : siop_table_sync(siop_cmd,
954 : BUS_DMASYNC_PREREAD |
955 : BUS_DMASYNC_PREWRITE);
956 0 : CALL_SCRIPT(Ent_send_msgout);
957 0 : return(1);
958 : case SIOP_NEG_ACK:
959 0 : siop_update_scntl3(sc,
960 0 : siop_cmd->cmd_c.siop_target);
961 0 : CALL_SCRIPT(Ent_msgin_ack);
962 0 : return(1);
963 : default:
964 0 : panic("invalid retval from "
965 : "siop_wdtr_neg()");
966 : }
967 : return(1);
968 : }
969 : /* send a message reject */
970 0 : siop_cmd->cmd_tables->msg_out[0] = MSG_MESSAGE_REJECT;
971 0 : siop_cmd->cmd_tables->t_msgout.count =
972 0 : siop_htoc32(&sc->sc_c, 1);
973 0 : siop_table_sync(siop_cmd,
974 : BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
975 0 : CALL_SCRIPT(Ent_send_msgout);
976 0 : return 1;
977 : case A_int_disc:
978 : INCSTAT(siop_stat_intr_sdp);
979 0 : offset = bus_space_read_1(sc->sc_c.sc_rt,
980 : sc->sc_c.sc_rh, SIOP_SCRATCHA + 1);
981 : #ifdef SIOP_DEBUG_DR
982 : printf("disconnect offset %d\n", offset);
983 : #endif
984 0 : siop_sdp(&siop_cmd->cmd_c, offset);
985 : /* we start again with no offset */
986 0 : siop_cmd->saved_offset = SIOP_NOOFFSET;
987 0 : siop_table_sync(siop_cmd,
988 : BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
989 0 : CALL_SCRIPT(Ent_script_sched);
990 0 : return 1;
991 : case A_int_saveoffset:
992 : INCSTAT(siop_stat_intr_saveoffset);
993 0 : offset = bus_space_read_1(sc->sc_c.sc_rt,
994 : sc->sc_c.sc_rh, SIOP_SCRATCHA + 1);
995 : #ifdef SIOP_DEBUG_DR
996 : printf("saveoffset offset %d\n", offset);
997 : #endif
998 0 : siop_cmd->saved_offset = offset;
999 0 : CALL_SCRIPT(Ent_script_sched);
1000 0 : return 1;
1001 : case A_int_resfail:
1002 0 : printf("reselect failed\n");
1003 : /* check if we can put some command in scheduler */
1004 0 : siop_start(sc);
1005 0 : CALL_SCRIPT(Ent_script_sched);
1006 0 : return 1;
1007 : case A_int_done:
1008 0 : if (xs == NULL) {
1009 0 : printf("%s: done without command, DSA=0x%lx\n",
1010 0 : sc->sc_c.sc_dev.dv_xname,
1011 0 : (u_long)siop_cmd->cmd_c.dsa);
1012 0 : siop_cmd->cmd_c.status = CMDST_FREE;
1013 0 : siop_start(sc);
1014 0 : CALL_SCRIPT(Ent_script_sched);
1015 0 : return 1;
1016 : }
1017 : #ifdef SIOP_DEBUG_INTR
1018 : printf("done, DSA=0x%lx target id 0x%x last msg "
1019 : "in=0x%x status=0x%x\n", (u_long)siop_cmd->cmd_c.dsa,
1020 : siop_ctoh32(&sc->sc_c, siop_cmd->cmd_tables->id),
1021 : siop_cmd->cmd_tables->msg_in[0],
1022 : siop_ctoh32(&sc->sc_c,
1023 : siop_cmd->cmd_tables->status));
1024 : #endif
1025 : INCSTAT(siop_stat_intr_done);
1026 : /* update resid. */
1027 0 : offset = bus_space_read_1(sc->sc_c.sc_rt,
1028 : sc->sc_c.sc_rh, SIOP_SCRATCHA + 1);
1029 : /*
1030 : * if we got a disconnect between the last data phase
1031 : * and the status phase, offset will be 0. In this
1032 : * case, siop_cmd->saved_offset will have the proper
1033 : * value if it got updated by the controller
1034 : */
1035 0 : if (offset == 0 &&
1036 0 : siop_cmd->saved_offset != SIOP_NOOFFSET)
1037 0 : offset = siop_cmd->saved_offset;
1038 0 : siop_update_resid(&siop_cmd->cmd_c, offset);
1039 0 : if (siop_cmd->cmd_c.status == CMDST_SENSE_ACTIVE)
1040 0 : siop_cmd->cmd_c.status = CMDST_SENSE_DONE;
1041 : else
1042 0 : siop_cmd->cmd_c.status = CMDST_DONE;
1043 : goto end;
1044 : default:
1045 0 : printf("unknown irqcode %x\n", irqcode);
1046 0 : if (xs) {
1047 0 : xs->error = XS_SELTIMEOUT;
1048 0 : goto end;
1049 : }
1050 : goto reset;
1051 : }
1052 : return 1;
1053 : } else
1054 : irqcode = 0;
1055 : /* We can get here if ISTAT_DIP and DSTAT_DFE are the only bits set. */
1056 : /* But that *SHOULDN'T* happen. It does on powerpc (at least). */
1057 0 : printf("%s: siop_intr() - we should not be here!\n"
1058 : " istat = 0x%x, dstat = 0x%x, sist = 0x%x, sstat1 = 0x%x\n"
1059 : " need_reset = %x, irqcode = %x, siop_cmd %s\n",
1060 0 : sc->sc_c.sc_dev.dv_xname,
1061 : istat, dstat, sist, sstat1, need_reset, irqcode,
1062 0 : (siop_cmd == NULL) ? "== NULL" : "!= NULL");
1063 0 : goto reset; /* Where we should have gone in the first place! */
1064 : end:
1065 : /*
1066 : * restart the script now if command completed properly
1067 : * Otherwise wait for siop_scsicmd_end(), we may need to cleanup the
1068 : * queue
1069 : */
1070 0 : xs->status = siop_ctoh32(&sc->sc_c, siop_cmd->cmd_tables->status);
1071 0 : if (xs->status == SCSI_OK)
1072 0 : CALL_SCRIPT(Ent_script_sched);
1073 : else
1074 : restart = 1;
1075 0 : siop_lun->siop_tag[tag].active = NULL;
1076 0 : siop_scsicmd_end(siop_cmd);
1077 0 : siop_start(sc);
1078 0 : if (restart)
1079 0 : CALL_SCRIPT(Ent_script_sched);
1080 0 : return 1;
1081 0 : }
1082 :
1083 : void
1084 0 : siop_scsicmd_end(siop_cmd)
1085 : struct siop_cmd *siop_cmd;
1086 : {
1087 0 : struct scsi_xfer *xs = siop_cmd->cmd_c.xs;
1088 0 : struct siop_softc *sc = (struct siop_softc *)siop_cmd->cmd_c.siop_sc;
1089 : struct siop_lun *siop_lun =
1090 0 : ((struct siop_target*)sc->sc_c.targets[xs->sc_link->target])->siop_lun[xs->sc_link->lun];
1091 :
1092 : /*
1093 : * If the command is re-queued (SENSE, QUEUE_FULL) it
1094 : * must get a new timeout, so delete existing timeout now.
1095 : */
1096 0 : timeout_del(&siop_cmd->cmd_c.xs->stimeout);
1097 :
1098 0 : switch(xs->status) {
1099 : case SCSI_OK:
1100 0 : xs->error = (siop_cmd->cmd_c.status == CMDST_DONE) ?
1101 : XS_NOERROR : XS_SENSE;
1102 0 : break;
1103 : case SCSI_BUSY:
1104 0 : xs->error = XS_BUSY;
1105 0 : break;
1106 : case SCSI_CHECK:
1107 0 : if (siop_cmd->cmd_c.status == CMDST_SENSE_DONE) {
1108 : /* request sense on a request sense ? */
1109 0 : printf("%s: request sense failed\n",
1110 0 : sc->sc_c.sc_dev.dv_xname);
1111 0 : xs->error = XS_DRIVER_STUFFUP;
1112 0 : } else {
1113 0 : siop_cmd->cmd_c.status = CMDST_SENSE;
1114 : }
1115 : break;
1116 : case SCSI_QUEUE_FULL:
1117 : /*
1118 : * Device didn't queue the command. We have to retry
1119 : * it. We insert it into the urgent list, hoping to
1120 : * preserve order. But unfortunately, commands already
1121 : * in the scheduler may be accepted before this one.
1122 : * Also remember the condition, to avoid starting new
1123 : * commands for this device before one is done.
1124 : */
1125 : INCSTAT(siop_stat_intr_qfull);
1126 : #ifdef SIOP_DEBUG
1127 : printf("%s:%d:%d: queue full (tag %d)\n", sc->sc_c.sc_dev.dv_xname,
1128 : xs->sc_link->target,
1129 : xs->sc_link->lun, siop_cmd->cmd_c.tag);
1130 : #endif
1131 0 : siop_lun->lun_flags |= SIOP_LUNF_FULL;
1132 0 : siop_cmd->cmd_c.status = CMDST_READY;
1133 0 : siop_setuptables(&siop_cmd->cmd_c);
1134 0 : siop_table_sync(siop_cmd, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1135 0 : TAILQ_INSERT_TAIL(&sc->urgent_list, siop_cmd, next);
1136 0 : return;
1137 : case SCSI_SIOP_NOCHECK:
1138 : /*
1139 : * don't check status, xs->error is already valid
1140 : */
1141 : break;
1142 : case SCSI_SIOP_NOSTATUS:
1143 : /*
1144 : * the status byte was not updated, cmd was
1145 : * aborted
1146 : */
1147 0 : xs->error = XS_SELTIMEOUT;
1148 0 : break;
1149 : default:
1150 0 : xs->error = XS_DRIVER_STUFFUP;
1151 0 : }
1152 0 : if (siop_cmd->cmd_c.status != CMDST_SENSE_DONE &&
1153 0 : xs->flags & (SCSI_DATA_IN | SCSI_DATA_OUT)) {
1154 0 : bus_dmamap_sync(sc->sc_c.sc_dmat, siop_cmd->cmd_c.dmamap_data, 0,
1155 : siop_cmd->cmd_c.dmamap_data->dm_mapsize,
1156 : (xs->flags & SCSI_DATA_IN) ?
1157 : BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
1158 0 : bus_dmamap_unload(sc->sc_c.sc_dmat, siop_cmd->cmd_c.dmamap_data);
1159 0 : }
1160 0 : if (siop_cmd->cmd_c.status == CMDST_SENSE) {
1161 : /* issue a request sense for this target */
1162 0 : struct scsi_sense *cmd = (struct scsi_sense *)&siop_cmd->cmd_c.siop_tables->xscmd;
1163 : int error;
1164 0 : bzero(cmd, sizeof(*cmd));
1165 0 : siop_cmd->cmd_c.siop_tables->cmd.count =
1166 0 : siop_htoc32(&sc->sc_c, sizeof(struct scsi_sense));
1167 0 : cmd->opcode = REQUEST_SENSE;
1168 0 : cmd->byte2 = xs->sc_link->lun << 5;
1169 0 : cmd->unused[0] = cmd->unused[1] = 0;
1170 0 : cmd->length = sizeof(struct scsi_sense_data);
1171 0 : cmd->control = 0;
1172 0 : siop_cmd->cmd_c.flags &= ~CMDFL_TAG;
1173 0 : error = bus_dmamap_load(sc->sc_c.sc_dmat,
1174 : siop_cmd->cmd_c.dmamap_data,
1175 : siop_cmd->cmd_c.sense, sizeof(struct scsi_sense_data),
1176 : NULL, BUS_DMA_NOWAIT);
1177 0 : if (error) {
1178 0 : printf("%s: unable to load data DMA map "
1179 : "(for SENSE): %d\n",
1180 0 : sc->sc_c.sc_dev.dv_xname, error);
1181 0 : xs->error = XS_DRIVER_STUFFUP;
1182 0 : goto out;
1183 : }
1184 0 : bus_dmamap_sync(sc->sc_c.sc_dmat, siop_cmd->cmd_c.dmamap_data,
1185 : 0, siop_cmd->cmd_c.dmamap_data->dm_mapsize,
1186 : BUS_DMASYNC_PREREAD);
1187 :
1188 0 : siop_setuptables(&siop_cmd->cmd_c);
1189 0 : siop_table_sync(siop_cmd, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1190 : /* arrange for the cmd to be handled now */
1191 0 : TAILQ_INSERT_HEAD(&sc->urgent_list, siop_cmd, next);
1192 0 : return;
1193 0 : } else if (siop_cmd->cmd_c.status == CMDST_SENSE_DONE) {
1194 0 : bus_dmamap_sync(sc->sc_c.sc_dmat, siop_cmd->cmd_c.dmamap_data,
1195 : 0, siop_cmd->cmd_c.dmamap_data->dm_mapsize,
1196 : BUS_DMASYNC_POSTREAD);
1197 0 : bus_dmamap_unload(sc->sc_c.sc_dmat, siop_cmd->cmd_c.dmamap_data);
1198 0 : bcopy(siop_cmd->cmd_c.sense, &xs->sense, sizeof(xs->sense));
1199 0 : }
1200 : out:
1201 0 : siop_lun->lun_flags &= ~SIOP_LUNF_FULL;
1202 : #if 0
1203 : if (xs->resid != 0)
1204 : printf("resid %d datalen %d\n", xs->resid, xs->datalen);
1205 : #endif
1206 0 : scsi_done(xs);
1207 0 : }
1208 :
1209 : /*
1210 : * handle a rejected queue tag message: the command will run untagged,
1211 : * has to adjust the reselect script.
1212 : */
1213 : int
1214 0 : siop_handle_qtag_reject(siop_cmd)
1215 : struct siop_cmd *siop_cmd;
1216 : {
1217 0 : struct siop_softc *sc = (struct siop_softc *)siop_cmd->cmd_c.siop_sc;
1218 0 : int target = siop_cmd->cmd_c.xs->sc_link->target;
1219 0 : int lun = siop_cmd->cmd_c.xs->sc_link->lun;
1220 0 : int tag = siop_cmd->cmd_tables->msg_out[2];
1221 : struct siop_lun *siop_lun =
1222 0 : ((struct siop_target*)sc->sc_c.targets[target])->siop_lun[lun];
1223 :
1224 : #ifdef SIOP_DEBUG
1225 : printf("%s:%d:%d: tag message %d (%d) rejected (status %d)\n",
1226 : sc->sc_c.sc_dev.dv_xname, target, lun, tag, siop_cmd->cmd_c.tag,
1227 : siop_cmd->cmd_c.status);
1228 : #endif
1229 :
1230 0 : if (siop_lun->siop_tag[0].active != NULL) {
1231 0 : printf("%s: untagged command already running for target %d "
1232 0 : "lun %d (status %d)\n", sc->sc_c.sc_dev.dv_xname,
1233 0 : target, lun, siop_lun->siop_tag[0].active->cmd_c.status);
1234 0 : return -1;
1235 : }
1236 : /* clear tag slot */
1237 0 : siop_lun->siop_tag[tag].active = NULL;
1238 : /* add command to non-tagged slot */
1239 0 : siop_lun->siop_tag[0].active = siop_cmd;
1240 0 : siop_cmd->cmd_c.tag = 0;
1241 : /* adjust reselect script if there is one */
1242 0 : if (siop_lun->siop_tag[0].reseloff > 0) {
1243 0 : siop_script_write(sc,
1244 0 : siop_lun->siop_tag[0].reseloff + 1,
1245 0 : siop_cmd->cmd_c.dsa + sizeof(struct siop_common_xfer) +
1246 : Ent_ldsa_reload_dsa);
1247 0 : siop_table_sync(siop_cmd, BUS_DMASYNC_PREWRITE);
1248 0 : }
1249 0 : return 0;
1250 0 : }
1251 :
1252 : /*
1253 : * handle a bus reset: reset chip, unqueue all active commands, free all
1254 : * target struct and report lossage to upper layer.
1255 : * As the upper layer may requeue immediately we have to first store
1256 : * all active commands in a temporary queue.
1257 : */
1258 : void
1259 0 : siop_handle_reset(sc)
1260 : struct siop_softc *sc;
1261 : {
1262 0 : struct cmd_list reset_list;
1263 : struct siop_cmd *siop_cmd, *next_siop_cmd;
1264 : struct siop_lun *siop_lun;
1265 : int target, lun, tag;
1266 : /*
1267 : * scsi bus reset. reset the chip and restart
1268 : * the queue. Need to clean up all active commands
1269 : */
1270 0 : printf("%s: scsi bus reset\n", sc->sc_c.sc_dev.dv_xname);
1271 : /* stop, reset and restart the chip */
1272 0 : siop_reset(sc);
1273 0 : TAILQ_INIT(&reset_list);
1274 : /*
1275 : * Process all commands: first commands being executed
1276 : */
1277 0 : for (target = 0; target < sc->sc_c.sc_link.adapter_buswidth;
1278 0 : target++) {
1279 0 : if (sc->sc_c.targets[target] == NULL)
1280 : continue;
1281 0 : for (lun = 0; lun < 8; lun++) {
1282 : struct siop_target *siop_target =
1283 0 : (struct siop_target *)sc->sc_c.targets[target];
1284 0 : siop_lun = siop_target->siop_lun[lun];
1285 0 : if (siop_lun == NULL)
1286 0 : continue;
1287 0 : siop_lun->lun_flags &= ~SIOP_LUNF_FULL;
1288 0 : for (tag = 0; tag <
1289 0 : ((sc->sc_c.targets[target]->flags & TARF_TAG) ?
1290 : SIOP_NTAG : 1);
1291 0 : tag++) {
1292 0 : siop_cmd = siop_lun->siop_tag[tag].active;
1293 0 : if (siop_cmd == NULL)
1294 : continue;
1295 0 : siop_lun->siop_tag[tag].active = NULL;
1296 0 : TAILQ_INSERT_TAIL(&reset_list, siop_cmd, next);
1297 0 : sc_print_addr(siop_cmd->cmd_c.xs->sc_link);
1298 0 : printf("cmd %p (tag %d) added to reset list\n",
1299 : siop_cmd, tag);
1300 0 : }
1301 0 : }
1302 0 : if (sc->sc_c.targets[target]->status != TARST_PROBING) {
1303 0 : sc->sc_c.targets[target]->status = TARST_ASYNC;
1304 0 : sc->sc_c.targets[target]->flags &= ~TARF_ISWIDE;
1305 0 : sc->sc_c.targets[target]->period =
1306 0 : sc->sc_c.targets[target]->offset = 0;
1307 0 : siop_update_xfer_mode(&sc->sc_c, target);
1308 0 : }
1309 : }
1310 : /* Next commands from the urgent list */
1311 0 : for (siop_cmd = TAILQ_FIRST(&sc->urgent_list); siop_cmd != NULL;
1312 : siop_cmd = next_siop_cmd) {
1313 0 : next_siop_cmd = TAILQ_NEXT(siop_cmd, next);
1314 0 : TAILQ_REMOVE(&sc->urgent_list, siop_cmd, next);
1315 0 : TAILQ_INSERT_TAIL(&reset_list, siop_cmd, next);
1316 0 : sc_print_addr(siop_cmd->cmd_c.xs->sc_link);
1317 0 : printf("cmd %p added to reset list from urgent list\n",
1318 : siop_cmd);
1319 : }
1320 : /* Then commands waiting in the input list. */
1321 0 : for (siop_cmd = TAILQ_FIRST(&sc->ready_list); siop_cmd != NULL;
1322 : siop_cmd = next_siop_cmd) {
1323 0 : next_siop_cmd = TAILQ_NEXT(siop_cmd, next);
1324 0 : TAILQ_REMOVE(&sc->ready_list, siop_cmd, next);
1325 0 : TAILQ_INSERT_TAIL(&reset_list, siop_cmd, next);
1326 0 : sc_print_addr(siop_cmd->cmd_c.xs->sc_link);
1327 0 : printf("cmd %p added to reset list from ready list\n",
1328 : siop_cmd);
1329 : }
1330 :
1331 0 : for (siop_cmd = TAILQ_FIRST(&reset_list); siop_cmd != NULL;
1332 : siop_cmd = next_siop_cmd) {
1333 0 : next_siop_cmd = TAILQ_NEXT(siop_cmd, next);
1334 0 : siop_cmd->cmd_c.flags &= ~CMDFL_TAG;
1335 0 : siop_cmd->cmd_c.xs->error =
1336 0 : (siop_cmd->cmd_c.flags & CMDFL_TIMEOUT)
1337 : ? XS_TIMEOUT : XS_RESET;
1338 0 : siop_cmd->cmd_c.xs->status = SCSI_SIOP_NOCHECK;
1339 0 : sc_print_addr(siop_cmd->cmd_c.xs->sc_link);
1340 0 : printf("cmd %p (status %d) reset",
1341 0 : siop_cmd, siop_cmd->cmd_c.status);
1342 0 : if (siop_cmd->cmd_c.status == CMDST_SENSE ||
1343 0 : siop_cmd->cmd_c.status == CMDST_SENSE_ACTIVE)
1344 0 : siop_cmd->cmd_c.status = CMDST_SENSE_DONE;
1345 : else
1346 0 : siop_cmd->cmd_c.status = CMDST_DONE;
1347 0 : printf(" with status %d, xs->error %d\n",
1348 0 : siop_cmd->cmd_c.status, siop_cmd->cmd_c.xs->error);
1349 0 : TAILQ_REMOVE(&reset_list, siop_cmd, next);
1350 0 : siop_scsicmd_end(siop_cmd);
1351 : }
1352 0 : }
1353 :
1354 : void *
1355 0 : siop_cmd_get(void *cookie)
1356 : {
1357 0 : struct siop_softc *sc = cookie;
1358 : struct siop_cmd *siop_cmd;
1359 : int s;
1360 :
1361 : /* Look if a ccb is available. */
1362 0 : s = splbio();
1363 0 : siop_cmd = TAILQ_FIRST(&sc->free_list);
1364 0 : if (siop_cmd != NULL) {
1365 0 : TAILQ_REMOVE(&sc->free_list, siop_cmd, next);
1366 : #ifdef DIAGNOSTIC
1367 0 : if (siop_cmd->cmd_c.status != CMDST_FREE)
1368 0 : panic("siop_scsicmd: new cmd not free");
1369 : #endif
1370 0 : siop_cmd->cmd_c.status = CMDST_READY;
1371 0 : }
1372 0 : splx(s);
1373 :
1374 0 : return (siop_cmd);
1375 : }
1376 :
1377 : void
1378 0 : siop_cmd_put(void *cookie, void *io)
1379 : {
1380 0 : struct siop_softc *sc = cookie;
1381 0 : struct siop_cmd *siop_cmd = io;
1382 : int s;
1383 :
1384 0 : s = splbio();
1385 0 : siop_cmd->cmd_c.status = CMDST_FREE;
1386 0 : TAILQ_INSERT_TAIL(&sc->free_list, siop_cmd, next);
1387 0 : splx(s);
1388 0 : }
1389 :
1390 : int
1391 0 : siop_scsiprobe(struct scsi_link *link)
1392 : {
1393 0 : struct siop_softc *sc = (struct siop_softc *)link->adapter_softc;
1394 : struct siop_target *siop_target;
1395 0 : const int target = link->target;
1396 0 : const int lun = link->lun;
1397 : int i;
1398 :
1399 : #ifdef SIOP_DEBUG
1400 : printf("%s:%d:%d: probe\n",
1401 : sc->sc_c.sc_dev.dv_xname, target, lun);
1402 : #endif
1403 :
1404 : /* XXX locking */
1405 :
1406 0 : siop_target = (struct siop_target*)sc->sc_c.targets[target];
1407 0 : if (siop_target == NULL) {
1408 0 : siop_target = malloc(sizeof(*siop_target), M_DEVBUF,
1409 : M_WAITOK | M_CANFAIL | M_ZERO);
1410 0 : if (siop_target == NULL) {
1411 0 : printf("%s: can't malloc memory for target %d\n",
1412 0 : sc->sc_c.sc_dev.dv_xname, target);
1413 0 : return (ENOMEM);
1414 : }
1415 :
1416 0 : siop_target->target_c.status = TARST_PROBING;
1417 0 : siop_target->target_c.flags = 0;
1418 0 : siop_target->target_c.id =
1419 0 : sc->sc_c.clock_div << 24; /* scntl3 */
1420 0 : siop_target->target_c.id |= target << 16; /* id */
1421 : /* siop_target->target_c.id |= 0x0 << 8; scxfer is 0 */
1422 :
1423 : /* get a lun switch script */
1424 0 : siop_target->lunsw = siop_get_lunsw(sc);
1425 0 : if (siop_target->lunsw == NULL) {
1426 0 : printf("%s: can't alloc lunsw for target %d\n",
1427 0 : sc->sc_c.sc_dev.dv_xname, target);
1428 0 : free(siop_target, M_DEVBUF, sizeof *siop_target);
1429 0 : return (ENOMEM);
1430 : }
1431 0 : for (i = 0; i < 8; i++)
1432 0 : siop_target->siop_lun[i] = NULL;
1433 :
1434 0 : sc->sc_c.targets[target] =
1435 0 : (struct siop_common_target *)siop_target;
1436 :
1437 0 : siop_add_reselsw(sc, target);
1438 0 : }
1439 :
1440 0 : if (siop_target->siop_lun[lun] == NULL) {
1441 0 : siop_target->siop_lun[lun] =
1442 0 : malloc(sizeof(struct siop_lun), M_DEVBUF,
1443 : M_WAITOK | M_CANFAIL | M_ZERO);
1444 0 : if (siop_target->siop_lun[lun] == NULL) {
1445 0 : printf("%s: can't alloc siop_lun for "
1446 : "target %d lun %d\n",
1447 0 : sc->sc_c.sc_dev.dv_xname, target, lun);
1448 0 : return (ENOMEM);
1449 : }
1450 : }
1451 :
1452 0 : return (0);
1453 0 : }
1454 :
1455 : void
1456 0 : siop_scsicmd(xs)
1457 : struct scsi_xfer *xs;
1458 : {
1459 0 : struct siop_softc *sc = (struct siop_softc *)xs->sc_link->adapter_softc;
1460 : struct siop_cmd *siop_cmd;
1461 : struct siop_target *siop_target;
1462 : int s, error, i, j;
1463 0 : const int target = xs->sc_link->target;
1464 0 : const int lun = xs->sc_link->lun;
1465 :
1466 : #ifdef SIOP_DEBUG_SCHED
1467 : printf("starting cmd for %d:%d\n", target, lun);
1468 : #endif
1469 :
1470 0 : siop_target = (struct siop_target*)sc->sc_c.targets[target];
1471 0 : siop_cmd = xs->io;
1472 :
1473 : /*
1474 : * The xs may have been restarted by the scsi layer, so ensure the ccb
1475 : * starts in the proper state.
1476 : */
1477 0 : siop_cmd->cmd_c.status = CMDST_READY;
1478 :
1479 : /* Always reset xs->stimeout, lest we timeout_del() with trash */
1480 0 : timeout_set(&xs->stimeout, siop_timeout, siop_cmd);
1481 :
1482 0 : siop_cmd->cmd_c.siop_target = sc->sc_c.targets[target];
1483 0 : siop_cmd->cmd_c.xs = xs;
1484 0 : siop_cmd->cmd_c.flags = 0;
1485 :
1486 0 : bzero(&siop_cmd->cmd_c.siop_tables->xscmd,
1487 : sizeof(siop_cmd->cmd_c.siop_tables->xscmd));
1488 0 : bcopy(xs->cmd, &siop_cmd->cmd_c.siop_tables->xscmd, xs->cmdlen);
1489 0 : siop_cmd->cmd_c.siop_tables->cmd.count =
1490 0 : siop_htoc32(&sc->sc_c, xs->cmdlen);
1491 :
1492 : /* load the DMA maps */
1493 0 : if (xs->flags & (SCSI_DATA_IN | SCSI_DATA_OUT)) {
1494 0 : error = bus_dmamap_load(sc->sc_c.sc_dmat,
1495 : siop_cmd->cmd_c.dmamap_data, xs->data, xs->datalen,
1496 : NULL, BUS_DMA_NOWAIT | BUS_DMA_STREAMING |
1497 : ((xs->flags & SCSI_DATA_IN) ?
1498 : BUS_DMA_READ : BUS_DMA_WRITE));
1499 0 : if (error) {
1500 0 : printf("%s: unable to load data DMA map: %d\n",
1501 0 : sc->sc_c.sc_dev.dv_xname, error);
1502 0 : xs->error = XS_DRIVER_STUFFUP;
1503 0 : scsi_done(xs);
1504 0 : return;
1505 : }
1506 0 : bus_dmamap_sync(sc->sc_c.sc_dmat,
1507 : siop_cmd->cmd_c.dmamap_data, 0,
1508 : siop_cmd->cmd_c.dmamap_data->dm_mapsize,
1509 : (xs->flags & SCSI_DATA_IN) ?
1510 : BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE);
1511 0 : }
1512 :
1513 0 : siop_setuptables(&siop_cmd->cmd_c);
1514 0 : siop_cmd->saved_offset = SIOP_NOOFFSET;
1515 0 : siop_table_sync(siop_cmd,
1516 : BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1517 :
1518 : /* Negotiate transfer parameters on first non-polling command. */
1519 0 : if (((xs->flags & SCSI_POLL) == 0) &&
1520 0 : siop_target->target_c.status == TARST_PROBING)
1521 0 : siop_target->target_c.status = TARST_ASYNC;
1522 :
1523 0 : s = splbio();
1524 0 : TAILQ_INSERT_TAIL(&sc->ready_list, siop_cmd, next);
1525 0 : siop_start(sc);
1526 0 : if ((xs->flags & SCSI_POLL) == 0) {
1527 0 : splx(s);
1528 0 : return;
1529 : }
1530 :
1531 : /* Poll for command completion. */
1532 0 : for(i = xs->timeout; i > 0; i--) {
1533 0 : siop_intr(sc);
1534 0 : if ((xs->flags & ITSDONE) == 0) {
1535 0 : delay(1000);
1536 : continue;
1537 : }
1538 0 : if (xs->cmd->opcode == INQUIRY && xs->error == XS_NOERROR) {
1539 : struct scsi_inquiry_data *inqbuf =
1540 0 : (struct scsi_inquiry_data *)xs->data;
1541 0 : if ((inqbuf->device & SID_QUAL) == SID_QUAL_BAD_LU)
1542 0 : break;
1543 : /*
1544 : * Allocate cbd's to hold maximum openings worth of
1545 : * commands. Do this now because doing it dynamically in
1546 : * siop_startcmd may cause calls to bus_dma* functions
1547 : * in interrupt context.
1548 : */
1549 0 : for (j = 0; j < SIOP_NTAG; j += SIOP_NCMDPB)
1550 0 : siop_morecbd(sc);
1551 :
1552 : /*
1553 : * Set TARF_DT here because if it is turned off during
1554 : * PPR, it must STAY off!
1555 : */
1556 0 : if ((lun == 0) && (sc->sc_c.features & SF_BUS_ULTRA3))
1557 0 : sc->sc_c.targets[target]->flags |= TARF_DT;
1558 : /*
1559 : * Can't do lun 0 here, because flags are not set yet.
1560 : * But have to do other lun's here because they never go
1561 : * through TARST_ASYNC.
1562 : */
1563 0 : if (lun > 0)
1564 0 : siop_add_dev(sc, target, lun);
1565 0 : }
1566 : break;
1567 : }
1568 0 : if (i == 0) {
1569 0 : siop_timeout(siop_cmd);
1570 0 : while ((xs->flags & ITSDONE) == 0)
1571 0 : siop_intr(sc);
1572 : }
1573 :
1574 0 : splx(s);
1575 0 : }
1576 :
1577 : void
1578 0 : siop_start(sc)
1579 : struct siop_softc *sc;
1580 : {
1581 : struct siop_cmd *siop_cmd, *next_siop_cmd;
1582 : struct siop_lun *siop_lun;
1583 : struct siop_xfer *siop_xfer;
1584 : u_int32_t dsa;
1585 : int target, lun, tag, slot;
1586 : int newcmd = 0;
1587 : int doingready = 0;
1588 :
1589 : /*
1590 : * first make sure to read valid data
1591 : */
1592 0 : siop_script_sync(sc, BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
1593 :
1594 : /*
1595 : * The queue management here is a bit tricky: the script always looks
1596 : * at the slot from first to last, so if we always use the first
1597 : * free slot commands can stay at the tail of the queue ~forever.
1598 : * The algorithm used here is to restart from the head when we know
1599 : * that the queue is empty, and only add commands after the last one.
1600 : * When we're at the end of the queue wait for the script to clear it.
1601 : * The best thing to do here would be to implement a circular queue,
1602 : * but using only 53c720 features this can be "interesting".
1603 : * A mid-way solution could be to implement 2 queues and swap orders.
1604 : */
1605 0 : slot = sc->sc_currschedslot;
1606 : /*
1607 : * If the instruction is 0x80000000 (JUMP foo, IF FALSE) the slot is
1608 : * free. As this is the last used slot, all previous slots are free,
1609 : * we can restart from 1.
1610 : * slot 0 is reserved for request sense commands.
1611 : */
1612 0 : if (siop_script_read(sc, (Ent_script_sched_slot0 / 4) + slot * 2) ==
1613 : 0x80000000) {
1614 0 : slot = sc->sc_currschedslot = 1;
1615 0 : } else {
1616 0 : slot++;
1617 : }
1618 : /* first handle commands from the urgent list */
1619 0 : siop_cmd = TAILQ_FIRST(&sc->urgent_list);
1620 : again:
1621 0 : for (; siop_cmd != NULL; siop_cmd = next_siop_cmd) {
1622 0 : next_siop_cmd = TAILQ_NEXT(siop_cmd, next);
1623 : #ifdef DIAGNOSTIC
1624 0 : if (siop_cmd->cmd_c.status != CMDST_READY &&
1625 0 : siop_cmd->cmd_c.status != CMDST_SENSE)
1626 0 : panic("siop: non-ready cmd in ready list");
1627 : #endif
1628 0 : target = siop_cmd->cmd_c.xs->sc_link->target;
1629 0 : lun = siop_cmd->cmd_c.xs->sc_link->lun;
1630 : siop_lun =
1631 0 : ((struct siop_target*)sc->sc_c.targets[target])->siop_lun[lun];
1632 : /* if non-tagged command active, wait */
1633 0 : if (siop_lun->siop_tag[0].active != NULL)
1634 : continue;
1635 : /*
1636 : * if we're in a queue full condition don't start a new
1637 : * command, unless it's a request sense
1638 : */
1639 0 : if ((siop_lun->lun_flags & SIOP_LUNF_FULL) &&
1640 0 : siop_cmd->cmd_c.status == CMDST_READY)
1641 : continue;
1642 : /* find a free tag if needed */
1643 0 : if (siop_cmd->cmd_c.flags & CMDFL_TAG) {
1644 0 : for (tag = 1; tag < SIOP_NTAG; tag++) {
1645 0 : if (siop_lun->siop_tag[tag].active == NULL)
1646 : break;
1647 : }
1648 0 : if (tag == SIOP_NTAG) /* no free tag */
1649 : continue;
1650 : } else {
1651 : tag = 0;
1652 : }
1653 0 : siop_cmd->cmd_c.tag = tag;
1654 : /*
1655 : * find a free scheduler slot and load it. If it's a request
1656 : * sense we need to use slot 0.
1657 : */
1658 0 : if (siop_cmd->cmd_c.status != CMDST_SENSE) {
1659 0 : for (; slot < SIOP_NSLOTS; slot++) {
1660 : /*
1661 : * If cmd if 0x80000000 the slot is free
1662 : */
1663 0 : if (siop_script_read(sc,
1664 0 : (Ent_script_sched_slot0 / 4) + slot * 2) ==
1665 : 0x80000000)
1666 : break;
1667 : }
1668 : /* no more free slots, no need to continue */
1669 0 : if (slot == SIOP_NSLOTS) {
1670 : goto end;
1671 : }
1672 : } else {
1673 : slot = 0;
1674 0 : if (siop_script_read(sc, Ent_script_sched_slot0 / 4)
1675 0 : != 0x80000000)
1676 : goto end;
1677 : }
1678 :
1679 : #ifdef SIOP_DEBUG_SCHED
1680 : printf("using slot %d for DSA 0x%lx\n", slot,
1681 : (u_long)siop_cmd->cmd_c.dsa);
1682 : #endif
1683 : /* Ok, we can add the tag message */
1684 0 : if (tag > 0) {
1685 : #ifdef DIAGNOSTIC
1686 0 : int msgcount = siop_ctoh32(&sc->sc_c,
1687 : siop_cmd->cmd_tables->t_msgout.count);
1688 0 : if (msgcount != 1)
1689 0 : printf("%s:%d:%d: tag %d with msgcount %d\n",
1690 0 : sc->sc_c.sc_dev.dv_xname, target, lun, tag,
1691 : msgcount);
1692 : #endif
1693 0 : siop_cmd->cmd_tables->msg_out[1] = MSG_SIMPLE_Q_TAG;
1694 0 : siop_cmd->cmd_tables->msg_out[2] = tag;
1695 0 : siop_cmd->cmd_tables->t_msgout.count =
1696 0 : siop_htoc32(&sc->sc_c, 3);
1697 0 : }
1698 : /* note that we started a new command */
1699 : newcmd = 1;
1700 : /* mark command as active */
1701 0 : if (siop_cmd->cmd_c.status == CMDST_READY) {
1702 0 : siop_cmd->cmd_c.status = CMDST_ACTIVE;
1703 0 : } else if (siop_cmd->cmd_c.status == CMDST_SENSE) {
1704 0 : siop_cmd->cmd_c.status = CMDST_SENSE_ACTIVE;
1705 : } else
1706 0 : panic("siop_start: bad status");
1707 0 : if (doingready)
1708 0 : TAILQ_REMOVE(&sc->ready_list, siop_cmd, next);
1709 : else
1710 0 : TAILQ_REMOVE(&sc->urgent_list, siop_cmd, next);
1711 0 : siop_lun->siop_tag[tag].active = siop_cmd;
1712 : /* patch scripts with DSA addr */
1713 0 : dsa = siop_cmd->cmd_c.dsa;
1714 : /* first reselect switch, if we have an entry */
1715 0 : if (siop_lun->siop_tag[tag].reseloff > 0)
1716 0 : siop_script_write(sc,
1717 0 : siop_lun->siop_tag[tag].reseloff + 1,
1718 0 : dsa + sizeof(struct siop_common_xfer) +
1719 : Ent_ldsa_reload_dsa);
1720 : /* CMD script: MOVE MEMORY addr */
1721 0 : siop_xfer = (struct siop_xfer*)siop_cmd->cmd_tables;
1722 0 : siop_xfer->resel[E_ldsa_abs_slot_Used[0]] =
1723 0 : siop_htoc32(&sc->sc_c, sc->sc_c.sc_scriptaddr +
1724 : Ent_script_sched_slot0 + slot * 8);
1725 0 : siop_table_sync(siop_cmd, BUS_DMASYNC_PREWRITE);
1726 : /* scheduler slot: JUMP ldsa_select */
1727 0 : siop_script_write(sc,
1728 0 : (Ent_script_sched_slot0 / 4) + slot * 2 + 1,
1729 0 : dsa + sizeof(struct siop_common_xfer) + Ent_ldsa_select);
1730 : /* handle timeout */
1731 0 : if (siop_cmd->cmd_c.status == CMDST_ACTIVE) {
1732 0 : if ((siop_cmd->cmd_c.xs->flags & SCSI_POLL) == 0) {
1733 : /* start expire timer */
1734 0 : timeout_add_msec(&siop_cmd->cmd_c.xs->stimeout,
1735 0 : siop_cmd->cmd_c.xs->timeout);
1736 0 : }
1737 : }
1738 : /*
1739 : * Change JUMP cmd so that this slot will be handled
1740 : */
1741 0 : siop_script_write(sc, (Ent_script_sched_slot0 / 4) + slot * 2,
1742 : 0x80080000);
1743 : /* if we're using the request sense slot, stop here */
1744 0 : if (slot == 0)
1745 : goto end;
1746 0 : sc->sc_currschedslot = slot;
1747 0 : slot++;
1748 0 : }
1749 0 : if (doingready == 0) {
1750 : /* now process ready list */
1751 : doingready = 1;
1752 0 : siop_cmd = TAILQ_FIRST(&sc->ready_list);
1753 0 : goto again;
1754 : }
1755 :
1756 : end:
1757 : /* if nothing changed no need to flush cache and wakeup script */
1758 0 : if (newcmd == 0)
1759 0 : return;
1760 : /* make sure SCRIPT processor will read valid data */
1761 0 : siop_script_sync(sc,BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1762 : /* Signal script it has some work to do */
1763 0 : bus_space_write_1(sc->sc_c.sc_rt, sc->sc_c.sc_rh,
1764 : SIOP_ISTAT, ISTAT_SIGP);
1765 : /* and wait for IRQ */
1766 0 : }
1767 :
1768 : void
1769 0 : siop_timeout(v)
1770 : void *v;
1771 : {
1772 0 : struct siop_cmd *siop_cmd = v;
1773 0 : struct siop_softc *sc = (struct siop_softc *)siop_cmd->cmd_c.siop_sc;
1774 : int s;
1775 :
1776 : /* deactivate callout */
1777 0 : timeout_del(&siop_cmd->cmd_c.xs->stimeout);
1778 :
1779 0 : sc_print_addr(siop_cmd->cmd_c.xs->sc_link);
1780 0 : printf("timeout on SCSI command 0x%x\n",
1781 0 : siop_cmd->cmd_c.xs->cmd->opcode);
1782 :
1783 0 : s = splbio();
1784 : /* reset the scsi bus */
1785 0 : siop_resetbus(&sc->sc_c);
1786 0 : siop_cmd->cmd_c.flags |= CMDFL_TIMEOUT;
1787 0 : siop_handle_reset(sc);
1788 0 : splx(s);
1789 0 : }
1790 :
1791 : #ifdef DUMP_SCRIPT
1792 : void
1793 : siop_dump_script(sc)
1794 : struct siop_softc *sc;
1795 : {
1796 : int i;
1797 : for (i = 0; i < PAGE_SIZE / 4; i += 2) {
1798 : printf("0x%04x: 0x%08x 0x%08x", i * 4,
1799 : siop_ctoh32(&sc->sc_c, sc->sc_c.sc_script[i]),
1800 : siop_ctoh32(&sc->sc_c, sc->sc_c.sc_script[i+1]));
1801 : if ((siop_ctoh32(&sc->sc_c,
1802 : sc->sc_c.sc_script[i]) & 0xe0000000) == 0xc0000000) {
1803 : i++;
1804 : printf(" 0x%08x", siop_ctoh32(&sc->sc_c,
1805 : sc->sc_c.sc_script[i+1]));
1806 : }
1807 : printf("\n");
1808 : }
1809 : }
1810 : #endif
1811 :
1812 : void
1813 0 : siop_morecbd(sc)
1814 : struct siop_softc *sc;
1815 : {
1816 : int error, off, i, j, s;
1817 : struct siop_cbd *newcbd;
1818 : struct siop_xfer *xfers, *xfer;
1819 : bus_addr_t dsa;
1820 : u_int32_t *scr;
1821 : size_t sense_size = roundup(sizeof(struct scsi_sense_data), 16);
1822 :
1823 : /* allocate a new list head */
1824 0 : newcbd = malloc(sizeof(struct siop_cbd), M_DEVBUF, M_NOWAIT | M_ZERO);
1825 0 : if (newcbd == NULL) {
1826 0 : printf("%s: can't allocate memory for command descriptors "
1827 0 : "head\n", sc->sc_c.sc_dev.dv_xname);
1828 0 : return;
1829 : }
1830 :
1831 : /* allocate cmd list */
1832 0 : newcbd->cmds = mallocarray(SIOP_NCMDPB, sizeof(struct siop_cmd),
1833 : M_DEVBUF, M_NOWAIT | M_ZERO);
1834 0 : if (newcbd->cmds == NULL) {
1835 0 : printf("%s: can't allocate memory for command descriptors\n",
1836 0 : sc->sc_c.sc_dev.dv_xname);
1837 0 : goto bad3;
1838 : }
1839 :
1840 0 : newcbd->xfers = siop_dmamem_alloc(sc, PAGE_SIZE);
1841 0 : if (newcbd->xfers == NULL) {
1842 0 : printf("%s: unable to allocate cbd xfer DMA memory\n",
1843 0 : sc->sc_c.sc_dev.dv_xname);
1844 0 : goto bad2;
1845 : }
1846 0 : xfers = SIOP_DMA_KVA(newcbd->xfers);
1847 :
1848 0 : newcbd->sense = siop_dmamem_alloc(sc, sense_size * SIOP_NCMDPB);
1849 0 : if (newcbd->sense == NULL) {
1850 0 : printf("%s: unable to allocate cbd sense DMA memory\n",
1851 0 : sc->sc_c.sc_dev.dv_xname);
1852 0 : goto bad1;
1853 : }
1854 :
1855 0 : for (i = 0; i < SIOP_NCMDPB; i++) {
1856 0 : error = bus_dmamap_create(sc->sc_c.sc_dmat, MAXPHYS, SIOP_NSG,
1857 : MAXPHYS, 0, BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW,
1858 : &newcbd->cmds[i].cmd_c.dmamap_data);
1859 0 : if (error) {
1860 0 : printf("%s: unable to create data DMA map for cbd: "
1861 : "error %d\n",
1862 0 : sc->sc_c.sc_dev.dv_xname, error);
1863 : goto bad0;
1864 : }
1865 : }
1866 :
1867 : /* Use two loops since bailing out above releases allocated memory */
1868 0 : off = (sc->sc_c.features & SF_CHIP_BE) ? 3 : 0;
1869 0 : for (i = 0; i < SIOP_NCMDPB; i++) {
1870 0 : newcbd->cmds[i].cmd_c.siop_sc = &sc->sc_c;
1871 0 : newcbd->cmds[i].siop_cbdp = newcbd;
1872 0 : xfer = &xfers[i];
1873 0 : newcbd->cmds[i].cmd_tables = (struct siop_common_xfer *)xfer;
1874 0 : bzero(newcbd->cmds[i].cmd_tables, sizeof(struct siop_xfer));
1875 0 : dsa = SIOP_DMA_DVA(newcbd->xfers) +
1876 0 : i * sizeof(struct siop_xfer);
1877 0 : newcbd->cmds[i].cmd_c.dsa = dsa;
1878 0 : newcbd->cmds[i].cmd_c.status = CMDST_FREE;
1879 0 : newcbd->cmds[i].cmd_c.sense = (struct scsi_sense_data *)(
1880 0 : i * sense_size +
1881 0 : (u_int8_t *)SIOP_DMA_KVA(newcbd->sense));
1882 0 : xfer->siop_tables.t_msgout.count= siop_htoc32(&sc->sc_c, 1);
1883 0 : xfer->siop_tables.t_msgout.addr = siop_htoc32(&sc->sc_c, dsa);
1884 0 : xfer->siop_tables.t_msgin.count= siop_htoc32(&sc->sc_c, 1);
1885 0 : xfer->siop_tables.t_msgin.addr = siop_htoc32(&sc->sc_c,
1886 : dsa + offsetof(struct siop_common_xfer, msg_in));
1887 0 : xfer->siop_tables.t_extmsgin.count= siop_htoc32(&sc->sc_c, 2);
1888 0 : xfer->siop_tables.t_extmsgin.addr = siop_htoc32(&sc->sc_c,
1889 : dsa + offsetof(struct siop_common_xfer, msg_in) + 1);
1890 0 : xfer->siop_tables.t_extmsgdata.addr = siop_htoc32(&sc->sc_c,
1891 : dsa + offsetof(struct siop_common_xfer, msg_in) + 3);
1892 0 : xfer->siop_tables.t_status.count= siop_htoc32(&sc->sc_c, 1);
1893 0 : xfer->siop_tables.t_status.addr = siop_htoc32(&sc->sc_c,
1894 : dsa + offsetof(struct siop_common_xfer, status) + off);
1895 0 : xfer->siop_tables.cmd.count = siop_htoc32(&sc->sc_c, 0);
1896 0 : xfer->siop_tables.cmd.addr = siop_htoc32(&sc->sc_c,
1897 : dsa + offsetof(struct siop_common_xfer, xscmd));
1898 : /* The select/reselect script */
1899 0 : scr = &xfer->resel[0];
1900 0 : for (j = 0; j < sizeof(load_dsa) / sizeof(load_dsa[0]); j++)
1901 0 : scr[j] = siop_htoc32(&sc->sc_c, load_dsa[j]);
1902 : /*
1903 : * 0x78000000 is a 'move data8 to reg'. data8 is the second
1904 : * octet, reg offset is the third.
1905 : */
1906 0 : scr[Ent_rdsa0 / 4] = siop_htoc32(&sc->sc_c,
1907 : 0x78100000 | ((dsa & 0x000000ff) << 8));
1908 0 : scr[Ent_rdsa1 / 4] = siop_htoc32(&sc->sc_c,
1909 : 0x78110000 | ( dsa & 0x0000ff00 ));
1910 0 : scr[Ent_rdsa2 / 4] = siop_htoc32(&sc->sc_c,
1911 : 0x78120000 | ((dsa & 0x00ff0000) >> 8));
1912 0 : scr[Ent_rdsa3 / 4] = siop_htoc32(&sc->sc_c,
1913 : 0x78130000 | ((dsa & 0xff000000) >> 16));
1914 0 : scr[E_ldsa_abs_reselected_Used[0]] = siop_htoc32(&sc->sc_c,
1915 : sc->sc_c.sc_scriptaddr + Ent_reselected);
1916 0 : scr[E_ldsa_abs_reselect_Used[0]] = siop_htoc32(&sc->sc_c,
1917 : sc->sc_c.sc_scriptaddr + Ent_reselect);
1918 0 : scr[E_ldsa_abs_selected_Used[0]] = siop_htoc32(&sc->sc_c,
1919 : sc->sc_c.sc_scriptaddr + Ent_selected);
1920 0 : scr[E_ldsa_abs_data_Used[0]] = siop_htoc32(&sc->sc_c,
1921 : dsa + sizeof(struct siop_common_xfer) + Ent_ldsa_data);
1922 : /* JUMP foo, IF FALSE - used by MOVE MEMORY to clear the slot */
1923 0 : scr[Ent_ldsa_data / 4] = siop_htoc32(&sc->sc_c, 0x80000000);
1924 0 : s = splbio();
1925 0 : TAILQ_INSERT_TAIL(&sc->free_list, &newcbd->cmds[i], next);
1926 0 : splx(s);
1927 : #ifdef SIOP_DEBUG
1928 : printf("tables[%d]: in=0x%x out=0x%x status=0x%x "
1929 : "offset=0x%x\n", i,
1930 : siop_ctoh32(&sc->sc_c,
1931 : newcbd->cmds[i].cmd_tables->t_msgin.addr),
1932 : siop_ctoh32(&sc->sc_c,
1933 : newcbd->cmds[i].cmd_tables->t_msgout.addr),
1934 : siop_ctoh32(&sc->sc_c,
1935 : newcbd->cmds[i].cmd_tables->t_status.addr));
1936 : #endif
1937 : }
1938 0 : s = splbio();
1939 0 : TAILQ_INSERT_TAIL(&sc->cmds, newcbd, next);
1940 0 : splx(s);
1941 0 : return;
1942 : bad0:
1943 0 : while (--i >= 0) {
1944 0 : bus_dmamap_destroy(sc->sc_c.sc_dmat,
1945 : newcbd->cmds[i].cmd_c.dmamap_data);
1946 : }
1947 0 : siop_dmamem_free(sc, newcbd->sense);
1948 : bad1:
1949 0 : siop_dmamem_free(sc, newcbd->xfers);
1950 : bad2:
1951 0 : free(newcbd->cmds, M_DEVBUF, SIOP_NCMDPB * sizeof(struct siop_cmd));
1952 : bad3:
1953 0 : free(newcbd, M_DEVBUF, sizeof *newcbd);
1954 0 : }
1955 :
1956 : struct siop_lunsw *
1957 0 : siop_get_lunsw(sc)
1958 : struct siop_softc *sc;
1959 : {
1960 : struct siop_lunsw *lunsw;
1961 : int i;
1962 :
1963 0 : if (sc->script_free_lo + (sizeof(lun_switch) / sizeof(lun_switch[0])) >=
1964 0 : sc->script_free_hi)
1965 0 : return NULL;
1966 0 : lunsw = TAILQ_FIRST(&sc->lunsw_list);
1967 0 : if (lunsw != NULL) {
1968 : #ifdef SIOP_DEBUG
1969 : printf("siop_get_lunsw got lunsw at offset %d\n",
1970 : lunsw->lunsw_off);
1971 : #endif
1972 0 : TAILQ_REMOVE(&sc->lunsw_list, lunsw, next);
1973 0 : return lunsw;
1974 : }
1975 0 : lunsw = malloc(sizeof(struct siop_lunsw), M_DEVBUF, M_NOWAIT | M_ZERO);
1976 0 : if (lunsw == NULL)
1977 0 : return NULL;
1978 : #ifdef SIOP_DEBUG
1979 : printf("allocating lunsw at offset %d\n", sc->script_free_lo);
1980 : #endif
1981 0 : if (sc->sc_c.features & SF_CHIP_RAM) {
1982 0 : bus_space_write_region_4(sc->sc_c.sc_ramt, sc->sc_c.sc_ramh,
1983 : sc->script_free_lo * 4, lun_switch,
1984 : sizeof(lun_switch) / sizeof(lun_switch[0]));
1985 0 : bus_space_write_4(sc->sc_c.sc_ramt, sc->sc_c.sc_ramh,
1986 : (sc->script_free_lo + E_abs_lunsw_return_Used[0]) * 4,
1987 : sc->sc_c.sc_scriptaddr + Ent_lunsw_return);
1988 0 : } else {
1989 0 : for (i = 0; i < sizeof(lun_switch) / sizeof(lun_switch[0]);
1990 0 : i++)
1991 0 : sc->sc_c.sc_script[sc->script_free_lo + i] =
1992 0 : siop_htoc32(&sc->sc_c, lun_switch[i]);
1993 0 : sc->sc_c.sc_script[
1994 0 : sc->script_free_lo + E_abs_lunsw_return_Used[0]] =
1995 0 : siop_htoc32(&sc->sc_c,
1996 : sc->sc_c.sc_scriptaddr + Ent_lunsw_return);
1997 : }
1998 0 : lunsw->lunsw_off = sc->script_free_lo;
1999 0 : lunsw->lunsw_size = sizeof(lun_switch) / sizeof(lun_switch[0]);
2000 0 : sc->script_free_lo += lunsw->lunsw_size;
2001 0 : siop_script_sync(sc, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
2002 0 : return lunsw;
2003 0 : }
2004 :
2005 : void
2006 0 : siop_add_reselsw(sc, target)
2007 : struct siop_softc *sc;
2008 : int target;
2009 : {
2010 : int i,j;
2011 : struct siop_target *siop_target;
2012 : struct siop_lun *siop_lun;
2013 :
2014 0 : siop_target = (struct siop_target *)sc->sc_c.targets[target];
2015 : /*
2016 : * add an entry to resel switch
2017 : */
2018 0 : siop_script_sync(sc, BUS_DMASYNC_POSTWRITE);
2019 0 : for (i = 0; i < 15; i++) {
2020 0 : siop_target->reseloff = Ent_resel_targ0 / 4 + i * 2;
2021 0 : if ((siop_script_read(sc, siop_target->reseloff) & 0xff)
2022 0 : == 0xff) { /* it's free */
2023 : #ifdef SIOP_DEBUG
2024 : printf("siop: target %d slot %d offset %d\n",
2025 : target, i, siop_target->reseloff);
2026 : #endif
2027 : /* JUMP abs_foo, IF target | 0x80; */
2028 0 : siop_script_write(sc, siop_target->reseloff,
2029 0 : 0x800c0080 | target);
2030 0 : siop_script_write(sc, siop_target->reseloff + 1,
2031 0 : sc->sc_c.sc_scriptaddr +
2032 0 : siop_target->lunsw->lunsw_off * 4 +
2033 : Ent_lun_switch_entry);
2034 0 : break;
2035 : }
2036 : }
2037 0 : if (i == 15) /* no free slot, shouldn't happen */
2038 0 : panic("siop: resel switch full");
2039 :
2040 0 : sc->sc_ntargets++;
2041 0 : for (i = 0; i < 8; i++) {
2042 0 : siop_lun = siop_target->siop_lun[i];
2043 0 : if (siop_lun == NULL)
2044 : continue;
2045 0 : if (siop_lun->reseloff > 0) {
2046 0 : siop_lun->reseloff = 0;
2047 0 : for (j = 0; j < SIOP_NTAG; j++)
2048 0 : siop_lun->siop_tag[j].reseloff = 0;
2049 0 : siop_add_dev(sc, target, i);
2050 0 : }
2051 : }
2052 0 : siop_update_scntl3(sc, sc->sc_c.targets[target]);
2053 0 : siop_script_sync(sc, BUS_DMASYNC_PREWRITE);
2054 0 : }
2055 :
2056 : void
2057 0 : siop_update_scntl3(sc, _siop_target)
2058 : struct siop_softc *sc;
2059 : struct siop_common_target *_siop_target;
2060 : {
2061 0 : struct siop_target *siop_target = (struct siop_target *)_siop_target;
2062 : /* MOVE target->id >> 24 TO SCNTL3 */
2063 0 : siop_script_write(sc,
2064 0 : siop_target->lunsw->lunsw_off + (Ent_restore_scntl3 / 4),
2065 0 : 0x78030000 | ((siop_target->target_c.id >> 16) & 0x0000ff00));
2066 : /* MOVE target->id >> 8 TO SXFER */
2067 0 : siop_script_write(sc,
2068 0 : siop_target->lunsw->lunsw_off + (Ent_restore_scntl3 / 4) + 2,
2069 0 : 0x78050000 | (siop_target->target_c.id & 0x0000ff00));
2070 0 : siop_script_sync(sc, BUS_DMASYNC_PREWRITE);
2071 0 : }
2072 :
2073 : void
2074 0 : siop_add_dev(sc, target, lun)
2075 : struct siop_softc *sc;
2076 : int target;
2077 : int lun;
2078 : {
2079 : struct siop_lunsw *lunsw;
2080 : struct siop_target *siop_target =
2081 0 : (struct siop_target *)sc->sc_c.targets[target];
2082 0 : struct siop_lun *siop_lun = siop_target->siop_lun[lun];
2083 : int i, ntargets;
2084 :
2085 0 : if (siop_lun->reseloff > 0)
2086 0 : return;
2087 0 : lunsw = siop_target->lunsw;
2088 0 : if ((lunsw->lunsw_off + lunsw->lunsw_size) < sc->script_free_lo) {
2089 : /*
2090 : * can't extend this slot. Probably not worth trying to deal
2091 : * with this case
2092 : */
2093 : #ifdef SIOP_DEBUG
2094 : printf("%s:%d:%d: can't allocate a lun sw slot\n",
2095 : sc->sc_c.sc_dev.dv_xname, target, lun);
2096 : #endif
2097 0 : return;
2098 : }
2099 : /* count how many free targets we still have to probe */
2100 0 : ntargets = (sc->sc_c.sc_link.adapter_buswidth - 1) - 1 - sc->sc_ntargets;
2101 :
2102 : /*
2103 : * we need 8 bytes for the lun sw additional entry, and
2104 : * eventually sizeof(tag_switch) for the tag switch entry.
2105 : * Keep enough free space for the free targets that could be
2106 : * probed later.
2107 : */
2108 0 : if (sc->script_free_lo + 2 +
2109 0 : (ntargets * sizeof(lun_switch) / sizeof(lun_switch[0])) >=
2110 0 : ((siop_target->target_c.flags & TARF_TAG) ?
2111 0 : sc->script_free_hi - (sizeof(tag_switch) / sizeof(tag_switch[0])) :
2112 : sc->script_free_hi)) {
2113 : /*
2114 : * not enough space, probably not worth dealing with it.
2115 : * We can hold 13 tagged-queuing capable devices in the 4k RAM.
2116 : */
2117 : #ifdef SIOP_DEBUG
2118 : printf("%s:%d:%d: not enough memory for a lun sw slot\n",
2119 : sc->sc_c.sc_dev.dv_xname, target, lun);
2120 : #endif
2121 0 : return;
2122 : }
2123 : #ifdef SIOP_DEBUG
2124 : printf("%s:%d:%d: allocate lun sw entry\n",
2125 : sc->sc_c.sc_dev.dv_xname, target, lun);
2126 : #endif
2127 : /* INT int_resellun */
2128 0 : siop_script_write(sc, sc->script_free_lo, 0x98080000);
2129 0 : siop_script_write(sc, sc->script_free_lo + 1, A_int_resellun);
2130 : /* Now the slot entry: JUMP abs_foo, IF lun */
2131 0 : siop_script_write(sc, sc->script_free_lo - 2,
2132 0 : 0x800c0000 | lun);
2133 0 : siop_script_write(sc, sc->script_free_lo - 1, 0);
2134 0 : siop_lun->reseloff = sc->script_free_lo - 2;
2135 0 : lunsw->lunsw_size += 2;
2136 0 : sc->script_free_lo += 2;
2137 0 : if (siop_target->target_c.flags & TARF_TAG) {
2138 : /* we need a tag switch */
2139 0 : sc->script_free_hi -=
2140 : sizeof(tag_switch) / sizeof(tag_switch[0]);
2141 0 : if (sc->sc_c.features & SF_CHIP_RAM) {
2142 0 : bus_space_write_region_4(sc->sc_c.sc_ramt,
2143 : sc->sc_c.sc_ramh,
2144 : sc->script_free_hi * 4, tag_switch,
2145 : sizeof(tag_switch) / sizeof(tag_switch[0]));
2146 0 : } else {
2147 0 : for(i = 0;
2148 0 : i < sizeof(tag_switch) / sizeof(tag_switch[0]);
2149 0 : i++) {
2150 0 : sc->sc_c.sc_script[sc->script_free_hi + i] =
2151 0 : siop_htoc32(&sc->sc_c, tag_switch[i]);
2152 : }
2153 : }
2154 0 : siop_script_write(sc,
2155 0 : siop_lun->reseloff + 1,
2156 0 : sc->sc_c.sc_scriptaddr + sc->script_free_hi * 4 +
2157 : Ent_tag_switch_entry);
2158 :
2159 0 : for (i = 0; i < SIOP_NTAG; i++) {
2160 0 : siop_lun->siop_tag[i].reseloff =
2161 0 : sc->script_free_hi + (Ent_resel_tag0 / 4) + i * 2;
2162 : }
2163 : } else {
2164 : /* non-tag case; just work with the lun switch */
2165 0 : siop_lun->siop_tag[0].reseloff =
2166 0 : siop_target->siop_lun[lun]->reseloff;
2167 : }
2168 0 : siop_script_sync(sc, BUS_DMASYNC_PREWRITE);
2169 0 : }
2170 :
2171 : void
2172 0 : siop_scsifree(struct scsi_link *link)
2173 : {
2174 0 : struct siop_softc *sc = link->adapter_softc;
2175 0 : int target = link->target;
2176 0 : int lun = link->lun;
2177 : int i;
2178 : struct siop_target *siop_target;
2179 :
2180 : #ifdef SIOP_DEBUG
2181 : printf("%s:%d:%d: free lun sw entry\n",
2182 : sc->sc_c.sc_dev.dv_xname, target, lun);
2183 : #endif
2184 :
2185 0 : siop_target = (struct siop_target *)sc->sc_c.targets[target];
2186 0 : free(siop_target->siop_lun[lun], M_DEVBUF, 0);
2187 0 : siop_target->siop_lun[lun] = NULL;
2188 : /* XXX compact sw entry too ? */
2189 : /* check if we can free the whole target */
2190 0 : for (i = 0; i < 8; i++) {
2191 0 : if (siop_target->siop_lun[i] != NULL)
2192 0 : return;
2193 : }
2194 : #ifdef SIOP_DEBUG
2195 : printf("%s: free siop_target for target %d lun %d lunsw offset %d\n",
2196 : sc->sc_c.sc_dev.dv_xname, target, lun,
2197 : siop_target->lunsw->lunsw_off);
2198 : #endif
2199 : /*
2200 : * nothing here, free the target struct and resel
2201 : * switch entry
2202 : */
2203 0 : siop_script_write(sc, siop_target->reseloff, 0x800c00ff);
2204 0 : siop_script_sync(sc, BUS_DMASYNC_PREWRITE);
2205 0 : TAILQ_INSERT_TAIL(&sc->lunsw_list, siop_target->lunsw, next);
2206 0 : free(sc->sc_c.targets[target], M_DEVBUF, 0);
2207 0 : sc->sc_c.targets[target] = NULL;
2208 0 : sc->sc_ntargets--;
2209 0 : }
2210 :
2211 : #ifdef SIOP_STATS
2212 : void
2213 : siop_printstats(void)
2214 : {
2215 : printf("siop_stat_intr %d\n", siop_stat_intr);
2216 : printf("siop_stat_intr_shortxfer %d\n", siop_stat_intr_shortxfer);
2217 : printf("siop_stat_intr_xferdisc %d\n", siop_stat_intr_xferdisc);
2218 : printf("siop_stat_intr_sdp %d\n", siop_stat_intr_sdp);
2219 : printf("siop_stat_intr_saveoffset %d\n", siop_stat_intr_saveoffset);
2220 : printf("siop_stat_intr_done %d\n", siop_stat_intr_done);
2221 : printf("siop_stat_intr_lunresel %d\n", siop_stat_intr_lunresel);
2222 : printf("siop_stat_intr_qfull %d\n", siop_stat_intr_qfull);
2223 : }
2224 : #endif
2225 :
2226 : struct siop_dmamem *
2227 0 : siop_dmamem_alloc(struct siop_softc *sc, size_t size)
2228 : {
2229 : struct siop_dmamem *sdm;
2230 0 : int nsegs;
2231 :
2232 0 : sdm = malloc(sizeof(*sdm), M_DEVBUF, M_NOWAIT | M_ZERO);
2233 0 : if (sdm == NULL)
2234 0 : return (NULL);
2235 :
2236 0 : sdm->sdm_size = size;
2237 :
2238 0 : if (bus_dmamap_create(sc->sc_c.sc_dmat, size, 1, size, 0,
2239 0 : BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &sdm->sdm_map) != 0)
2240 : goto sdmfree;
2241 :
2242 0 : if (bus_dmamem_alloc(sc->sc_c.sc_dmat, size, PAGE_SIZE, 0,
2243 0 : &sdm->sdm_seg, 1, &nsegs, BUS_DMA_NOWAIT | BUS_DMA_ZERO) != 0)
2244 : goto destroy;
2245 :
2246 0 : if (bus_dmamem_map(sc->sc_c.sc_dmat, &sdm->sdm_seg, nsegs, size,
2247 0 : &sdm->sdm_kva, BUS_DMA_NOWAIT | BUS_DMA_COHERENT) != 0)
2248 : goto free;
2249 :
2250 0 : if (bus_dmamap_load(sc->sc_c.sc_dmat, sdm->sdm_map, sdm->sdm_kva,
2251 0 : size, NULL, BUS_DMA_NOWAIT) != 0)
2252 : goto unmap;
2253 :
2254 0 : return (sdm);
2255 :
2256 : unmap:
2257 0 : bus_dmamem_unmap(sc->sc_c.sc_dmat, sdm->sdm_kva, size);
2258 : free:
2259 0 : bus_dmamem_free(sc->sc_c.sc_dmat, &sdm->sdm_seg, 1);
2260 : destroy:
2261 0 : bus_dmamap_destroy(sc->sc_c.sc_dmat, sdm->sdm_map);
2262 : sdmfree:
2263 0 : free(sdm, M_DEVBUF, sizeof *sdm);
2264 :
2265 0 : return (NULL);
2266 0 : }
2267 :
2268 : void
2269 0 : siop_dmamem_free(struct siop_softc *sc, struct siop_dmamem *sdm)
2270 : {
2271 0 : bus_dmamap_unload(sc->sc_c.sc_dmat, sdm->sdm_map);
2272 0 : bus_dmamem_unmap(sc->sc_c.sc_dmat, sdm->sdm_kva, sdm->sdm_size);
2273 0 : bus_dmamem_free(sc->sc_c.sc_dmat, &sdm->sdm_seg, 1);
2274 0 : bus_dmamap_destroy(sc->sc_c.sc_dmat, sdm->sdm_map);
2275 0 : free(sdm, M_DEVBUF, sizeof *sdm);
2276 0 : }
2277 :
|