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