Annotation of src/sys/dev/ic/siop.c, Revision 1.21
1.21 ! bouyer 1: /* $NetBSD: siop.c,v 1.20 2000/06/12 20:13:41 bouyer 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.5 bouyer 16: * This product includes software developed by Manuel 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.
23: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
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 */
34:
35: #include <sys/param.h>
36: #include <sys/systm.h>
37: #include <sys/device.h>
38: #include <sys/malloc.h>
39: #include <sys/buf.h>
40: #include <sys/kernel.h>
41:
42: #include <machine/endian.h>
43: #include <machine/bus.h>
44:
45: #include <vm/vm.h>
46: #include <vm/vm_param.h>
47: #include <vm/vm_kern.h>
48:
49: #include <dev/microcode/siop/siop.out>
50:
51: #include <dev/scsipi/scsi_all.h>
52: #include <dev/scsipi/scsi_message.h>
53: #include <dev/scsipi/scsipi_all.h>
54:
55: #include <dev/scsipi/scsiconf.h>
56:
57: #include <dev/ic/siopreg.h>
58: #include <dev/ic/siopvar.h>
1.14 bouyer 59: #include <dev/ic/siopvar_common.h>
1.1 bouyer 60:
1.15 bouyer 61: #undef DEBUG
1.8 bouyer 62: #undef DEBUG_DR
1.2 bouyer 63: #undef DEBUG_INTR
64: #undef DEBUG_SHED
65: #undef DUMP_SCRIPT
66:
67: #define SIOP_STATS
68:
1.1 bouyer 69: #ifndef SIOP_DEFAULT_TARGET
70: #define SIOP_DEFAULT_TARGET 7
71: #endif
72:
1.16 bouyer 73: /* number of cmd descriptors per block */
74: #define SIOP_NCMDPB (NBPG / sizeof(struct siop_xfer))
1.1 bouyer 75:
76: void siop_reset __P((struct siop_softc *));
1.2 bouyer 77: void siop_handle_reset __P((struct siop_softc *));
78: void siop_scsicmd_end __P((struct siop_cmd *));
1.1 bouyer 79: void siop_start __P((struct siop_softc *));
80: void siop_timeout __P((void *));
81: int siop_scsicmd __P((struct scsipi_xfer *));
1.2 bouyer 82: void siop_dump_script __P((struct siop_softc *));
1.16 bouyer 83: int siop_morecbd __P((struct siop_softc *));
1.1 bouyer 84:
85: struct scsipi_adapter siop_adapter = {
86: 0,
87: siop_scsicmd,
88: siop_minphys,
1.2 bouyer 89: siop_ioctl,
1.19 tsutsui 90: NULL,
1.1 bouyer 91: NULL,
92: };
93:
94: struct scsipi_device siop_dev = {
95: NULL,
96: NULL,
97: NULL,
98: NULL,
99: };
100:
1.2 bouyer 101: #ifdef SIOP_STATS
102: static int siop_stat_intr = 0;
103: static int siop_stat_intr_shortxfer = 0;
104: static int siop_stat_intr_sdp = 0;
105: static int siop_stat_intr_done = 0;
106: static int siop_stat_intr_reselect = 0;
107: static int siop_stat_intr_xferdisc = 0;
108: void siop_printstats __P((void));
109: #define INCSTAT(x) x++
110: #else
111: #define INCSTAT(x)
112: #endif
113:
114: static __inline__ void siop_table_sync __P((struct siop_cmd *, int));
115: static __inline__ void
116: siop_table_sync(siop_cmd, ops)
117: struct siop_cmd *siop_cmd;
118: int ops;
119: {
1.7 bouyer 120: struct siop_softc *sc = siop_cmd->siop_target->siop_sc;
1.2 bouyer 121: bus_addr_t offset;
122:
1.16 bouyer 123: offset = siop_cmd->dsa -
124: siop_cmd->siop_cbdp->xferdma->dm_segs[0].ds_addr;
125: bus_dmamap_sync(sc->sc_dmat, siop_cmd->siop_cbdp->xferdma, offset,
1.2 bouyer 126: sizeof(struct siop_xfer), ops);
127: }
128:
1.17 bouyer 129: static __inline__ void siop_shed_sync __P((struct siop_softc *, int));
1.2 bouyer 130: static __inline__ void
1.17 bouyer 131: siop_shed_sync(sc, ops)
1.2 bouyer 132: struct siop_softc *sc;
133: int ops;
134: {
1.17 bouyer 135: bus_dmamap_sync(sc->sc_dmat, sc->sc_sheddma, 0, NBPG, ops);
1.2 bouyer 136: }
137:
1.1 bouyer 138: void
139: siop_attach(sc)
140: struct siop_softc *sc;
141: {
142: int error, i;
143: bus_dma_segment_t seg;
144: int rseg;
145:
146: /*
1.21 ! bouyer 147: * Allocate DMA-safe memory for the script and script scheduler
1.17 bouyer 148: * and map it.
1.1 bouyer 149: */
1.17 bouyer 150: if ((sc->features & SF_CHIP_RAM) == 0) {
151: error = bus_dmamem_alloc(sc->sc_dmat, NBPG,
152: NBPG, 0, &seg, 1, &rseg, BUS_DMA_NOWAIT);
153: if (error) {
154: printf("%s: unable to allocate script DMA memory, "
155: "error = %d\n", sc->sc_dev.dv_xname, error);
156: return;
157: }
158: error = bus_dmamem_map(sc->sc_dmat, &seg, rseg, NBPG,
159: (caddr_t *)&sc->sc_script, BUS_DMA_NOWAIT|BUS_DMA_COHERENT);
160: if (error) {
161: printf("%s: unable to map script DMA memory, "
162: "error = %d\n", sc->sc_dev.dv_xname, error);
163: return;
164: }
165: error = bus_dmamap_create(sc->sc_dmat, NBPG, 1,
166: NBPG, 0, BUS_DMA_NOWAIT, &sc->sc_scriptdma);
167: if (error) {
168: printf("%s: unable to create script DMA map, "
169: "error = %d\n", sc->sc_dev.dv_xname, error);
170: return;
171: }
172: error = bus_dmamap_load(sc->sc_dmat, sc->sc_scriptdma,
173: sc->sc_script,
174: NBPG, NULL, BUS_DMA_NOWAIT);
175: if (error) {
176: printf("%s: unable to load script DMA map, "
177: "error = %d\n", sc->sc_dev.dv_xname, error);
178: return;
179: }
180: sc->sc_scriptaddr = sc->sc_scriptdma->dm_segs[0].ds_addr;
181: }
1.16 bouyer 182: error = bus_dmamem_alloc(sc->sc_dmat, NBPG,
1.1 bouyer 183: NBPG, 0, &seg, 1, &rseg, BUS_DMA_NOWAIT);
184: if (error) {
1.21 ! bouyer 185: printf("%s: unable to allocate scheduler DMA memory, "
1.17 bouyer 186: "error = %d\n", sc->sc_dev.dv_xname, error);
1.1 bouyer 187: return;
188: }
1.16 bouyer 189: error = bus_dmamem_map(sc->sc_dmat, &seg, rseg, NBPG,
1.17 bouyer 190: (caddr_t *)&sc->sc_shed, BUS_DMA_NOWAIT|BUS_DMA_COHERENT);
1.1 bouyer 191: if (error) {
1.21 ! bouyer 192: printf("%s: unable to map scheduler DMA memory, error = %d\n",
1.1 bouyer 193: sc->sc_dev.dv_xname, error);
194: return;
195: }
1.16 bouyer 196: error = bus_dmamap_create(sc->sc_dmat, NBPG, 1,
1.17 bouyer 197: NBPG, 0, BUS_DMA_NOWAIT, &sc->sc_sheddma);
1.1 bouyer 198: if (error) {
1.21 ! bouyer 199: printf("%s: unable to create scheduler DMA map, error = %d\n",
1.1 bouyer 200: sc->sc_dev.dv_xname, error);
201: return;
202: }
1.17 bouyer 203: error = bus_dmamap_load(sc->sc_dmat, sc->sc_sheddma, sc->sc_shed,
1.16 bouyer 204: NBPG, NULL, BUS_DMA_NOWAIT);
1.1 bouyer 205: if (error) {
1.21 ! bouyer 206: printf("%s: unable to load scheduler DMA map, error = %d\n",
1.1 bouyer 207: sc->sc_dev.dv_xname, error);
208: return;
209: }
210: TAILQ_INIT(&sc->free_list);
1.16 bouyer 211: TAILQ_INIT(&sc->cmds);
1.21 ! bouyer 212: /* compute number of scheduler slots */
1.2 bouyer 213: sc->sc_nshedslots = (
1.21 ! bouyer 214: NBPG /* memory size allocated for scheduler */
! 215: - sizeof(endslot_script) /* memory needed at end of scheduler */
1.2 bouyer 216: ) / (sizeof(slot_script) - 8);
1.7 bouyer 217: sc->sc_currshedslot = 0;
1.1 bouyer 218: #ifdef DEBUG
1.2 bouyer 219: printf("%s: script size = %d, PHY addr=0x%x, VIRT=%p nslots %d\n",
220: sc->sc_dev.dv_xname, (int)sizeof(siop_script),
1.18 bouyer 221: sc->sc_scriptaddr, sc->sc_script, sc->sc_nshedslots);
1.1 bouyer 222: #endif
223:
224: sc->sc_link.adapter_softc = sc;
225: sc->sc_link.openings = 1;
226: sc->sc_link.scsipi_scsi.channel = SCSI_CHANNEL_ONLY_ONE;
227: sc->sc_link.scsipi_scsi.max_target =
228: (sc->features & SF_BUS_WIDE) ? 15 : 7;
229: sc->sc_link.scsipi_scsi.max_lun = 7;
230: sc->sc_link.scsipi_scsi.adapter_target = bus_space_read_1(sc->sc_rt,
231: sc->sc_rh, SIOP_SCID);
1.2 bouyer 232: if (sc->sc_link.scsipi_scsi.adapter_target == 0 ||
233: sc->sc_link.scsipi_scsi.adapter_target >
1.1 bouyer 234: sc->sc_link.scsipi_scsi.max_target)
235: sc->sc_link.scsipi_scsi.adapter_target = SIOP_DEFAULT_TARGET;
236: sc->sc_link.type = BUS_SCSI;
237: sc->sc_link.adapter = &siop_adapter;
238: sc->sc_link.device = &siop_dev;
239: sc->sc_link.flags = 0;
240:
1.7 bouyer 241: for (i = 0; i < 16; i++)
242: sc->targets[i] = NULL;
243:
244: /* find min/max sync period for this chip */
245: sc->maxsync = 0;
246: sc->minsync = 255;
247: for (i = 0; i < sizeof(scf_period) / sizeof(scf_period[0]); i++) {
248: if (sc->clock_period != scf_period[i].clock)
249: continue;
250: if (sc->maxsync < scf_period[i].period)
251: sc->maxsync = scf_period[i].period;
252: if (sc->minsync > scf_period[i].period)
253: sc->minsync = scf_period[i].period;
254: }
255: if (sc->maxsync == 255 || sc->minsync == 0)
256: panic("siop: can't find my sync parameters\n");
1.1 bouyer 257: siop_reset(sc);
1.2 bouyer 258: #ifdef DUMP_SCRIPT
259: siop_dump_script(sc);
260: #endif
1.1 bouyer 261:
262: config_found((struct device*)sc, &sc->sc_link, scsiprint);
263: }
264:
265: void
266: siop_reset(sc)
267: struct siop_softc *sc;
268: {
1.4 bouyer 269: int i, j;
1.2 bouyer 270: u_int32_t *scr;
271: bus_addr_t physaddr;
1.4 bouyer 272:
1.14 bouyer 273: siop_common_reset(sc);
1.1 bouyer 274:
275: /* copy and patch the script */
1.17 bouyer 276: if (sc->features & SF_CHIP_RAM) {
277: bus_space_write_region_4(sc->sc_ramt, sc->sc_ramh, 0,
278: siop_script, sizeof(siop_script) / sizeof(siop_script[0]));
279: for (j = 0; j <
280: (sizeof(E_script_abs_shed_Used) /
281: sizeof(E_script_abs_shed_Used[0]));
282: j++) {
283: bus_space_write_4(sc->sc_ramt, sc->sc_ramh,
284: E_script_abs_shed_Used[j] * 4,
285: sc->sc_sheddma->dm_segs[0].ds_addr);
286: }
287: } else {
288: for (j = 0;
289: j < (sizeof(siop_script) / sizeof(siop_script[0])); j++) {
290: sc->sc_script[j] = htole32(siop_script[j]);
291: }
292: for (j = 0; j <
293: (sizeof(E_script_abs_shed_Used) /
294: sizeof(E_script_abs_shed_Used[0]));
295: j++) {
296: sc->sc_script[E_script_abs_shed_Used[j]] =
297: htole32(sc->sc_sheddma->dm_segs[0].ds_addr);
298: }
1.4 bouyer 299: }
1.21 ! bouyer 300: /* copy and init the scheduler slots script */
1.2 bouyer 301: for (i = 0; i < sc->sc_nshedslots; i++) {
1.17 bouyer 302: scr = &sc->sc_shed[(Ent_nextslot / 4) * i];
303: physaddr = sc->sc_sheddma->dm_segs[0].ds_addr +
304: Ent_nextslot * i;
1.4 bouyer 305: for (j = 0; j < (sizeof(slot_script) / sizeof(slot_script[0]));
306: j++) {
307: scr[j] = htole32(slot_script[j]);
308: }
1.2 bouyer 309: /*
310: * save current jump offset and patch MOVE MEMORY operands
311: * to restore it.
312: */
313: scr[Ent_slotdata/4 + 1] = scr[Ent_slot/4 + 1];
314: scr[E_slot_nextp_Used[0]] = htole32(physaddr + Ent_slot + 4);
315: scr[E_slot_shed_addrsrc_Used[0]] = htole32(physaddr +
316: Ent_slotdata + 4);
317: /* JUMP selected, in main script */
318: scr[E_slot_abs_selected_Used[0]] =
1.17 bouyer 319: htole32(sc->sc_scriptaddr + Ent_selected);
1.2 bouyer 320: /* JUMP addr if SELECT fail */
321: scr[E_slot_abs_reselect_Used[0]] =
1.17 bouyer 322: htole32(sc->sc_scriptaddr + Ent_reselect);
1.2 bouyer 323: }
324: /* Now the final JUMP */
1.17 bouyer 325: scr = &sc->sc_shed[(Ent_nextslot / 4) * sc->sc_nshedslots];
1.4 bouyer 326: for (j = 0; j < (sizeof(endslot_script) / sizeof(endslot_script[0]));
327: j++) {
328: scr[j] = htole32(endslot_script[j]);
329: }
1.2 bouyer 330: scr[E_endslot_abs_reselect_Used[0]] =
1.17 bouyer 331: htole32(sc->sc_scriptaddr + Ent_reselect);
1.1 bouyer 332:
1.2 bouyer 333: /* start script */
1.17 bouyer 334: bus_dmamap_sync(sc->sc_dmat, sc->sc_scriptdma, 0, NBPG,
335: BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
336: siop_shed_sync(sc, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1.2 bouyer 337: bus_space_write_4(sc->sc_rt, sc->sc_rh, SIOP_DSP,
1.17 bouyer 338: sc->sc_scriptaddr + Ent_reselect);
1.1 bouyer 339: }
340:
341: #if 0
342: #define CALL_SCRIPT(ent) do {\
343: printf ("start script DSA 0x%lx DSP 0x%lx\n", \
1.4 bouyer 344: siop_cmd->dsa, \
1.17 bouyer 345: sc->sc_scriptaddr + ent); \
346: bus_space_write_4(sc->sc_rt, sc->sc_rh, SIOP_DSP, sc->sc_scriptaddr + ent); \
1.1 bouyer 347: } while (0)
348: #else
349: #define CALL_SCRIPT(ent) do {\
1.17 bouyer 350: bus_space_write_4(sc->sc_rt, sc->sc_rh, SIOP_DSP, sc->sc_scriptaddr + ent); \
1.1 bouyer 351: } while (0)
352: #endif
353:
354: int
355: siop_intr(v)
356: void *v;
357: {
358: struct siop_softc *sc = v;
1.7 bouyer 359: struct siop_target *siop_target;
1.1 bouyer 360: struct siop_cmd *siop_cmd;
361: struct scsipi_xfer *xs;
1.8 bouyer 362: int istat, sist0, sist1, sstat1, dstat, scntl1;
1.1 bouyer 363: u_int32_t irqcode;
364: int need_reset = 0;
1.7 bouyer 365: int offset, target, lun;
1.2 bouyer 366: bus_addr_t dsa;
1.16 bouyer 367: struct siop_cbd *cbdp;
1.1 bouyer 368:
369: istat = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_ISTAT);
1.2 bouyer 370: if ((istat & (ISTAT_INTF | ISTAT_DIP | ISTAT_SIP)) == 0)
371: return 0;
372: INCSTAT(siop_stat_intr);
1.1 bouyer 373: if (istat & ISTAT_INTF) {
374: printf("INTRF\n");
375: bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_ISTAT, ISTAT_INTF);
376: }
1.2 bouyer 377: /* use DSA to find the current siop_cmd */
378: dsa = bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSA);
1.16 bouyer 379: for (cbdp = TAILQ_FIRST(&sc->cmds); cbdp != NULL;
380: cbdp = TAILQ_NEXT(cbdp, next)) {
381: if (dsa >= cbdp->xferdma->dm_segs[0].ds_addr &&
382: dsa < cbdp->xferdma->dm_segs[0].ds_addr + NBPG) {
383: dsa -= cbdp->xferdma->dm_segs[0].ds_addr;
384: siop_cmd = &cbdp->cmds[dsa / sizeof(struct siop_xfer)];
385: siop_table_sync(siop_cmd,
386: BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
387: break;
388: }
389: }
390: if (cbdp == NULL) {
1.2 bouyer 391: siop_cmd = NULL;
392: }
1.1 bouyer 393: if (istat & ISTAT_DIP) {
394: u_int32_t *p;
395: dstat = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_DSTAT);
1.2 bouyer 396: if (dstat & DSTAT_SSI) {
397: printf("single step dsp 0x%08x dsa 0x08%x\n",
1.7 bouyer 398: (int)(bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSP) -
1.17 bouyer 399: sc->sc_scriptaddr),
1.2 bouyer 400: bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSA));
401: if ((dstat & ~(DSTAT_DFE | DSTAT_SSI)) == 0 &&
402: (istat & ISTAT_SIP) == 0) {
403: bus_space_write_1(sc->sc_rt, sc->sc_rh,
404: SIOP_DCNTL, bus_space_read_1(sc->sc_rt,
405: sc->sc_rh, SIOP_DCNTL) | DCNTL_STD);
406: }
407: return 1;
408: }
409: if (dstat & ~(DSTAT_SIR | DSTAT_DFE | DSTAT_SSI)) {
1.1 bouyer 410: printf("DMA IRQ:");
411: if (dstat & DSTAT_IID)
412: printf(" Illegal instruction");
413: if (dstat & DSTAT_ABRT)
414: printf(" abort");
415: if (dstat & DSTAT_BF)
416: printf(" bus fault");
417: if (dstat & DSTAT_MDPE)
418: printf(" parity");
419: if (dstat & DSTAT_DFE)
420: printf(" dma fifo empty");
421: printf(", DSP=0x%x DSA=0x%x: ",
1.7 bouyer 422: (int)(bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSP) -
1.17 bouyer 423: sc->sc_scriptaddr),
1.1 bouyer 424: bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSA));
1.2 bouyer 425: p = sc->sc_script +
1.1 bouyer 426: (bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSP) -
1.17 bouyer 427: sc->sc_scriptaddr - 8) / 4;
1.4 bouyer 428: printf("0x%x 0x%x 0x%x 0x%x\n", le32toh(p[0]), le32toh(p[1]),
429: le32toh(p[2]), le32toh(p[3]));
1.2 bouyer 430: if (siop_cmd)
1.1 bouyer 431: printf("last msg_in=0x%x status=0x%x\n",
1.2 bouyer 432: siop_cmd->siop_table->msg_in[0],
1.6 bouyer 433: le32toh(siop_cmd->siop_table->status));
1.20 bouyer 434: else
435: printf("%s: current DSA invalid\n",
436: sc->sc_dev.dv_xname);
1.1 bouyer 437: need_reset = 1;
438: }
439: }
440: if (istat & ISTAT_SIP) {
1.2 bouyer 441: /*
442: * SCSI interrupt. If current command is not active,
443: * we don't need siop_cmd
444: */
1.17 bouyer 445: if (siop_cmd && siop_cmd->status != CMDST_ACTIVE &&
1.2 bouyer 446: siop_cmd->status != CMDST_SENSE_ACTIVE) {
447: siop_cmd = NULL;
448: }
1.1 bouyer 449: if (istat & ISTAT_DIP)
1.8 bouyer 450: delay(10);
1.1 bouyer 451: sist0 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SIST0);
1.8 bouyer 452: delay(10);
1.1 bouyer 453: sist1 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SIST1);
454: sstat1 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SSTAT1);
1.8 bouyer 455: #ifdef DEBUG_INTR
1.1 bouyer 456: printf("scsi interrupt, sist0=0x%x sist1=0x%x sstat1=0x%x "
1.8 bouyer 457: "DSA=0x%x DSP=0x%lx\n", sist0, sist1,
1.1 bouyer 458: bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SSTAT1),
459: bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSA),
1.8 bouyer 460: (u_long)(bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSP) -
1.17 bouyer 461: sc->sc_scriptaddr));
1.1 bouyer 462: #endif
1.7 bouyer 463: if (siop_cmd) {
1.1 bouyer 464: xs = siop_cmd->xs;
1.7 bouyer 465: siop_target = siop_cmd->siop_target;
466: }
1.1 bouyer 467: if (sist0 & SIST0_RST) {
1.2 bouyer 468: siop_handle_reset(sc);
1.1 bouyer 469: siop_start(sc);
1.2 bouyer 470: /* no table to flush here */
1.1 bouyer 471: return 1;
472: }
473: if (sist0 & SIST0_SGE) {
474: if (siop_cmd)
475: scsi_print_addr(xs->sc_link);
476: else
477: printf("%s:", sc->sc_dev.dv_xname);
478: printf("scsi gross error\n");
479: goto reset;
480: }
481: if ((sist0 & SIST0_MA) && need_reset == 0) {
482: if (siop_cmd) {
1.8 bouyer 483: int scratcha0;
484: dstat = bus_space_read_1(sc->sc_rt, sc->sc_rh,
485: SIOP_DSTAT);
1.3 bouyer 486: /*
487: * first restore DSA, in case we were in a S/G
488: * operation.
489: */
490: bus_space_write_4(sc->sc_rt, sc->sc_rh,
1.4 bouyer 491: SIOP_DSA, siop_cmd->dsa);
1.8 bouyer 492: scratcha0 = bus_space_read_1(sc->sc_rt,
493: sc->sc_rh, SIOP_SCRATCHA);
1.1 bouyer 494: switch (sstat1 & SSTAT1_PHASE_MASK) {
495: case SSTAT1_PHASE_STATUS:
496: /*
497: * previous phase may be aborted for any reason
498: * ( for example, the target has less data to
499: * transfer than requested). Just go to status
500: * and the command should terminate.
501: */
1.2 bouyer 502: INCSTAT(siop_stat_intr_shortxfer);
1.1 bouyer 503: CALL_SCRIPT(Ent_status);
1.8 bouyer 504: if ((dstat & DSTAT_DFE) == 0)
505: siop_clearfifo(sc);
1.2 bouyer 506: /* no table to flush here */
1.1 bouyer 507: return 1;
508: case SSTAT1_PHASE_MSGIN:
509: /*
510: * target may be ready to disconnect
511: * Save data pointers just in case.
512: */
1.2 bouyer 513: INCSTAT(siop_stat_intr_xferdisc);
1.8 bouyer 514: if (scratcha0 & A_flag_data)
515: siop_sdp(siop_cmd);
516: else if ((dstat & DSTAT_DFE) == 0)
517: siop_clearfifo(sc);
518: bus_space_write_1(sc->sc_rt, sc->sc_rh,
519: SIOP_SCRATCHA,
520: scratcha0 & ~A_flag_data);
1.2 bouyer 521: siop_table_sync(siop_cmd,
522: BUS_DMASYNC_PREREAD |
523: BUS_DMASYNC_PREWRITE);
1.1 bouyer 524: CALL_SCRIPT(Ent_msgin);
525: return 1;
526: }
527: printf("%s: unexpected phase mismatch %d\n",
528: sc->sc_dev.dv_xname,
529: sstat1 & SSTAT1_PHASE_MASK);
530: } else {
531: printf("%s: phase mismatch without command\n",
532: sc->sc_dev.dv_xname);
533: }
534: need_reset = 1;
535: }
536: if (sist0 & SIST0_PAR) {
537: /* parity error, reset */
538: if (siop_cmd)
539: scsi_print_addr(xs->sc_link);
540: else
541: printf("%s:", sc->sc_dev.dv_xname);
542: printf("parity error\n");
1.11 bouyer 543: goto reset;
1.1 bouyer 544: }
545: if ((sist1 & SIST1_STO) && need_reset == 0) {
546: /* selection time out, assume there's no device here */
547: if (siop_cmd) {
548: siop_cmd->status = CMDST_DONE;
549: xs->error = XS_SELTIMEOUT;
550: goto end;
551: } else {
552: printf("%s: selection timeout without "
553: "command\n", sc->sc_dev.dv_xname);
554: need_reset = 1;
555: }
556: }
557: if (sist0 & SIST0_UDC) {
558: /*
559: * unexpected disconnect. Usually the target signals
560: * a fatal condition this way. Attempt to get sense.
561: */
562: if (siop_cmd)
1.7 bouyer 563: goto check_sense;
1.1 bouyer 564: printf("%s: unexpected disconnect without "
565: "command\n", sc->sc_dev.dv_xname);
1.2 bouyer 566: goto reset;
1.1 bouyer 567: }
1.20 bouyer 568: if (sist1 & SIST1_SBMC) {
569: /* SCSI bus mode change */
570: if (siop_modechange(sc) == 0 || need_reset == 1)
571: goto reset;
572: if ((istat & ISTAT_DIP) && (dstat & DSTAT_SIR)) {
573: /*
574: * we have a script interrupt, it will
575: * restart the script.
576: */
577: goto scintr;
578: }
579: /*
580: * else we have to restart it ourselve, at the
581: * interrupted instruction.
582: */
583: bus_space_write_4(sc->sc_rt, sc->sc_rh, SIOP_DSP,
584: bus_space_read_4(sc->sc_rt, sc->sc_rh,
585: SIOP_DSP) - 8);
586: return 1;
587: }
1.1 bouyer 588: /* Else it's an unhandled exeption (for now). */
589: printf("%s: unhandled scsi interrupt, sist0=0x%x sist1=0x%x "
590: "sstat1=0x%x DSA=0x%x DSP=0x%x\n", sc->sc_dev.dv_xname,
591: sist0, sist1,
592: bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SSTAT1),
593: bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSA),
1.7 bouyer 594: (int)(bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSP) -
1.17 bouyer 595: sc->sc_scriptaddr));
1.1 bouyer 596: if (siop_cmd) {
597: siop_cmd->status = CMDST_DONE;
598: xs->error = XS_SELTIMEOUT;
599: goto end;
600: }
601: need_reset = 1;
602: }
603: if (need_reset) {
604: reset:
605: /* fatal error, reset the bus */
606: scntl1 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1);
607: bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1,
608: scntl1 | SCNTL1_RST);
609: /* minimum 25 us, more time won't hurt */
610: delay(100);
611: bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1, scntl1);
1.2 bouyer 612: /* no table to flush here */
1.1 bouyer 613: return 1;
614: }
615:
1.20 bouyer 616: scintr:
1.1 bouyer 617: if ((istat & ISTAT_DIP) && (dstat & DSTAT_SIR)) { /* script interrupt */
618: irqcode = bus_space_read_4(sc->sc_rt, sc->sc_rh,
619: SIOP_DSPS);
1.2 bouyer 620: #ifdef DEBUG_INTR
621: printf("script interrupt 0x%x\n", irqcode);
622: #endif
1.16 bouyer 623: if (siop_cmd == NULL) {
624: printf("%s: script interrupt (0x%x) with invalid "
625: "DSA !!!\n", sc->sc_dev.dv_xname, irqcode);
626: goto reset;
627: }
1.2 bouyer 628: /*
629: * an inactive command is only valid if it's a reselect
630: * interrupt: we'll change siop_cmd to point to the rigth one
631: * just here
632: */
1.14 bouyer 633: if (irqcode != A_int_resel && irqcode != A_int_reseltag &&
1.2 bouyer 634: siop_cmd->status != CMDST_ACTIVE &&
635: siop_cmd->status != CMDST_SENSE_ACTIVE) {
636: printf("%s: Aie, no command (IRQ code 0x%x current "
637: "status %d) !\n", sc->sc_dev.dv_xname,
638: irqcode, siop_cmd->status);
639: xs = NULL;
1.7 bouyer 640: } else {
1.2 bouyer 641: xs = siop_cmd->xs;
1.7 bouyer 642: siop_target = siop_cmd->siop_target;
643: }
1.1 bouyer 644: switch(irqcode) {
645: case A_int_err:
1.2 bouyer 646: printf("error, DSP=0x%x\n",
1.17 bouyer 647: (int)(bus_space_read_4(sc->sc_rt, sc->sc_rh,
648: SIOP_DSP) - sc->sc_scriptaddr));
1.2 bouyer 649: if (xs) {
650: xs->error = XS_SELTIMEOUT;
651: goto end;
652: } else {
653: goto reset;
654: }
1.1 bouyer 655: case A_int_msgin:
1.2 bouyer 656: if (siop_cmd->siop_table->msg_in[0] ==
657: MSG_MESSAGE_REJECT) {
1.8 bouyer 658: int msg, extmsg;
659: if (siop_cmd->siop_table->msg_out[0] & 0x80) {
660: /*
661: * message was part of a identify +
662: * something else. Identify shoudl't
663: * have been rejected.
664: */
665: msg = siop_cmd->siop_table->msg_out[1];
666: extmsg =
667: siop_cmd->siop_table->msg_out[3];
668: } else {
669: msg = siop_cmd->siop_table->msg_out[0];
670: extmsg =
671: siop_cmd->siop_table->msg_out[2];
672: }
673: if (msg == MSG_MESSAGE_REJECT) {
1.2 bouyer 674: /* MSG_REJECT for a MSG_REJECT !*/
1.9 bouyer 675: if (xs)
676: scsi_print_addr(xs->sc_link);
677: else
678: printf("%s: ",
679: sc->sc_dev.dv_xname);
680: printf("our reject message was "
681: "rejected\n");
1.2 bouyer 682: goto reset;
683: }
1.8 bouyer 684: if (msg == MSG_EXTENDED &&
685: extmsg == MSG_EXT_WDTR) {
1.9 bouyer 686: /* WDTR rejected, initiate sync */
687: printf("%s: target %d using 8bit "
688: "transfers\n", sc->sc_dev.dv_xname,
689: xs->sc_link->scsipi_scsi.target);
690: siop_target->status = TARST_SYNC_NEG;
691: siop_cmd->siop_table->msg_out[0] =
692: MSG_EXTENDED;
693: siop_cmd->siop_table->msg_out[1] =
694: MSG_EXT_SDTR_LEN;
695: siop_cmd->siop_table->msg_out[2] =
696: MSG_EXT_SDTR;
697: siop_cmd->siop_table->msg_out[3] =
698: sc->minsync;
699: siop_cmd->siop_table->msg_out[4] =
700: sc->maxoff;
701: siop_cmd->siop_table->t_msgout.count =
702: htole32(MSG_EXT_SDTR_LEN + 2);
703: siop_cmd->siop_table->t_msgout.addr =
704: htole32(siop_cmd->dsa);
705: siop_table_sync(siop_cmd,
706: BUS_DMASYNC_PREREAD |
707: BUS_DMASYNC_PREWRITE);
708: CALL_SCRIPT(Ent_send_msgout);
709: return 1;
1.8 bouyer 710: } else if (msg == MSG_EXTENDED &&
711: extmsg == MSG_EXT_SDTR) {
1.7 bouyer 712: /* sync rejected */
1.9 bouyer 713: printf("%s: target %d asynchronous\n",
714: sc->sc_dev.dv_xname,
715: xs->sc_link->scsipi_scsi.target);
1.7 bouyer 716: siop_cmd->siop_target->status =
717: TARST_OK;
1.9 bouyer 718: /* no table to flush here */
719: CALL_SCRIPT(Ent_msgin_ack);
720: return 1;
721: }
722: if (xs)
723: scsi_print_addr(xs->sc_link);
724: else
725: printf("%s: ", sc->sc_dev.dv_xname);
726: if (msg == MSG_EXTENDED) {
727: printf("scsi message reject, extended "
728: "message sent was 0x%x\n", extmsg);
729: } else {
730: printf("scsi message reject, message "
731: "sent was 0x%x\n", msg);
1.7 bouyer 732: }
1.2 bouyer 733: /* no table to flush here */
734: CALL_SCRIPT(Ent_msgin_ack);
735: return 1;
736: }
1.9 bouyer 737: if (xs)
738: scsi_print_addr(xs->sc_link);
739: else
740: printf("%s: ", sc->sc_dev.dv_xname);
1.8 bouyer 741: printf("unhandled message 0x%x\n",
742: siop_cmd->siop_table->msg_in[0]);
1.2 bouyer 743: siop_cmd->siop_table->t_msgout.count= htole32(1);
744: siop_cmd->siop_table->t_msgout.addr =
745: htole32(siop_cmd->dsa);
746: siop_cmd->siop_table->msg_out[0] = MSG_MESSAGE_REJECT;
747: siop_table_sync(siop_cmd,
748: BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
749: CALL_SCRIPT(Ent_send_msgout);
750: return 1;
751: case A_int_extmsgin:
752: #ifdef DEBUG_INTR
753: printf("extended message: msg 0x%x len %d\n",
754: siop_cmd->siop_table->msg_in[2],
755: siop_cmd->siop_table->msg_in[1]);
756: #endif
1.8 bouyer 757: if (siop_cmd->siop_table->msg_in[1] > 6)
758: printf("%s: extended message too big (%d)\n",
759: sc->sc_dev.dv_xname,
760: siop_cmd->siop_table->msg_in[1]);
1.2 bouyer 761: siop_cmd->siop_table->t_extmsgdata.count =
762: htole32(siop_cmd->siop_table->msg_in[1] - 1);
763: siop_cmd->siop_table->t_extmsgdata.addr =
764: htole32(
1.4 bouyer 765: le32toh(siop_cmd->siop_table->t_extmsgin.addr)
1.2 bouyer 766: + 2);
767: siop_table_sync(siop_cmd,
768: BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
769: CALL_SCRIPT(Ent_get_extmsgdata);
770: return 1;
771: case A_int_extmsgdata:
772: #ifdef DEBUG_INTR
773: {
774: int i;
775: printf("extended message: 0x%x, data:",
776: siop_cmd->siop_table->msg_in[2]);
777: for (i = 3; i < 2 + siop_cmd->siop_table->msg_in[1];
778: i++)
779: printf(" 0x%x",
780: siop_cmd->siop_table->msg_in[i]);
781: printf("\n");
782: }
783: #endif
1.7 bouyer 784: if (siop_cmd->siop_table->msg_in[2] == MSG_EXT_WDTR) {
1.14 bouyer 785: switch (siop_wdtr_neg(siop_cmd)) {
786: case SIOP_NEG_NOP:
787: break;
788: case SIOP_NEG_MSGOUT:
789: siop_table_sync(siop_cmd,
790: BUS_DMASYNC_PREREAD |
791: BUS_DMASYNC_PREWRITE);
792: CALL_SCRIPT(Ent_send_msgout);
793: break;
794: default:
795: panic("invalid retval from "
796: "siop_wdtr_neg()");
797: }
1.7 bouyer 798: return(1);
799: }
1.2 bouyer 800: if (siop_cmd->siop_table->msg_in[2] == MSG_EXT_SDTR) {
1.14 bouyer 801: switch (siop_sdtr_neg(siop_cmd)) {
802: case SIOP_NEG_NOP:
803: break;
804: case SIOP_NEG_MSGOUT:
805: siop_table_sync(siop_cmd,
806: BUS_DMASYNC_PREREAD |
807: BUS_DMASYNC_PREWRITE);
808: CALL_SCRIPT(Ent_send_msgout);
809: break;
810: case SIOP_NEG_ACK:
811: CALL_SCRIPT(Ent_msgin_ack);
812: break;
813: default:
814: panic("invalid retval from "
815: "siop_wdtr_neg()");
816: }
1.7 bouyer 817: return(1);
1.2 bouyer 818: }
1.7 bouyer 819: /* send a message reject */
820: siop_cmd->siop_table->t_msgout.count =
821: htole32(1);
822: siop_cmd->siop_table->t_msgout.addr =
823: htole32(siop_cmd->dsa);
824: siop_cmd->siop_table->msg_out[0] =
825: MSG_MESSAGE_REJECT;
1.2 bouyer 826: siop_table_sync(siop_cmd,
827: BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
828: CALL_SCRIPT(Ent_send_msgout);
829: return 1;
1.1 bouyer 830: case A_int_resel: /* reselected */
1.14 bouyer 831: case A_int_reseltag: /* reselected with tag */
1.2 bouyer 832: INCSTAT(siop_stat_intr_reselect);
833: if ((siop_cmd->siop_table->msg_in[0] & 0x80) == 0) {
1.1 bouyer 834: printf("%s: reselect without identify (%d)\n",
835: sc->sc_dev.dv_xname,
1.2 bouyer 836: siop_cmd->siop_table->msg_in[0]);
1.1 bouyer 837: goto reset;
838: }
1.2 bouyer 839: target = bus_space_read_1(sc->sc_rt,
1.1 bouyer 840: sc->sc_rh, SIOP_SCRATCHA);
1.2 bouyer 841: if ((target & 0x80) == 0) {
842: printf("reselect without id (%d)\n", target);
1.1 bouyer 843: goto reset;
844: }
1.2 bouyer 845: target &= 0x0f;
1.7 bouyer 846: lun = siop_cmd->siop_table->msg_in[0] & 0x07;
1.1 bouyer 847: #ifdef DEBUG_DR
848: printf("reselected by target %d lun %d\n",
1.7 bouyer 849: target, lun);
1.1 bouyer 850: #endif
851: siop_cmd =
1.7 bouyer 852: sc->targets[target]->active_list[lun].tqh_first;
1.1 bouyer 853: if (siop_cmd == NULL) {
854: printf("%s: reselected without cmd\n",
855: sc->sc_dev.dv_xname);
856: goto reset;
857: }
1.4 bouyer 858: bus_space_write_4(sc->sc_rt, sc->sc_rh, SIOP_DSA,
859: siop_cmd->dsa);
1.11 bouyer 860: bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL3,
861: (sc->targets[target]->id >> 24) & 0xff);
862: bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCXFER,
863: (sc->targets[target]->id >> 8) & 0xff);
1.2 bouyer 864: /* no table to flush */
865: CALL_SCRIPT(Ent_selected);
1.1 bouyer 866: return 1;
867: case A_int_disc:
1.2 bouyer 868: INCSTAT(siop_stat_intr_sdp);
1.1 bouyer 869: offset = bus_space_read_1(sc->sc_rt, sc->sc_rh,
870: SIOP_SCRATCHA + 1);
871: #ifdef DEBUG_DR
872: printf("disconnect offset %d\n", offset);
873: #endif
874: if (offset > SIOP_NSG) {
875: printf("%s: bad offset for disconnect (%d)\n",
876: sc->sc_dev.dv_xname, offset);
877: goto reset;
878: }
879: /*
880: * offset == SIOP_NSG may be a valid condition if
881: * we get a sdp when the xfer is done.
882: * Don't call memmove in this case.
883: */
884: if (offset < SIOP_NSG) {
885: memmove(&siop_cmd->siop_table->data[0],
886: &siop_cmd->siop_table->data[offset],
887: (SIOP_NSG - offset) * sizeof(scr_table_t));
1.2 bouyer 888: siop_table_sync(siop_cmd,
889: BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1.1 bouyer 890: }
1.17 bouyer 891: bus_space_write_4(sc->sc_rt, sc->sc_rh, SIOP_DSP,
892: sc->sc_sheddma->dm_segs[0].ds_addr);
1.1 bouyer 893: return 1;
894: case A_int_resfail:
895: printf("reselect failed\n");
1.17 bouyer 896: bus_space_write_4(sc->sc_rt, sc->sc_rh, SIOP_DSP,
897: sc->sc_sheddma->dm_segs[0].ds_addr);
1.1 bouyer 898: return 1;
899: case A_int_done:
1.2 bouyer 900: if (xs == NULL) {
1.8 bouyer 901: printf("%s: done without command, DSA=0x%lx\n",
902: sc->sc_dev.dv_xname, (u_long)siop_cmd->dsa);
903: siop_cmd->status = CMDST_FREE;
1.17 bouyer 904: bus_space_write_4(sc->sc_rt, sc->sc_rh,
905: SIOP_DSP,
906: sc->sc_sheddma->dm_segs[0].ds_addr);
1.2 bouyer 907: siop_start(sc);
908: return 1;
909: }
1.7 bouyer 910: if (siop_target->status == TARST_PROBING)
911: siop_target->status = TARST_ASYNC;
1.8 bouyer 912: #ifdef DEBUG_INTR
913: printf("done, DSA=0x%lx target id 0x%x last msg "
914: "in=0x%x status=0x%x\n", (u_long)siop_cmd->dsa,
1.4 bouyer 915: le32toh(siop_cmd->siop_table->id),
1.2 bouyer 916: siop_cmd->siop_table->msg_in[0],
1.4 bouyer 917: le32toh(siop_cmd->siop_table->status));
1.1 bouyer 918: #endif
1.2 bouyer 919: INCSTAT(siop_stat_intr_done);
920: if (siop_cmd->status == CMDST_SENSE_ACTIVE)
1.1 bouyer 921: siop_cmd->status = CMDST_SENSE_DONE;
922: else
923: siop_cmd->status = CMDST_DONE;
1.4 bouyer 924: switch(le32toh(siop_cmd->siop_table->status)) {
1.1 bouyer 925: case SCSI_OK:
926: xs->error = (siop_cmd->status == CMDST_DONE) ?
927: XS_NOERROR : XS_SENSE;
928: break;
929: case SCSI_BUSY:
930: xs->error = XS_BUSY;
931: break;
932: case SCSI_CHECK:
933: check_sense:
934: if (siop_cmd->status == CMDST_SENSE_DONE) {
1.2 bouyer 935: /* request sense on a request sense ? */
936: printf("request sense failed\n");
1.1 bouyer 937: xs->error = XS_DRIVER_STUFFUP;
938: } else {
939: siop_cmd->status = CMDST_SENSE;
940: }
941: break;
942: case 0xff:
943: /*
944: * the status byte was not updated, cmd was
945: * aborted
946: */
947: xs->error = XS_SELTIMEOUT;
1.2 bouyer 948: break;
1.1 bouyer 949: default:
950: xs->error = XS_DRIVER_STUFFUP;
951: }
952: goto end;
953: default:
954: printf("unknown irqcode %x\n", irqcode);
955: xs->error = XS_SELTIMEOUT;
956: goto end;
957: }
958: return 1;
959: }
1.2 bouyer 960: /* We just should't get there */
961: panic("siop_intr: I shouldn't be there !");
962: return 1;
1.1 bouyer 963: end:
1.7 bouyer 964: bus_space_write_4(sc->sc_rt, sc->sc_rh, SIOP_DSP,
1.17 bouyer 965: sc->sc_sheddma->dm_segs[0].ds_addr);
1.7 bouyer 966: lun = siop_cmd->xs->sc_link->scsipi_scsi.lun;
1.2 bouyer 967: siop_scsicmd_end(siop_cmd);
968: if (siop_cmd->status == CMDST_FREE) {
1.7 bouyer 969: TAILQ_REMOVE(&siop_target->active_list[lun],
1.2 bouyer 970: siop_cmd, next);
971: TAILQ_INSERT_TAIL(&sc->free_list, siop_cmd, next);
972: }
973: siop_start(sc);
974: return 1;
975: }
976:
977: void
978: siop_scsicmd_end(siop_cmd)
979: struct siop_cmd *siop_cmd;
980: {
981: struct scsipi_xfer *xs = siop_cmd->xs;
1.7 bouyer 982: struct siop_softc *sc = siop_cmd->siop_target->siop_sc;
1.2 bouyer 983:
1.1 bouyer 984: if (siop_cmd->status != CMDST_SENSE_DONE &&
985: xs->xs_control & (XS_CTL_DATA_IN | XS_CTL_DATA_OUT)) {
986: bus_dmamap_sync(sc->sc_dmat, siop_cmd->dmamap_data, 0,
987: siop_cmd->dmamap_data->dm_mapsize,
988: (xs->xs_control & XS_CTL_DATA_IN) ?
989: BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
990: bus_dmamap_unload(sc->sc_dmat, siop_cmd->dmamap_data);
991: }
992: bus_dmamap_unload(sc->sc_dmat, siop_cmd->dmamap_cmd);
993: if (siop_cmd->status == CMDST_SENSE) {
994: /* issue a request sense for this target */
995: int error, i;
996: siop_cmd->rs_cmd.opcode = REQUEST_SENSE;
997: siop_cmd->rs_cmd.byte2 = xs->sc_link->scsipi_scsi.lun << 5;
998: siop_cmd->rs_cmd.unused[0] = siop_cmd->rs_cmd.unused[1] = 0;
999: siop_cmd->rs_cmd.length = sizeof(struct scsipi_sense_data);
1000: siop_cmd->rs_cmd.control = 0;
1.2 bouyer 1001: siop_cmd->siop_table->status = htole32(0xff); /*invalid status*/
1002: siop_cmd->siop_table->t_msgout.count= htole32(1);
1003: siop_cmd->siop_table->t_msgout.addr = htole32(siop_cmd->dsa);
1004: siop_cmd->siop_table->msg_out[0] =
1005: MSG_IDENTIFY(xs->sc_link->scsipi_scsi.lun, 1);
1.1 bouyer 1006: error = bus_dmamap_load(sc->sc_dmat, siop_cmd->dmamap_cmd,
1007: &siop_cmd->rs_cmd, sizeof(struct scsipi_sense),
1008: NULL, BUS_DMA_NOWAIT);
1009: if (error) {
1010: printf("%s: unable to load cmd DMA map: %d",
1011: sc->sc_dev.dv_xname, error);
1012: xs->error = XS_DRIVER_STUFFUP;
1013: goto out;
1014: }
1015: siop_cmd->siop_table->cmd.count =
1016: htole32(siop_cmd->dmamap_cmd->dm_segs[0].ds_len);
1017: siop_cmd->siop_table->cmd.addr =
1018: htole32(siop_cmd->dmamap_cmd->dm_segs[0].ds_addr);
1019: error = bus_dmamap_load(sc->sc_dmat, siop_cmd->dmamap_data,
1020: &xs->sense.scsi_sense, sizeof(struct scsipi_sense_data),
1021: NULL, BUS_DMA_NOWAIT);
1022: if (error) {
1023: printf("%s: unable to load sense DMA map: %d",
1024: sc->sc_dev.dv_xname, error);
1025: xs->error = XS_DRIVER_STUFFUP;
1026: bus_dmamap_unload(sc->sc_dmat, siop_cmd->dmamap_cmd);
1027: goto out;
1028: }
1029: for (i = 0; i < siop_cmd->dmamap_data->dm_nsegs; i++) {
1030: siop_cmd->siop_table->data[i].count =
1031: htole32(siop_cmd->dmamap_data->dm_segs[i].ds_len);
1032: siop_cmd->siop_table->data[i].addr =
1033: htole32(siop_cmd->dmamap_data->dm_segs[i].ds_addr);
1034: }
1035: bus_dmamap_sync(sc->sc_dmat, siop_cmd->dmamap_data, 0,
1036: siop_cmd->dmamap_data->dm_mapsize, BUS_DMASYNC_PREREAD);
1037: bus_dmamap_sync(sc->sc_dmat, siop_cmd->dmamap_cmd, 0,
1038: siop_cmd->dmamap_cmd->dm_mapsize, BUS_DMASYNC_PREWRITE);
1.2 bouyer 1039: siop_table_sync(siop_cmd, BUS_DMASYNC_PREWRITE);
1040: return;
1.1 bouyer 1041: } else if (siop_cmd->status == CMDST_SENSE_DONE) {
1042: bus_dmamap_sync(sc->sc_dmat, siop_cmd->dmamap_data, 0,
1043: siop_cmd->dmamap_data->dm_mapsize, BUS_DMASYNC_POSTREAD);
1044: bus_dmamap_unload(sc->sc_dmat, siop_cmd->dmamap_data);
1045: }
1046: out:
1047: callout_stop(&siop_cmd->xs->xs_callout);
1048: siop_cmd->status = CMDST_FREE;
1049: xs->xs_status |= XS_STS_DONE;
1050: xs->resid = 0;
1.14 bouyer 1051: if ((xs->xs_control & XS_CTL_POLL) == 0)
1052: scsipi_done (xs);
1.7 bouyer 1053: }
1054:
1.2 bouyer 1055: /*
1056: * handle a bus reset: reset chip, unqueue all active commands and report
1057: * loosage to upper layer.
1058: * As the upper layer may requeue immediatly we have to first store
1059: * all active commands in a temporary queue.
1060: */
1061: void
1062: siop_handle_reset(sc)
1063: struct siop_softc *sc;
1064: {
1065: struct cmd_list reset_list;
1066: struct siop_cmd *siop_cmd, *next_siop_cmd;
1.7 bouyer 1067: int target, lun;
1.2 bouyer 1068: /*
1069: * scsi bus reset. reset the chip and restart
1070: * the queue. Need to clean up all active commands
1071: */
1072: printf("%s: scsi bus reset\n", sc->sc_dev.dv_xname);
1073: /* stop, reset and restart the chip */
1074: siop_reset(sc);
1075: TAILQ_INIT(&reset_list);
1076: /* find all active commands */
1.7 bouyer 1077: for (target = 0; target < sc->sc_link.scsipi_scsi.max_target;
1078: target++) {
1079: if (sc->targets[target] == NULL)
1080: continue;
1081: for (lun = 0; lun < 8; lun++) {
1082: for (siop_cmd =
1083: TAILQ_FIRST(&sc->targets[target]->active_list[lun]);
1084: siop_cmd != NULL; siop_cmd = next_siop_cmd) {
1085: next_siop_cmd = TAILQ_NEXT(siop_cmd, next);
1086: if (siop_cmd->status < CMDST_ACTIVE)
1087: continue;
1088: printf("cmd %p (target %d) in reset list\n",
1089: siop_cmd, target);
1090: TAILQ_REMOVE(
1091: &sc->targets[target]->active_list[lun],
1092: siop_cmd, next);
1093: TAILQ_INSERT_TAIL(&reset_list, siop_cmd, next);
1094: }
1.2 bouyer 1095: }
1.7 bouyer 1096: sc->targets[target]->status = TARST_ASYNC;
1097: sc->targets[target]->flags = ~(TARF_SYNC | TARF_WIDE);
1.2 bouyer 1098: }
1099: for (siop_cmd = TAILQ_FIRST(&reset_list); siop_cmd != NULL;
1100: siop_cmd = next_siop_cmd) {
1101: next_siop_cmd = TAILQ_NEXT(siop_cmd, next);
1102: siop_cmd->xs->error = (siop_cmd->flags & CMDFL_TIMEOUT) ?
1103: XS_TIMEOUT : XS_RESET;
1104: printf("cmd %p about to be processed\n", siop_cmd);
1.16 bouyer 1105: if (siop_cmd->status == CMDST_SENSE ||
1106: siop_cmd->status == CMDST_SENSE_ACTIVE)
1107: siop_cmd->status = CMDST_SENSE_DONE;
1108: else
1109: siop_cmd->status = CMDST_DONE;
1.2 bouyer 1110: TAILQ_REMOVE(&reset_list, siop_cmd, next);
1111: siop_scsicmd_end(siop_cmd);
1112: TAILQ_INSERT_TAIL(&sc->free_list, siop_cmd, next);
1113: }
1.1 bouyer 1114: }
1115:
1.2 bouyer 1116: int
1.1 bouyer 1117: siop_scsicmd(xs)
1118: struct scsipi_xfer *xs;
1119: {
1120: struct siop_softc *sc = (struct siop_softc *)xs->sc_link->adapter_softc;
1121: struct siop_cmd *siop_cmd;
1122: int s, error, i;
1.7 bouyer 1123: int target = xs->sc_link->scsipi_scsi.target;
1124: int lun = xs->sc_link->scsipi_scsi.lun;
1.1 bouyer 1125:
1126: s = splbio();
1.7 bouyer 1127: #ifdef DEBUG_SHED
1128: printf("starting cmd for %d:%d\n", target, lun);
1.1 bouyer 1129: #endif
1130: siop_cmd = sc->free_list.tqh_first;
1131: if (siop_cmd) {
1132: TAILQ_REMOVE(&sc->free_list, siop_cmd, next);
1.16 bouyer 1133: } else {
1134: if (siop_morecbd(sc) == 0) {
1135: siop_cmd = sc->free_list.tqh_first;
1136: #ifdef DIAGNOSTIC
1137: if (siop_cmd == NULL)
1138: panic("siop_morecbd succeed and does nothing");
1139: #endif
1140: TAILQ_REMOVE(&sc->free_list, siop_cmd, next);
1141: }
1.1 bouyer 1142: }
1143: splx(s);
1144: if (siop_cmd == NULL) {
1145: xs->error = XS_DRIVER_STUFFUP;
1146: return(TRY_AGAIN_LATER);
1147: }
1148: #ifdef DIAGNOSTIC
1149: if (siop_cmd->status != CMDST_FREE)
1150: panic("siop_scsicmd: new cmd not free");
1151: #endif
1.7 bouyer 1152: if (sc->targets[target] == NULL) {
1153: sc->targets[target] =
1154: malloc(sizeof(struct siop_target), M_DEVBUF, M_NOWAIT);
1155: if (sc->targets[target] == NULL) {
1156: printf("%s: can't malloc memory for target %d\n",
1157: sc->sc_dev.dv_xname, target);
1158: xs->error = XS_DRIVER_STUFFUP;
1159: return(TRY_AGAIN_LATER);
1160: }
1161: sc->targets[target]->siop_sc = sc;
1162: sc->targets[target]->status = TARST_PROBING;
1163: sc->targets[target]->flags = 0;
1164: sc->targets[target]->id = sc->clock_div << 24; /* scntl3 */
1165: sc->targets[target]->id |= target << 16; /* id */
1.14 bouyer 1166: /* sc->targets[target]->id |= 0x0 << 8; scxfer is 0 */
1.7 bouyer 1167: for (i = 0; i < 8; i++)
1168: TAILQ_INIT(&sc->targets[target]->active_list[i]);
1169: }
1170: siop_cmd->siop_target = sc->targets[target];
1.1 bouyer 1171: siop_cmd->xs = xs;
1.7 bouyer 1172: siop_cmd->siop_table->id = htole32(sc->targets[target]->id);
1.2 bouyer 1173: siop_cmd->siop_table->t_msgout.count= htole32(1);
1174: siop_cmd->siop_table->t_msgout.addr = htole32(siop_cmd->dsa);
1.8 bouyer 1175: memset(siop_cmd->siop_table->msg_out, 0, 8);
1.7 bouyer 1176: siop_cmd->siop_table->msg_out[0] = MSG_IDENTIFY(lun, 1);
1.14 bouyer 1177: #if 0
1178: siop_cmd->siop_table->msg_out[1] = MSG_SIMPLE_Q_TAG;
1179: siop_cmd->siop_table->msg_out[2] = 0;
1180: #endif
1.7 bouyer 1181: if (sc->targets[target]->status == TARST_ASYNC) {
1182: if (sc->features & SF_BUS_WIDE) {
1183: sc->targets[target]->status = TARST_WIDE_NEG;
1184: siop_cmd->siop_table->msg_out[1] = MSG_EXTENDED;
1185: siop_cmd->siop_table->msg_out[2] = MSG_EXT_WDTR_LEN;
1186: siop_cmd->siop_table->msg_out[3] = MSG_EXT_WDTR;
1187: siop_cmd->siop_table->msg_out[4] =
1188: MSG_EXT_WDTR_BUS_16_BIT;
1.8 bouyer 1189: siop_cmd->siop_table->t_msgout.count=
1190: htole32(MSG_EXT_WDTR_LEN + 2 + 1);
1.7 bouyer 1191: } else {
1192: sc->targets[target]->status = TARST_SYNC_NEG;
1193: siop_cmd->siop_table->msg_out[1] = MSG_EXTENDED;
1194: siop_cmd->siop_table->msg_out[2] = MSG_EXT_SDTR_LEN;
1195: siop_cmd->siop_table->msg_out[3] = MSG_EXT_SDTR;
1196: siop_cmd->siop_table->msg_out[4] = sc->minsync;
1197: siop_cmd->siop_table->msg_out[5] = sc->maxoff;
1.8 bouyer 1198: siop_cmd->siop_table->t_msgout.count=
1199: htole32(MSG_EXT_SDTR_LEN + 2 +1);
1.7 bouyer 1200: }
1201: }
1.2 bouyer 1202: siop_cmd->siop_table->status = htole32(0xff); /* set invalid status */
1.1 bouyer 1203:
1204: /* load the DMA maps */
1205: error = bus_dmamap_load(sc->sc_dmat, siop_cmd->dmamap_cmd,
1206: xs->cmd, xs->cmdlen, NULL, BUS_DMA_NOWAIT);
1207: if (error) {
1208: printf("%s: unable to load cmd DMA map: %d",
1209: sc->sc_dev.dv_xname, error);
1210: xs->error = XS_DRIVER_STUFFUP;
1211: return(TRY_AGAIN_LATER);
1212: }
1213: siop_cmd->siop_table->cmd.count =
1214: htole32(siop_cmd->dmamap_cmd->dm_segs[0].ds_len);
1215: siop_cmd->siop_table->cmd.addr =
1216: htole32(siop_cmd->dmamap_cmd->dm_segs[0].ds_addr);
1217: if (xs->xs_control & (XS_CTL_DATA_IN | XS_CTL_DATA_OUT)) {
1218: error = bus_dmamap_load(sc->sc_dmat, siop_cmd->dmamap_data,
1219: xs->data, xs->datalen, NULL, BUS_DMA_NOWAIT);
1220: if (error) {
1221: printf("%s: unable to load cmd DMA map: %d",
1222: sc->sc_dev.dv_xname, error);
1223: xs->error = XS_DRIVER_STUFFUP;
1224: return(TRY_AGAIN_LATER);
1225: bus_dmamap_unload(sc->sc_dmat, siop_cmd->dmamap_cmd);
1226: }
1227: for (i = 0; i < siop_cmd->dmamap_data->dm_nsegs; i++) {
1228: siop_cmd->siop_table->data[i].count =
1229: htole32(siop_cmd->dmamap_data->dm_segs[i].ds_len);
1230: siop_cmd->siop_table->data[i].addr =
1231: htole32(siop_cmd->dmamap_data->dm_segs[i].ds_addr);
1232: }
1233: bus_dmamap_sync(sc->sc_dmat, siop_cmd->dmamap_data, 0,
1234: siop_cmd->dmamap_data->dm_mapsize,
1235: (xs->xs_control & XS_CTL_DATA_IN) ?
1236: BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE);
1237: }
1238: bus_dmamap_sync(sc->sc_dmat, siop_cmd->dmamap_cmd, 0,
1239: siop_cmd->dmamap_cmd->dm_mapsize, BUS_DMASYNC_PREWRITE);
1.2 bouyer 1240: siop_table_sync(siop_cmd, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1.1 bouyer 1241:
1242: siop_cmd->status = CMDST_READY;
1243: s = splbio();
1.7 bouyer 1244: TAILQ_INSERT_TAIL(&sc->targets[target]->active_list[lun],
1.1 bouyer 1245: siop_cmd, next);
1.2 bouyer 1246: siop_start(sc);
1.14 bouyer 1247: if (xs->xs_control & XS_CTL_POLL) {
1248: /* poll for command completion */
1249: while ((xs->xs_status & XS_STS_DONE) == 0)
1250: siop_intr(sc);
1251: splx(s);
1252: return (COMPLETE);
1253: }
1.1 bouyer 1254: splx(s);
1255: return (SUCCESSFULLY_QUEUED);
1256: }
1257:
1258: void
1259: siop_start(sc)
1260: struct siop_softc *sc;
1261: {
1262: struct siop_cmd *siop_cmd;
1.2 bouyer 1263: u_int32_t *scr;
1264: u_int32_t dsa;
1.1 bouyer 1265: int timeout;
1.10 bouyer 1266: int target, lun, slot;
1.2 bouyer 1267: int newcmd = 0;
1268:
1269: /*
1270: * first make sure to read valid data
1271: */
1.17 bouyer 1272: siop_shed_sync(sc, BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
1.1 bouyer 1273:
1.2 bouyer 1274: /*
1.10 bouyer 1275: * The queue management here is a bit tricky: the script always looks
1276: * at the slot from first to last, so if we always use the first
1277: * free slot commands can stay at the tail of the queue ~forever.
1278: * The algorithm used here is to restart from the head when we know
1279: * that the queue is empty, and only add commands after the last one.
1280: * When we're at the end of the queue wait for the script to clear it.
1281: * The best thing to do here would be to implement a circular queue,
1282: * but using only 53c720 features this can be "interesting".
1283: * A mid-way solution could be to implement 2 queues and swap orders.
1.2 bouyer 1284: */
1.10 bouyer 1285: slot = sc->sc_currshedslot;
1.17 bouyer 1286: scr = &sc->sc_shed[(Ent_nextslot / 4) * slot];
1.10 bouyer 1287: /*
1288: * if relative addr of first jump is not 0 the slot is free. As this is
1289: * the last used slot, all previous slots are free, we can restart
1290: * from 0.
1291: */
1292: if (scr[Ent_slot / 4 + 1] != 0) {
1293: slot = sc->sc_currshedslot = 0;
1294: } else {
1295: slot++;
1296: }
1297:
1.7 bouyer 1298: for (target = 0; target <= sc->sc_link.scsipi_scsi.max_target;
1299: target++) {
1300: if (sc->targets[target] == NULL)
1.2 bouyer 1301: continue;
1.7 bouyer 1302: for (lun = 0; lun < 8; lun++) {
1303: siop_cmd =
1304: sc->targets[target]->active_list[lun].tqh_first;
1305: if (siop_cmd == NULL)
1306: continue;
1307: if (siop_cmd->status != CMDST_READY &&
1308: siop_cmd->status != CMDST_SENSE)
1.2 bouyer 1309: continue;
1.21 ! bouyer 1310: /* find a free scheduler slot and load it */
1.10 bouyer 1311: for (; slot < sc->sc_nshedslots; slot++) {
1.17 bouyer 1312: scr = &sc->sc_shed[(Ent_nextslot / 4) * slot];
1.7 bouyer 1313: /*
1314: * if relative addr of first jump is 0 the
1315: * slot isn't free
1316: */
1317: if (scr[Ent_slot / 4 + 1] == 0)
1318: continue;
1.2 bouyer 1319: #ifdef DEBUG_SHED
1.8 bouyer 1320: printf("using slot %d for DSA 0x%lx\n", slot,
1321: (u_long)siop_cmd->dsa);
1.2 bouyer 1322: #endif
1.7 bouyer 1323: /* note that we started a new command */
1324: newcmd = 1;
1325: /* mark command as active */
1326: if (siop_cmd->status == CMDST_READY)
1327: siop_cmd->status = CMDST_ACTIVE;
1328: else if (siop_cmd->status == CMDST_SENSE)
1329: siop_cmd->status = CMDST_SENSE_ACTIVE;
1330: else
1331: panic("siop_start: bad status");
1332: /* patch script with DSA addr */
1333: dsa = siop_cmd->dsa;
1334: /*
1335: * 0x78000000 is a 'move data8 to reg'. data8
1336: * is the second octet, reg offset is the third.
1337: */
1338: scr[Ent_idsa0 / 4] =
1339: htole32(0x78100000 |
1340: ((dsa & 0x000000ff) << 8));
1341: scr[Ent_idsa1 / 4] =
1342: htole32(0x78110000 |
1343: ( dsa & 0x0000ff00 ));
1344: scr[Ent_idsa2 / 4] =
1345: htole32(0x78120000 |
1346: ((dsa & 0x00ff0000) >> 8));
1347: scr[Ent_idsa3 / 4] =
1348: htole32(0x78130000 |
1349: ((dsa & 0xff000000) >> 16));
1350: /* handle timeout */
1351: if (siop_cmd->status == CMDST_ACTIVE) {
1352: if ((siop_cmd->xs->xs_control &
1353: XS_CTL_POLL) == 0) {
1354: /* start exire timer */
1355: timeout =
1356: siop_cmd->xs->timeout *
1357: hz / 1000;
1358: if (timeout == 0)
1359: timeout = 1;
1360: callout_reset(
1361: &siop_cmd->xs->xs_callout,
1362: timeout, siop_timeout,
1363: siop_cmd);
1364: }
1.2 bouyer 1365: }
1.7 bouyer 1366: /*
1367: * Change jump offset so that this slot will be
1368: * handled
1369: */
1370: scr[Ent_slot / 4 + 1] = 0;
1371: break;
1372: }
1.10 bouyer 1373: /* no more free slot, no need to continue */
1.7 bouyer 1374: if (slot == sc->sc_nshedslots) {
1.10 bouyer 1375: goto end;
1.2 bouyer 1376: }
1.7 bouyer 1377: sc->sc_currshedslot = slot;
1.1 bouyer 1378: }
1379: }
1.7 bouyer 1380: end:
1.2 bouyer 1381: /* if nothing changed no need to flush cache and wakeup script */
1382: if (newcmd == 0)
1.1 bouyer 1383: return;
1.2 bouyer 1384: /* make sure SCRIPT processor will read valid data */
1.17 bouyer 1385: siop_shed_sync(sc, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1.2 bouyer 1386: /* Signal script it has some work to do */
1387: bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_ISTAT, ISTAT_SIGP);
1388: /* and wait for IRQ */
1389: return;
1.1 bouyer 1390: }
1391:
1392: void
1393: siop_timeout(v)
1394: void *v;
1395: {
1396: struct siop_cmd *siop_cmd = v;
1.7 bouyer 1397: struct siop_softc *sc = siop_cmd->siop_target->siop_sc;
1.1 bouyer 1398: int s;
1399: u_int8_t scntl1;
1400:
1401: scsi_print_addr(siop_cmd->xs->sc_link);
1402: printf("command timeout\n");
1403:
1404: s = splbio();
1405: /* reset the scsi bus */
1406: scntl1 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1);
1407: bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1,
1408: scntl1 | SCNTL1_RST);
1409: /* minimum 25 us, more time won't hurt */
1410: delay(100);
1411: bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1, scntl1);
1412:
1.12 soren 1413: /* deactivate callout */
1.1 bouyer 1414: callout_stop(&siop_cmd->xs->xs_callout);
1415: /* mark command has being timed out; siop_intr will handle it */
1416: /*
1417: * mark command has being timed out and just return;
1418: * the bus reset will generate an interrupt,
1419: * it will be handled in siop_intr()
1420: */
1421: siop_cmd->flags |= CMDFL_TIMEOUT;
1422: splx(s);
1423: return;
1424:
1425: }
1.2 bouyer 1426:
1427: void
1428: siop_dump_script(sc)
1429: struct siop_softc *sc;
1430: {
1431: int i;
1.17 bouyer 1432: siop_shed_sync(sc, BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
1.16 bouyer 1433: for (i = 0; i < NBPG / 4; i += 2) {
1.4 bouyer 1434: printf("0x%04x: 0x%08x 0x%08x", i * 4,
1435: le32toh(sc->sc_script[i]), le32toh(sc->sc_script[i+1]));
1436: if ((le32toh(sc->sc_script[i]) & 0xe0000000) == 0xc0000000) {
1.2 bouyer 1437: i++;
1.4 bouyer 1438: printf(" 0x%08x", le32toh(sc->sc_script[i+1]));
1.2 bouyer 1439: }
1440: printf("\n");
1441: }
1.16 bouyer 1442: }
1443:
1444: int
1445: siop_morecbd(sc)
1446: struct siop_softc *sc;
1447: {
1448: int error, i;
1449: bus_dma_segment_t seg;
1450: int rseg;
1451: struct siop_cbd *newcbd;
1452:
1453: /* allocate a new list head */
1454: newcbd = malloc(sizeof(struct siop_cbd), M_DEVBUF, M_NOWAIT);
1455: if (newcbd == NULL) {
1456: printf("%s: can't allocate memory for command descriptors "
1457: "head\n", sc->sc_dev.dv_xname);
1458: return ENOMEM;
1459: }
1460:
1461: /* allocate cmd list */
1462: newcbd->cmds =
1463: malloc(sizeof(struct siop_cmd) * SIOP_NCMDPB, M_DEVBUF, M_NOWAIT);
1464: if (newcbd->cmds == NULL) {
1465: printf("%s: can't allocate memory for command descriptors\n",
1466: sc->sc_dev.dv_xname);
1467: error = ENOMEM;
1468: goto bad3;
1469: }
1470: error = bus_dmamem_alloc(sc->sc_dmat, NBPG, NBPG, 0, &seg, 1, &rseg,
1471: BUS_DMA_NOWAIT);
1472: if (error) {
1473: printf("%s: unable to allocate cbd DMA memory, error = %d\n",
1474: sc->sc_dev.dv_xname, error);
1475: goto bad2;
1476: }
1477: error = bus_dmamem_map(sc->sc_dmat, &seg, rseg, NBPG,
1478: (caddr_t *)&newcbd->xfers, BUS_DMA_NOWAIT|BUS_DMA_COHERENT);
1479: if (error) {
1480: printf("%s: unable to map cbd DMA memory, error = %d\n",
1481: sc->sc_dev.dv_xname, error);
1482: goto bad2;
1483: }
1484: error = bus_dmamap_create(sc->sc_dmat, NBPG, 1, NBPG, 0,
1485: BUS_DMA_NOWAIT, &newcbd->xferdma);
1486: if (error) {
1487: printf("%s: unable to create cbd DMA map, error = %d\n",
1488: sc->sc_dev.dv_xname, error);
1489: goto bad1;
1490: }
1491: error = bus_dmamap_load(sc->sc_dmat, newcbd->xferdma, newcbd->xfers,
1492: NBPG, NULL, BUS_DMA_NOWAIT);
1493: if (error) {
1.17 bouyer 1494: printf("%s: unable to load cbd DMA map, error = %d\n",
1.16 bouyer 1495: sc->sc_dev.dv_xname, error);
1496: goto bad0;
1497: }
1498:
1499: for (i = 0; i < SIOP_NCMDPB; i++) {
1500: error = bus_dmamap_create(sc->sc_dmat, MAXPHYS, SIOP_NSG,
1501: MAXPHYS, 0, BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW,
1502: &newcbd->cmds[i].dmamap_data);
1503: if (error) {
1504: printf("%s: unable to create data DMA map for cbd: "
1505: "error %d\n",
1506: sc->sc_dev.dv_xname, error);
1507: goto bad0;
1508: }
1509: error = bus_dmamap_create(sc->sc_dmat,
1510: sizeof(struct scsipi_generic), 1,
1511: sizeof(struct scsipi_generic), 0,
1512: BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW,
1513: &newcbd->cmds[i].dmamap_cmd);
1514: if (error) {
1515: printf("%s: unable to create cmd DMA map for cbd %d\n",
1516: sc->sc_dev.dv_xname, error);
1517: goto bad0;
1518: }
1519: newcbd->cmds[i].siop_cbdp = newcbd;
1520: newcbd->cmds[i].siop_table = &newcbd->xfers[i];
1521: memset(newcbd->cmds[i].siop_table, 0, sizeof(struct siop_xfer));
1522: newcbd->cmds[i].dsa = newcbd->xferdma->dm_segs[0].ds_addr +
1523: i * sizeof(struct siop_xfer);
1524: newcbd->cmds[i].status = CMDST_FREE;
1525: newcbd->cmds[i].siop_table->t_msgout.count= htole32(1);
1526: newcbd->cmds[i].siop_table->t_msgout.addr =
1527: htole32(newcbd->cmds[i].dsa);
1528: newcbd->cmds[i].siop_table->t_msgin.count= htole32(1);
1529: newcbd->cmds[i].siop_table->t_msgin.addr =
1530: htole32(newcbd->cmds[i].dsa + 8);
1531: newcbd->cmds[i].siop_table->t_extmsgin.count= htole32(2);
1532: newcbd->cmds[i].siop_table->t_extmsgin.addr = htole32(
1533: le32toh(newcbd->cmds[i].siop_table->t_msgin.addr) + 1);
1534: newcbd->cmds[i].siop_table->t_msgtag.count= htole32(2);
1535: newcbd->cmds[i].siop_table->t_msgtag.addr = htole32(
1536: le32toh(newcbd->cmds[i].siop_table->t_msgin.addr) + 1);
1537: newcbd->cmds[i].siop_table->t_status.count= htole32(1);
1538: newcbd->cmds[i].siop_table->t_status.addr = htole32(
1539: le32toh(newcbd->cmds[i].siop_table->t_msgin.addr) + 8);
1540: TAILQ_INSERT_TAIL(&sc->free_list, &newcbd->cmds[i], next);
1541: #ifdef DEBUG
1542: printf("tables[%d]: out=0x%x in=0x%x status=0x%x\n", i,
1543: le32toh(newcbd->cmds[i].siop_table->t_msgin.addr),
1544: le32toh(newcbd->cmds[i].siop_table->t_msgout.addr),
1545: le32toh(newcbd->cmds[i].siop_table->t_status.addr));
1546: #endif
1547: }
1548: TAILQ_INSERT_TAIL(&sc->cmds, newcbd, next);
1549: return 0;
1550: bad0:
1551: bus_dmamap_destroy(sc->sc_dmat, newcbd->xferdma);
1552: bad1:
1553: bus_dmamem_free(sc->sc_dmat, &seg, rseg);
1554: bad2:
1555: free(newcbd->cmds, M_DEVBUF);
1556: bad3:
1557: free(newcbd, M_DEVBUF);
1558: return error;
1.2 bouyer 1559: }
1560:
1561: #ifdef SIOP_STATS
1562: void
1563: siop_printstats()
1564: {
1565: printf("siop_stat_intr %d\n", siop_stat_intr);
1566: printf("siop_stat_intr_shortxfer %d\n", siop_stat_intr_shortxfer);
1567: printf("siop_stat_intr_xferdisc %d\n", siop_stat_intr_xferdisc);
1568: printf("siop_stat_intr_sdp %d\n", siop_stat_intr_sdp);
1569: printf("siop_stat_intr_reselect %d\n", siop_stat_intr_reselect);
1570: printf("siop_stat_intr_done %d\n", siop_stat_intr_done);
1571: }
1572: #endif
CVSweb <webmaster@jp.NetBSD.org>