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