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