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