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