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