siop.c revision 1.13 1 /* $NetBSD: siop.c,v 1.13 2000/05/11 09:30:12 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 ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
21 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
22 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23 * AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
24 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * 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 #include <sys/scsiio.h>
42
43 #include <machine/endian.h>
44 #include <machine/bus.h>
45
46 #include <vm/vm.h>
47 #include <vm/vm_param.h>
48 #include <vm/vm_kern.h>
49
50 #include <dev/microcode/siop/siop.out>
51
52 #include <dev/scsipi/scsi_all.h>
53 #include <dev/scsipi/scsi_message.h>
54 #include <dev/scsipi/scsipi_all.h>
55
56 #include <dev/scsipi/scsiconf.h>
57
58 #include <dev/ic/siopreg.h>
59 #include <dev/ic/siopvar.h>
60
61 #define 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 #define MEM_SIZE 8192
74 #define CMD_OFF 4096
75
76 /* tables used by SCRIPT */
77 typedef struct scr_table {
78 u_int32_t count;
79 u_int32_t addr;
80 } scr_table_t ;
81
82 /* Number of scatter/gather entries */
83 #define SIOP_NSG (MAXPHYS/NBPG + 1)
84
85 /*
86 * This structure interfaces the SCRIPT with the driver; it describes a full
87 * transfer. It lives in the same chunk of DMA-safe memory as the script.
88 */
89 struct siop_xfer {
90 u_int8_t msg_out[8]; /* 0 */
91 u_int8_t msg_in[8]; /* 8 */
92 int status; /* 16 */
93 u_int32_t pad1; /* 20 */
94 u_int32_t id; /* 24 */
95 u_int32_t pad2; /* 28 */
96 scr_table_t t_msgin; /* 32 */
97 scr_table_t t_extmsgin; /* 40 */
98 scr_table_t t_extmsgdata; /* 48 */
99 scr_table_t t_extmsgtag; /* 56 */
100 scr_table_t t_msgout; /* 64 */
101 scr_table_t cmd; /* 72 */
102 scr_table_t t_status; /* 80 */
103 scr_table_t data[SIOP_NSG]; /* 88 */
104 } __attribute__((__packed__));
105
106 /*
107 * This decribes a command handled by the SCSI controller
108 * These are chained in either a free list or a active list
109 * We have one queue per target + (one at the adapter's target for probe)
110 */
111 struct siop_cmd {
112 TAILQ_ENTRY (siop_cmd) next;
113 struct siop_target *siop_target; /* pointer to our target def */
114 struct scsipi_xfer *xs; /* xfer from the upper level */
115 struct siop_xfer *siop_table; /* tables dealing with this xfer */
116 bus_addr_t dsa; /* DSA value to load */
117 bus_dmamap_t dmamap_cmd;
118 bus_dmamap_t dmamap_data;
119 struct scsipi_sense rs_cmd; /* request sense command buffer */
120 int status;
121 int flags;
122 };
123
124 /* status defs */
125 #define CMDST_FREE 0 /* cmd slot is free */
126 #define CMDST_READY 1 /* cmd slot is waiting for processing */
127 #define CMDST_ACTIVE 2 /* cmd slot is being processed */
128 #define CMDST_SENSE 3 /* cmd slot is being requesting sense */
129 #define CMDST_SENSE_ACTIVE 4 /* request sense active */
130 #define CMDST_SENSE_DONE 5 /* request sense done */
131 #define CMDST_DONE 6 /* cmd slot has been processed */
132 /* flags defs */
133 #define CMDFL_TIMEOUT 0x0001 /* cmd timed out */
134
135 /* initial number of cmd descriptors */
136 #define SIOP_NCMD 10
137
138 /* per-target struct */
139 struct siop_target {
140 int status; /* target status see below */
141 int flags; /* target flags, see below */
142 u_int32_t id; /* for SELECT FROM */
143 struct cmd_list active_list[8]; /* per-lun active cmds */
144 struct siop_softc *siop_sc; /* points back to our adapter */
145 };
146
147 /* target status */
148 #define TARST_PROBING 0 /* target is being probed */
149 #define TARST_ASYNC 1 /* target needs sync/wide negotiation */
150 #define TARST_WIDE_NEG 2 /* target is doing wide negotiation */
151 #define TARST_SYNC_NEG 3 /* target is doing sync negotiation */
152 #define TARST_OK 4 /* sync/wide agreement is valid */
153
154 /* target flags */
155 #define TARF_SYNC 0x00 /* target is sync */
156 #define TARF_WIDE 0x01 /* target is wide */
157
158 void siop_reset __P((struct siop_softc *));
159 void siop_handle_reset __P((struct siop_softc *));
160 void siop_scsicmd_end __P((struct siop_cmd *));
161 void siop_wdtr_neg __P((struct siop_cmd *siop_cmd));
162 void siop_sdtr_neg __P((struct siop_cmd *siop_cmd));
163 void siop_start __P((struct siop_softc *));
164 void siop_timeout __P((void *));
165 void siop_minphys __P((struct buf *));
166 int siop_ioctl __P((struct scsipi_link *, u_long,
167 caddr_t, int, struct proc *));
168 int siop_scsicmd __P((struct scsipi_xfer *));
169 void siop_sdp __P((struct siop_cmd *));
170 void siop_clearfifo __P((struct siop_softc *));
171 void siop_ssg __P((struct siop_cmd *));
172 void siop_dump_script __P((struct siop_softc *));
173
174 struct scsipi_adapter siop_adapter = {
175 0,
176 siop_scsicmd,
177 siop_minphys,
178 siop_ioctl,
179 NULL,
180 };
181
182 struct scsipi_device siop_dev = {
183 NULL,
184 NULL,
185 NULL,
186 NULL,
187 };
188
189 #ifdef SIOP_STATS
190 static int siop_stat_intr = 0;
191 static int siop_stat_intr_shortxfer = 0;
192 static int siop_stat_intr_sdp = 0;
193 static int siop_stat_intr_done = 0;
194 static int siop_stat_intr_reselect = 0;
195 static int siop_stat_intr_xferdisc = 0;
196 void siop_printstats __P((void));
197 #define INCSTAT(x) x++
198 #else
199 #define INCSTAT(x)
200 #endif
201
202 static __inline__ void siop_table_sync __P((struct siop_cmd *, int));
203 static __inline__ void
204 siop_table_sync(siop_cmd, ops)
205 struct siop_cmd *siop_cmd;
206 int ops;
207 {
208 struct siop_softc *sc = siop_cmd->siop_target->siop_sc;
209 bus_addr_t offset;
210
211 offset = siop_cmd->dsa - sc->sc_scriptdma->dm_segs[0].ds_addr;
212 bus_dmamap_sync(sc->sc_dmat, sc->sc_scriptdma, offset,
213 sizeof(struct siop_xfer), ops);
214 }
215
216 static __inline__ void siop_script_sync __P((struct siop_softc *, int));
217 static __inline__ void
218 siop_script_sync(sc, ops)
219 struct siop_softc *sc;
220 int ops;
221 {
222 bus_dmamap_sync(sc->sc_dmat, sc->sc_scriptdma, 0, CMD_OFF, ops);
223 }
224
225 void
226 siop_attach(sc)
227 struct siop_softc *sc;
228 {
229 int error, i;
230 bus_dma_segment_t seg;
231 int rseg;
232
233 /*
234 * Allocate DMA-safe memory for the script itself and internal
235 * variables and map it.
236 */
237 error = bus_dmamem_alloc(sc->sc_dmat, MEM_SIZE,
238 NBPG, 0, &seg, 1, &rseg, BUS_DMA_NOWAIT);
239 if (error) {
240 printf("%s: unable to allocate script DMA memory, error = %d\n",
241 sc->sc_dev.dv_xname, error);
242 return;
243 }
244 error = bus_dmamem_map(sc->sc_dmat, &seg, rseg, MEM_SIZE,
245 (caddr_t *)&sc->sc_script, BUS_DMA_NOWAIT|BUS_DMA_COHERENT);
246 if (error) {
247 printf("%s: unable to map script DMA memory, error = %d\n",
248 sc->sc_dev.dv_xname, error);
249 return;
250 }
251 error = bus_dmamap_create(sc->sc_dmat, MEM_SIZE, 1,
252 MEM_SIZE, 0, BUS_DMA_NOWAIT, &sc->sc_scriptdma);
253 if (error) {
254 printf("%s: unable to create script DMA map, error = %d\n",
255 sc->sc_dev.dv_xname, error);
256 return;
257 }
258 error = bus_dmamap_load(sc->sc_dmat, sc->sc_scriptdma, sc->sc_script,
259 MEM_SIZE, NULL, BUS_DMA_NOWAIT);
260 if (error) {
261 printf("%s: unable to load script DMA map, error = %d\n",
262 sc->sc_dev.dv_xname, error);
263 return;
264 }
265 TAILQ_INIT(&sc->free_list);
266 /* allocate cmd list */
267 sc->cmds =
268 malloc(sizeof(struct siop_cmd) * SIOP_NCMD, M_DEVBUF, M_NOWAIT);
269 if (sc->cmds == NULL) {
270 printf("%s: can't allocate memory for command descriptors\n",
271 sc->sc_dev.dv_xname);
272 return;
273 }
274 for (i = 0; i < SIOP_NCMD; i++) {
275 error = bus_dmamap_create(sc->sc_dmat, MAXPHYS, SIOP_NSG,
276 MAXPHYS, 0, BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW,
277 &sc->cmds[i].dmamap_data);
278 if (error) {
279 printf("%s: unable to create data DMA map for cbd %d\n",
280 sc->sc_dev.dv_xname, error);
281 return;
282 }
283 error = bus_dmamap_create(sc->sc_dmat,
284 sizeof(struct scsipi_generic), 1,
285 sizeof(struct scsipi_generic), 0,
286 BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW,
287 &sc->cmds[i].dmamap_cmd);
288 if (error) {
289 printf("%s: unable to create cmd DMA map for cbd %d\n",
290 sc->sc_dev.dv_xname, error);
291 return;
292 }
293 sc->cmds[i].siop_table =
294 &((struct siop_xfer *)(&sc->sc_script[CMD_OFF/4]))[i];
295 memset(sc->cmds[i].siop_table, 0, sizeof(struct siop_xfer));
296 sc->cmds[i].dsa = sc->sc_scriptdma->dm_segs[0].ds_addr +
297 CMD_OFF + i * sizeof(struct siop_xfer);
298 sc->cmds[i].status = CMDST_FREE;
299 sc->cmds[i].siop_table->t_msgout.count= htole32(1);
300 sc->cmds[i].siop_table->t_msgout.addr =
301 htole32(sc->cmds[i].dsa);
302 sc->cmds[i].siop_table->t_msgin.count= htole32(1);
303 sc->cmds[i].siop_table->t_msgin.addr =
304 htole32(sc->cmds[i].dsa + 8);
305 sc->cmds[i].siop_table->t_extmsgin.count= htole32(2);
306 sc->cmds[i].siop_table->t_extmsgin.addr =
307 htole32(le32toh(sc->cmds[i].siop_table->t_msgin.addr) + 1);
308 sc->cmds[i].siop_table->t_status.count= htole32(1);
309 sc->cmds[i].siop_table->t_status.addr =
310 htole32(le32toh(sc->cmds[i].siop_table->t_msgin.addr) + 8);
311 TAILQ_INSERT_TAIL(&sc->free_list, &sc->cmds[i], next);
312 #ifdef DEBUG
313 printf("tables[%d]: out=0x%x in=0x%x status=0x%x\n", i,
314 le32toh(sc->cmds[i].siop_table->t_msgin.addr),
315 le32toh(sc->cmds[i].siop_table->t_msgout.addr),
316 le32toh(sc->cmds[i].siop_table->t_status.addr));
317 #endif
318 }
319 /* compute number of sheduler slots */
320 sc->sc_nshedslots = (
321 CMD_OFF /* memory size allocated for scripts */
322 - sizeof(siop_script) /* memory for main script */
323 + 8 /* extra NOP at end of main script */
324 - sizeof(endslot_script) /* memory needed at end of sheduler */
325 ) / (sizeof(slot_script) - 8);
326 sc->sc_currshedslot = 0;
327 #ifdef DEBUG
328 printf("%s: script size = %d, PHY addr=0x%x, VIRT=%p nslots %d\n",
329 sc->sc_dev.dv_xname, (int)sizeof(siop_script),
330 (u_int)sc->sc_scriptdma->dm_segs[0].ds_addr, sc->sc_script,
331 sc->sc_nshedslots);
332 #endif
333
334 sc->sc_link.adapter_softc = sc;
335 sc->sc_link.openings = 1;
336 sc->sc_link.scsipi_scsi.channel = SCSI_CHANNEL_ONLY_ONE;
337 sc->sc_link.scsipi_scsi.max_target =
338 (sc->features & SF_BUS_WIDE) ? 15 : 7;
339 sc->sc_link.scsipi_scsi.max_lun = 7;
340 sc->sc_link.scsipi_scsi.adapter_target = bus_space_read_1(sc->sc_rt,
341 sc->sc_rh, SIOP_SCID);
342 if (sc->sc_link.scsipi_scsi.adapter_target == 0 ||
343 sc->sc_link.scsipi_scsi.adapter_target >
344 sc->sc_link.scsipi_scsi.max_target)
345 sc->sc_link.scsipi_scsi.adapter_target = SIOP_DEFAULT_TARGET;
346 sc->sc_link.type = BUS_SCSI;
347 sc->sc_link.adapter = &siop_adapter;
348 sc->sc_link.device = &siop_dev;
349 sc->sc_link.flags = 0;
350
351 for (i = 0; i < 16; i++)
352 sc->targets[i] = NULL;
353
354 /* find min/max sync period for this chip */
355 sc->maxsync = 0;
356 sc->minsync = 255;
357 for (i = 0; i < sizeof(scf_period) / sizeof(scf_period[0]); i++) {
358 if (sc->clock_period != scf_period[i].clock)
359 continue;
360 if (sc->maxsync < scf_period[i].period)
361 sc->maxsync = scf_period[i].period;
362 if (sc->minsync > scf_period[i].period)
363 sc->minsync = scf_period[i].period;
364 }
365 if (sc->maxsync == 255 || sc->minsync == 0)
366 panic("siop: can't find my sync parameters\n");
367 siop_reset(sc);
368 #ifdef DUMP_SCRIPT
369 siop_dump_script(sc);
370 #endif
371
372 config_found((struct device*)sc, &sc->sc_link, scsiprint);
373 }
374
375 void
376 siop_reset(sc)
377 struct siop_softc *sc;
378 {
379 int i, j;
380 u_int32_t *scr;
381 u_int32_t stest3;
382 bus_addr_t physaddr;
383
384 /* reset the chip */
385 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_ISTAT, ISTAT_SRST);
386 delay(1000);
387 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_ISTAT, 0);
388
389 /* copy and patch the script */
390 for (j = 0; j < (sizeof(siop_script) / sizeof(siop_script[0])); j++) {
391 sc->sc_script[j] = htole32(siop_script[j]);
392 }
393 /* copy the sheduler slots script */
394 for (i = 0; i < sc->sc_nshedslots; i++) {
395 scr = &sc->sc_script[Ent_sheduler / 4 + (Ent_nextslot / 4) * i];
396 physaddr = sc->sc_scriptdma->dm_segs[0].ds_addr + Ent_sheduler
397 + Ent_nextslot * i;
398 for (j = 0; j < (sizeof(slot_script) / sizeof(slot_script[0]));
399 j++) {
400 scr[j] = htole32(slot_script[j]);
401 }
402 /*
403 * save current jump offset and patch MOVE MEMORY operands
404 * to restore it.
405 */
406 scr[Ent_slotdata/4 + 1] = scr[Ent_slot/4 + 1];
407 scr[E_slot_nextp_Used[0]] = htole32(physaddr + Ent_slot + 4);
408 scr[E_slot_shed_addrsrc_Used[0]] = htole32(physaddr +
409 Ent_slotdata + 4);
410 /* JUMP selected, in main script */
411 scr[E_slot_abs_selected_Used[0]] =
412 htole32(sc->sc_scriptdma->dm_segs[0].ds_addr + Ent_selected);
413 /* JUMP addr if SELECT fail */
414 scr[E_slot_abs_reselect_Used[0]] =
415 htole32(sc->sc_scriptdma->dm_segs[0].ds_addr + Ent_reselect);
416 }
417 /* Now the final JUMP */
418 scr = &sc->sc_script[Ent_sheduler / 4 +
419 (Ent_nextslot / 4) * sc->sc_nshedslots];
420 for (j = 0; j < (sizeof(endslot_script) / sizeof(endslot_script[0]));
421 j++) {
422 scr[j] = htole32(endslot_script[j]);
423 }
424 scr[E_endslot_abs_reselect_Used[0]] =
425 htole32(sc->sc_scriptdma->dm_segs[0].ds_addr + Ent_reselect);
426
427 /* init registers */
428 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL0,
429 SCNTL0_ARB_MASK | SCNTL0_EPC | SCNTL0_AAP);
430 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1, 0);
431 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL3, sc->clock_div);
432 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_DIEN, 0xff);
433 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SIEN0,
434 0xff & ~(SIEN0_CMP | SIEN0_SEL | SIEN0_RSL));
435 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SIEN1,
436 0xff & ~(SIEN1_HTH | SIEN1_GEN));
437 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST2, STEST2_EXT);
438 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST3, STEST3_TE);
439 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STIME0,
440 (0xb << STIME0_SEL_SHIFT));
441 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCID,
442 sc->sc_link.scsipi_scsi.adapter_target | SCID_RRE);
443 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_RESPID0,
444 1 << sc->sc_link.scsipi_scsi.adapter_target);
445 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_DCNTL, DCNTL_COM);
446
447 /* enable clock doubler or quadruler if appropriate */
448 if (sc->features & (SF_CHIP_DBLR | SF_CHIP_QUAD)) {
449 stest3 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_STEST3);
450 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST1,
451 STEST1_DBLEN);
452 if (sc->features & SF_CHIP_QUAD) {
453 /* wait for PPL to lock */
454 while ((bus_space_read_1(sc->sc_rt, sc->sc_rh,
455 SIOP_STEST4) & STEST4_LOCK) == 0)
456 delay(10);
457 } else {
458 /* data sheet says 20us - more won't hurt */
459 delay(100);
460 }
461 /* halt scsi clock, select doubler/quad, restart clock */
462 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST3,
463 stest3 | STEST3_HSC);
464 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST1,
465 STEST1_DBLEN | STEST1_DBLSEL);
466 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST3, stest3);
467 } else {
468 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST1, 0);
469 }
470
471 /* start script */
472 siop_script_sync(sc, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
473 bus_space_write_4(sc->sc_rt, sc->sc_rh, SIOP_DSP,
474 sc->sc_scriptdma->dm_segs[0].ds_addr + Ent_reselect);
475 }
476
477 #if 0
478 #define CALL_SCRIPT(ent) do {\
479 printf ("start script DSA 0x%lx DSP 0x%lx\n", \
480 siop_cmd->dsa, \
481 sc->sc_scriptdma->dm_segs[0].ds_addr + ent); \
482 bus_space_write_4(sc->sc_rt, sc->sc_rh, SIOP_DSP, sc->sc_scriptdma->dm_segs[0].ds_addr + ent); \
483 } while (0)
484 #else
485 #define CALL_SCRIPT(ent) do {\
486 bus_space_write_4(sc->sc_rt, sc->sc_rh, SIOP_DSP, sc->sc_scriptdma->dm_segs[0].ds_addr + ent); \
487 } while (0)
488 #endif
489
490 int
491 siop_intr(v)
492 void *v;
493 {
494 struct siop_softc *sc = v;
495 struct siop_target *siop_target;
496 struct siop_cmd *siop_cmd;
497 struct scsipi_xfer *xs;
498 int istat, sist0, sist1, sstat1, dstat, scntl1;
499 u_int32_t irqcode;
500 int need_reset = 0;
501 int offset, target, lun;
502 bus_addr_t dsa;
503
504 istat = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_ISTAT);
505 if ((istat & (ISTAT_INTF | ISTAT_DIP | ISTAT_SIP)) == 0)
506 return 0;
507 INCSTAT(siop_stat_intr);
508 if (istat & ISTAT_INTF) {
509 printf("INTRF\n");
510 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_ISTAT, ISTAT_INTF);
511 }
512 /* use DSA to find the current siop_cmd */
513 dsa = bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSA);
514 if (dsa >= sc->sc_scriptdma->dm_segs[0].ds_addr + CMD_OFF &&
515 dsa < sc->sc_scriptdma->dm_segs[0].ds_addr + CMD_OFF +
516 SIOP_NCMD * sizeof(struct siop_xfer)) {
517 dsa -= sc->sc_scriptdma->dm_segs[0].ds_addr + CMD_OFF;
518 siop_cmd = &sc->cmds[dsa / sizeof(struct siop_xfer)];
519 siop_table_sync(siop_cmd,
520 BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
521 } else {
522 printf("%s: current DSA invalid\n",
523 sc->sc_dev.dv_xname);
524 siop_cmd = NULL;
525 }
526 if (istat & ISTAT_DIP) {
527 u_int32_t *p;
528 dstat = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_DSTAT);
529 if (dstat & DSTAT_SSI) {
530 printf("single step dsp 0x%08x dsa 0x08%x\n",
531 (int)(bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSP) -
532 sc->sc_scriptdma->dm_segs[0].ds_addr),
533 bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSA));
534 if ((dstat & ~(DSTAT_DFE | DSTAT_SSI)) == 0 &&
535 (istat & ISTAT_SIP) == 0) {
536 bus_space_write_1(sc->sc_rt, sc->sc_rh,
537 SIOP_DCNTL, bus_space_read_1(sc->sc_rt,
538 sc->sc_rh, SIOP_DCNTL) | DCNTL_STD);
539 }
540 return 1;
541 }
542 if (dstat & ~(DSTAT_SIR | DSTAT_DFE | DSTAT_SSI)) {
543 printf("DMA IRQ:");
544 if (dstat & DSTAT_IID)
545 printf(" Illegal instruction");
546 if (dstat & DSTAT_ABRT)
547 printf(" abort");
548 if (dstat & DSTAT_BF)
549 printf(" bus fault");
550 if (dstat & DSTAT_MDPE)
551 printf(" parity");
552 if (dstat & DSTAT_DFE)
553 printf(" dma fifo empty");
554 printf(", DSP=0x%x DSA=0x%x: ",
555 (int)(bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSP) -
556 sc->sc_scriptdma->dm_segs[0].ds_addr),
557 bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSA));
558 p = sc->sc_script +
559 (bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSP) -
560 sc->sc_scriptdma->dm_segs[0].ds_addr - 8) / 4;
561 printf("0x%x 0x%x 0x%x 0x%x\n", le32toh(p[0]), le32toh(p[1]),
562 le32toh(p[2]), le32toh(p[3]));
563 if (siop_cmd)
564 printf("last msg_in=0x%x status=0x%x\n",
565 siop_cmd->siop_table->msg_in[0],
566 le32toh(siop_cmd->siop_table->status));
567 need_reset = 1;
568 }
569 }
570 if (istat & ISTAT_SIP) {
571 /*
572 * SCSI interrupt. If current command is not active,
573 * we don't need siop_cmd
574 */
575 if (siop_cmd->status != CMDST_ACTIVE &&
576 siop_cmd->status != CMDST_SENSE_ACTIVE) {
577 siop_cmd = NULL;
578 }
579 if (istat & ISTAT_DIP)
580 delay(10);
581 sist0 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SIST0);
582 delay(10);
583 sist1 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SIST1);
584 sstat1 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SSTAT1);
585 #ifdef DEBUG_INTR
586 printf("scsi interrupt, sist0=0x%x sist1=0x%x sstat1=0x%x "
587 "DSA=0x%x DSP=0x%lx\n", sist0, sist1,
588 bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SSTAT1),
589 bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSA),
590 (u_long)(bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSP) -
591 sc->sc_scriptdma->dm_segs[0].ds_addr));
592 #endif
593 if (siop_cmd) {
594 xs = siop_cmd->xs;
595 siop_target = siop_cmd->siop_target;
596 }
597 if (sist0 & SIST0_RST) {
598 siop_handle_reset(sc);
599 siop_start(sc);
600 /* no table to flush here */
601 return 1;
602 }
603 if (sist0 & SIST0_SGE) {
604 if (siop_cmd)
605 scsi_print_addr(xs->sc_link);
606 else
607 printf("%s:", sc->sc_dev.dv_xname);
608 printf("scsi gross error\n");
609 goto reset;
610 }
611 if ((sist0 & SIST0_MA) && need_reset == 0) {
612 if (siop_cmd) {
613 int scratcha0;
614 dstat = bus_space_read_1(sc->sc_rt, sc->sc_rh,
615 SIOP_DSTAT);
616 /*
617 * first restore DSA, in case we were in a S/G
618 * operation.
619 */
620 bus_space_write_4(sc->sc_rt, sc->sc_rh,
621 SIOP_DSA, siop_cmd->dsa);
622 scratcha0 = bus_space_read_1(sc->sc_rt,
623 sc->sc_rh, SIOP_SCRATCHA);
624 switch (sstat1 & SSTAT1_PHASE_MASK) {
625 case SSTAT1_PHASE_STATUS:
626 /*
627 * previous phase may be aborted for any reason
628 * ( for example, the target has less data to
629 * transfer than requested). Just go to status
630 * and the command should terminate.
631 */
632 INCSTAT(siop_stat_intr_shortxfer);
633 CALL_SCRIPT(Ent_status);
634 if ((dstat & DSTAT_DFE) == 0)
635 siop_clearfifo(sc);
636 /* no table to flush here */
637 return 1;
638 case SSTAT1_PHASE_MSGIN:
639 /*
640 * target may be ready to disconnect
641 * Save data pointers just in case.
642 */
643 INCSTAT(siop_stat_intr_xferdisc);
644 if (scratcha0 & A_flag_data)
645 siop_sdp(siop_cmd);
646 else if ((dstat & DSTAT_DFE) == 0)
647 siop_clearfifo(sc);
648 bus_space_write_1(sc->sc_rt, sc->sc_rh,
649 SIOP_SCRATCHA,
650 scratcha0 & ~A_flag_data);
651 siop_table_sync(siop_cmd,
652 BUS_DMASYNC_PREREAD |
653 BUS_DMASYNC_PREWRITE);
654 CALL_SCRIPT(Ent_msgin);
655 return 1;
656 }
657 printf("%s: unexpected phase mismatch %d\n",
658 sc->sc_dev.dv_xname,
659 sstat1 & SSTAT1_PHASE_MASK);
660 } else {
661 printf("%s: phase mismatch without command\n",
662 sc->sc_dev.dv_xname);
663 }
664 need_reset = 1;
665 }
666 if (sist0 & SIST0_PAR) {
667 /* parity error, reset */
668 if (siop_cmd)
669 scsi_print_addr(xs->sc_link);
670 else
671 printf("%s:", sc->sc_dev.dv_xname);
672 printf("parity error\n");
673 goto reset;
674 }
675 if ((sist1 & SIST1_STO) && need_reset == 0) {
676 /* selection time out, assume there's no device here */
677 if (siop_cmd) {
678 siop_cmd->status = CMDST_DONE;
679 xs->error = XS_SELTIMEOUT;
680 goto end;
681 } else {
682 printf("%s: selection timeout without "
683 "command\n", sc->sc_dev.dv_xname);
684 need_reset = 1;
685 }
686 }
687 if (sist0 & SIST0_UDC) {
688 /*
689 * unexpected disconnect. Usually the target signals
690 * a fatal condition this way. Attempt to get sense.
691 */
692 if (siop_cmd)
693 goto check_sense;
694 printf("%s: unexpected disconnect without "
695 "command\n", sc->sc_dev.dv_xname);
696 goto reset;
697 }
698 /* Else it's an unhandled exeption (for now). */
699 printf("%s: unhandled scsi interrupt, sist0=0x%x sist1=0x%x "
700 "sstat1=0x%x DSA=0x%x DSP=0x%x\n", sc->sc_dev.dv_xname,
701 sist0, sist1,
702 bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SSTAT1),
703 bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSA),
704 (int)(bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSP) -
705 sc->sc_scriptdma->dm_segs[0].ds_addr));
706 if (siop_cmd) {
707 siop_cmd->status = CMDST_DONE;
708 xs->error = XS_SELTIMEOUT;
709 goto end;
710 }
711 need_reset = 1;
712 }
713 if (need_reset) {
714 reset:
715 /* fatal error, reset the bus */
716 scntl1 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1);
717 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1,
718 scntl1 | SCNTL1_RST);
719 /* minimum 25 us, more time won't hurt */
720 delay(100);
721 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1, scntl1);
722 /* no table to flush here */
723 return 1;
724 }
725
726
727 if ((istat & ISTAT_DIP) && (dstat & DSTAT_SIR)) { /* script interrupt */
728 irqcode = bus_space_read_4(sc->sc_rt, sc->sc_rh,
729 SIOP_DSPS);
730 #ifdef DEBUG_INTR
731 printf("script interrupt 0x%x\n", irqcode);
732 #endif
733 /*
734 * an inactive command is only valid if it's a reselect
735 * interrupt: we'll change siop_cmd to point to the rigth one
736 * just here
737 */
738 if (irqcode != A_int_resel &&
739 siop_cmd->status != CMDST_ACTIVE &&
740 siop_cmd->status != CMDST_SENSE_ACTIVE) {
741 printf("%s: Aie, no command (IRQ code 0x%x current "
742 "status %d) !\n", sc->sc_dev.dv_xname,
743 irqcode, siop_cmd->status);
744 xs = NULL;
745 } else {
746 xs = siop_cmd->xs;
747 siop_target = siop_cmd->siop_target;
748 }
749 switch(irqcode) {
750 case A_int_err:
751 printf("error, DSP=0x%x\n",
752 (int)(bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSP) -
753 sc->sc_scriptdma->dm_segs[0].ds_addr));
754 if (xs) {
755 xs->error = XS_SELTIMEOUT;
756 goto end;
757 } else {
758 goto reset;
759 }
760 case A_int_msgin:
761 if (siop_cmd->siop_table->msg_in[0] ==
762 MSG_MESSAGE_REJECT) {
763 int msg, extmsg;
764 if (siop_cmd->siop_table->msg_out[0] & 0x80) {
765 /*
766 * message was part of a identify +
767 * something else. Identify shoudl't
768 * have been rejected.
769 */
770 msg = siop_cmd->siop_table->msg_out[1];
771 extmsg =
772 siop_cmd->siop_table->msg_out[3];
773 } else {
774 msg = siop_cmd->siop_table->msg_out[0];
775 extmsg =
776 siop_cmd->siop_table->msg_out[2];
777 }
778 if (msg == MSG_MESSAGE_REJECT) {
779 /* MSG_REJECT for a MSG_REJECT !*/
780 if (xs)
781 scsi_print_addr(xs->sc_link);
782 else
783 printf("%s: ",
784 sc->sc_dev.dv_xname);
785 printf("our reject message was "
786 "rejected\n");
787 goto reset;
788 }
789 if (msg == MSG_EXTENDED &&
790 extmsg == MSG_EXT_WDTR) {
791 /* WDTR rejected, initiate sync */
792 printf("%s: target %d using 8bit "
793 "transfers\n", sc->sc_dev.dv_xname,
794 xs->sc_link->scsipi_scsi.target);
795 siop_target->status = TARST_SYNC_NEG;
796 siop_cmd->siop_table->msg_out[0] =
797 MSG_EXTENDED;
798 siop_cmd->siop_table->msg_out[1] =
799 MSG_EXT_SDTR_LEN;
800 siop_cmd->siop_table->msg_out[2] =
801 MSG_EXT_SDTR;
802 siop_cmd->siop_table->msg_out[3] =
803 sc->minsync;
804 siop_cmd->siop_table->msg_out[4] =
805 sc->maxoff;
806 siop_cmd->siop_table->t_msgout.count =
807 htole32(MSG_EXT_SDTR_LEN + 2);
808 siop_cmd->siop_table->t_msgout.addr =
809 htole32(siop_cmd->dsa);
810 siop_table_sync(siop_cmd,
811 BUS_DMASYNC_PREREAD |
812 BUS_DMASYNC_PREWRITE);
813 CALL_SCRIPT(Ent_send_msgout);
814 return 1;
815 } else if (msg == MSG_EXTENDED &&
816 extmsg == MSG_EXT_SDTR) {
817 /* sync rejected */
818 printf("%s: target %d asynchronous\n",
819 sc->sc_dev.dv_xname,
820 xs->sc_link->scsipi_scsi.target);
821 siop_cmd->siop_target->status =
822 TARST_OK;
823 /* no table to flush here */
824 CALL_SCRIPT(Ent_msgin_ack);
825 return 1;
826 }
827 if (xs)
828 scsi_print_addr(xs->sc_link);
829 else
830 printf("%s: ", sc->sc_dev.dv_xname);
831 if (msg == MSG_EXTENDED) {
832 printf("scsi message reject, extended "
833 "message sent was 0x%x\n", extmsg);
834 } else {
835 printf("scsi message reject, message "
836 "sent was 0x%x\n", msg);
837 }
838 /* no table to flush here */
839 CALL_SCRIPT(Ent_msgin_ack);
840 return 1;
841 }
842 if (xs)
843 scsi_print_addr(xs->sc_link);
844 else
845 printf("%s: ", sc->sc_dev.dv_xname);
846 printf("unhandled message 0x%x\n",
847 siop_cmd->siop_table->msg_in[0]);
848 siop_cmd->siop_table->t_msgout.count= htole32(1);
849 siop_cmd->siop_table->t_msgout.addr =
850 htole32(siop_cmd->dsa);
851 siop_cmd->siop_table->msg_out[0] = MSG_MESSAGE_REJECT;
852 siop_table_sync(siop_cmd,
853 BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
854 CALL_SCRIPT(Ent_send_msgout);
855 return 1;
856 case A_int_extmsgin:
857 #ifdef DEBUG_INTR
858 printf("extended message: msg 0x%x len %d\n",
859 siop_cmd->siop_table->msg_in[2],
860 siop_cmd->siop_table->msg_in[1]);
861 #endif
862 if (siop_cmd->siop_table->msg_in[1] > 6)
863 printf("%s: extended message too big (%d)\n",
864 sc->sc_dev.dv_xname,
865 siop_cmd->siop_table->msg_in[1]);
866 siop_cmd->siop_table->t_extmsgdata.count =
867 htole32(siop_cmd->siop_table->msg_in[1] - 1);
868 siop_cmd->siop_table->t_extmsgdata.addr =
869 htole32(
870 le32toh(siop_cmd->siop_table->t_extmsgin.addr)
871 + 2);
872 siop_table_sync(siop_cmd,
873 BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
874 CALL_SCRIPT(Ent_get_extmsgdata);
875 return 1;
876 case A_int_extmsgdata:
877 #ifdef DEBUG_INTR
878 {
879 int i;
880 printf("extended message: 0x%x, data:",
881 siop_cmd->siop_table->msg_in[2]);
882 for (i = 3; i < 2 + siop_cmd->siop_table->msg_in[1];
883 i++)
884 printf(" 0x%x",
885 siop_cmd->siop_table->msg_in[i]);
886 printf("\n");
887 }
888 #endif
889 if (siop_cmd->siop_table->msg_in[2] == MSG_EXT_WDTR) {
890 siop_wdtr_neg(siop_cmd);
891 return(1);
892 }
893 if (siop_cmd->siop_table->msg_in[2] == MSG_EXT_SDTR) {
894 siop_sdtr_neg(siop_cmd);
895 return(1);
896 }
897 /* send a message reject */
898 siop_cmd->siop_table->t_msgout.count =
899 htole32(1);
900 siop_cmd->siop_table->t_msgout.addr =
901 htole32(siop_cmd->dsa);
902 siop_cmd->siop_table->msg_out[0] =
903 MSG_MESSAGE_REJECT;
904 siop_table_sync(siop_cmd,
905 BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
906 CALL_SCRIPT(Ent_send_msgout);
907 return 1;
908 case A_int_resel: /* reselected */
909 INCSTAT(siop_stat_intr_reselect);
910 if ((siop_cmd->siop_table->msg_in[0] & 0x80) == 0) {
911 printf("%s: reselect without identify (%d)\n",
912 sc->sc_dev.dv_xname,
913 siop_cmd->siop_table->msg_in[0]);
914 goto reset;
915 }
916 target = bus_space_read_1(sc->sc_rt,
917 sc->sc_rh, SIOP_SCRATCHA);
918 if ((target & 0x80) == 0) {
919 printf("reselect without id (%d)\n", target);
920 goto reset;
921 }
922 target &= 0x0f;
923 lun = siop_cmd->siop_table->msg_in[0] & 0x07;
924 #ifdef DEBUG_DR
925 printf("reselected by target %d lun %d\n",
926 target, lun);
927 #endif
928 siop_cmd =
929 sc->targets[target]->active_list[lun].tqh_first;
930 if (siop_cmd == NULL) {
931 printf("%s: reselected without cmd\n",
932 sc->sc_dev.dv_xname);
933 goto reset;
934 }
935 bus_space_write_4(sc->sc_rt, sc->sc_rh, SIOP_DSA,
936 siop_cmd->dsa);
937 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL3,
938 (sc->targets[target]->id >> 24) & 0xff);
939 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCXFER,
940 (sc->targets[target]->id >> 8) & 0xff);
941 /* no table to flush */
942 CALL_SCRIPT(Ent_selected);
943 return 1;
944 case A_int_disc:
945 INCSTAT(siop_stat_intr_sdp);
946 offset = bus_space_read_1(sc->sc_rt, sc->sc_rh,
947 SIOP_SCRATCHA + 1);
948 #ifdef DEBUG_DR
949 printf("disconnect offset %d\n", offset);
950 #endif
951 if (offset > SIOP_NSG) {
952 printf("%s: bad offset for disconnect (%d)\n",
953 sc->sc_dev.dv_xname, offset);
954 goto reset;
955 }
956 /*
957 * offset == SIOP_NSG may be a valid condition if
958 * we get a sdp when the xfer is done.
959 * Don't call memmove in this case.
960 */
961 if (offset < SIOP_NSG) {
962 memmove(&siop_cmd->siop_table->data[0],
963 &siop_cmd->siop_table->data[offset],
964 (SIOP_NSG - offset) * sizeof(scr_table_t));
965 siop_table_sync(siop_cmd,
966 BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
967 }
968 CALL_SCRIPT(Ent_sheduler);
969 return 1;
970 case A_int_resfail:
971 printf("reselect failed\n");
972 CALL_SCRIPT(Ent_sheduler);
973 return 1;
974 case A_int_done:
975 if (xs == NULL) {
976 printf("%s: done without command, DSA=0x%lx\n",
977 sc->sc_dev.dv_xname, (u_long)siop_cmd->dsa);
978 siop_cmd->status = CMDST_FREE;
979 CALL_SCRIPT(Ent_sheduler);
980 siop_start(sc);
981 return 1;
982 }
983 if (siop_target->status == TARST_PROBING)
984 siop_target->status = TARST_ASYNC;
985 #ifdef DEBUG_INTR
986 printf("done, DSA=0x%lx target id 0x%x last msg "
987 "in=0x%x status=0x%x\n", (u_long)siop_cmd->dsa,
988 le32toh(siop_cmd->siop_table->id),
989 siop_cmd->siop_table->msg_in[0],
990 le32toh(siop_cmd->siop_table->status));
991 #endif
992 INCSTAT(siop_stat_intr_done);
993 if (siop_cmd->status == CMDST_SENSE_ACTIVE)
994 siop_cmd->status = CMDST_SENSE_DONE;
995 else
996 siop_cmd->status = CMDST_DONE;
997 switch(le32toh(siop_cmd->siop_table->status)) {
998 case SCSI_OK:
999 xs->error = (siop_cmd->status == CMDST_DONE) ?
1000 XS_NOERROR : XS_SENSE;
1001 break;
1002 case SCSI_BUSY:
1003 xs->error = XS_BUSY;
1004 break;
1005 case SCSI_CHECK:
1006 check_sense:
1007 if (siop_cmd->status == CMDST_SENSE_DONE) {
1008 /* request sense on a request sense ? */
1009 printf("request sense failed\n");
1010 xs->error = XS_DRIVER_STUFFUP;
1011 } else {
1012 siop_cmd->status = CMDST_SENSE;
1013 }
1014 break;
1015 case 0xff:
1016 /*
1017 * the status byte was not updated, cmd was
1018 * aborted
1019 */
1020 xs->error = XS_SELTIMEOUT;
1021 break;
1022 default:
1023 xs->error = XS_DRIVER_STUFFUP;
1024 }
1025 goto end;
1026 default:
1027 printf("unknown irqcode %x\n", irqcode);
1028 xs->error = XS_SELTIMEOUT;
1029 goto end;
1030 }
1031 return 1;
1032 }
1033 /* We just should't get there */
1034 panic("siop_intr: I shouldn't be there !");
1035 return 1;
1036 end:
1037 bus_space_write_4(sc->sc_rt, sc->sc_rh, SIOP_DSP,
1038 sc->sc_scriptdma->dm_segs[0].ds_addr + Ent_sheduler);
1039 lun = siop_cmd->xs->sc_link->scsipi_scsi.lun;
1040 siop_scsicmd_end(siop_cmd);
1041 if (siop_cmd->status == CMDST_FREE) {
1042 TAILQ_REMOVE(&siop_target->active_list[lun],
1043 siop_cmd, next);
1044 TAILQ_INSERT_TAIL(&sc->free_list, siop_cmd, next);
1045 }
1046 siop_start(sc);
1047 return 1;
1048 }
1049
1050 void
1051 siop_scsicmd_end(siop_cmd)
1052 struct siop_cmd *siop_cmd;
1053 {
1054 struct scsipi_xfer *xs = siop_cmd->xs;
1055 struct siop_softc *sc = siop_cmd->siop_target->siop_sc;
1056
1057 if (siop_cmd->status != CMDST_SENSE_DONE &&
1058 xs->xs_control & (XS_CTL_DATA_IN | XS_CTL_DATA_OUT)) {
1059 bus_dmamap_sync(sc->sc_dmat, siop_cmd->dmamap_data, 0,
1060 siop_cmd->dmamap_data->dm_mapsize,
1061 (xs->xs_control & XS_CTL_DATA_IN) ?
1062 BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
1063 bus_dmamap_unload(sc->sc_dmat, siop_cmd->dmamap_data);
1064 }
1065 bus_dmamap_unload(sc->sc_dmat, siop_cmd->dmamap_cmd);
1066 if (siop_cmd->status == CMDST_SENSE) {
1067 /* issue a request sense for this target */
1068 int error, i;
1069 siop_cmd->rs_cmd.opcode = REQUEST_SENSE;
1070 siop_cmd->rs_cmd.byte2 = xs->sc_link->scsipi_scsi.lun << 5;
1071 siop_cmd->rs_cmd.unused[0] = siop_cmd->rs_cmd.unused[1] = 0;
1072 siop_cmd->rs_cmd.length = sizeof(struct scsipi_sense_data);
1073 siop_cmd->rs_cmd.control = 0;
1074 siop_cmd->siop_table->status = htole32(0xff); /*invalid status*/
1075 siop_cmd->siop_table->t_msgout.count= htole32(1);
1076 siop_cmd->siop_table->t_msgout.addr = htole32(siop_cmd->dsa);
1077 siop_cmd->siop_table->msg_out[0] =
1078 MSG_IDENTIFY(xs->sc_link->scsipi_scsi.lun, 1);
1079 error = bus_dmamap_load(sc->sc_dmat, siop_cmd->dmamap_cmd,
1080 &siop_cmd->rs_cmd, sizeof(struct scsipi_sense),
1081 NULL, BUS_DMA_NOWAIT);
1082 if (error) {
1083 printf("%s: unable to load cmd DMA map: %d",
1084 sc->sc_dev.dv_xname, error);
1085 xs->error = XS_DRIVER_STUFFUP;
1086 goto out;
1087 }
1088 siop_cmd->siop_table->cmd.count =
1089 htole32(siop_cmd->dmamap_cmd->dm_segs[0].ds_len);
1090 siop_cmd->siop_table->cmd.addr =
1091 htole32(siop_cmd->dmamap_cmd->dm_segs[0].ds_addr);
1092 error = bus_dmamap_load(sc->sc_dmat, siop_cmd->dmamap_data,
1093 &xs->sense.scsi_sense, sizeof(struct scsipi_sense_data),
1094 NULL, BUS_DMA_NOWAIT);
1095 if (error) {
1096 printf("%s: unable to load sense DMA map: %d",
1097 sc->sc_dev.dv_xname, error);
1098 xs->error = XS_DRIVER_STUFFUP;
1099 bus_dmamap_unload(sc->sc_dmat, siop_cmd->dmamap_cmd);
1100 goto out;
1101 }
1102 for (i = 0; i < siop_cmd->dmamap_data->dm_nsegs; i++) {
1103 siop_cmd->siop_table->data[i].count =
1104 htole32(siop_cmd->dmamap_data->dm_segs[i].ds_len);
1105 siop_cmd->siop_table->data[i].addr =
1106 htole32(siop_cmd->dmamap_data->dm_segs[i].ds_addr);
1107 }
1108 bus_dmamap_sync(sc->sc_dmat, siop_cmd->dmamap_data, 0,
1109 siop_cmd->dmamap_data->dm_mapsize, BUS_DMASYNC_PREREAD);
1110 bus_dmamap_sync(sc->sc_dmat, siop_cmd->dmamap_cmd, 0,
1111 siop_cmd->dmamap_cmd->dm_mapsize, BUS_DMASYNC_PREWRITE);
1112 siop_table_sync(siop_cmd, BUS_DMASYNC_PREWRITE);
1113 return;
1114 } else if (siop_cmd->status == CMDST_SENSE_DONE) {
1115 bus_dmamap_sync(sc->sc_dmat, siop_cmd->dmamap_data, 0,
1116 siop_cmd->dmamap_data->dm_mapsize, BUS_DMASYNC_POSTREAD);
1117 bus_dmamap_unload(sc->sc_dmat, siop_cmd->dmamap_data);
1118 }
1119 out:
1120 callout_stop(&siop_cmd->xs->xs_callout);
1121 siop_cmd->status = CMDST_FREE;
1122 xs->xs_status |= XS_STS_DONE;
1123 xs->resid = 0;
1124 scsipi_done (xs);
1125 }
1126
1127 void
1128 siop_wdtr_neg(siop_cmd)
1129 struct siop_cmd *siop_cmd;
1130 {
1131 struct siop_softc *sc = siop_cmd->siop_target->siop_sc;
1132 struct siop_target *siop_target = siop_cmd->siop_target;
1133 int target = siop_cmd->xs->sc_link->scsipi_scsi.target;
1134
1135 if (siop_target->status == TARST_WIDE_NEG) {
1136 /* we initiated wide negotiation */
1137 switch (siop_cmd->siop_table->msg_in[3]) {
1138 case MSG_EXT_WDTR_BUS_8_BIT:
1139 printf("%s: target %d using 8bit transfers\n",
1140 sc->sc_dev.dv_xname, target);
1141 siop_target->flags &= ~SF_BUS_WIDE;
1142 sc->targets[target]->id &= ~(SCNTL3_EWS << 24);
1143 break;
1144 case MSG_EXT_WDTR_BUS_16_BIT:
1145 if (sc->features & SF_BUS_WIDE) {
1146 printf("%s: target %d using 16bit transfers\n",
1147 sc->sc_dev.dv_xname, target);
1148 siop_target->flags |= TARF_WIDE;
1149 sc->targets[target]->id |= (SCNTL3_EWS << 24);
1150 break;
1151 }
1152 /* FALLTHROUH */
1153 default:
1154 /*
1155 * hum, we got more than what we can handle, shoudn't
1156 * happen. Reject, and stay async
1157 */
1158 siop_target->flags &= ~TARF_WIDE;
1159 siop_target->status = TARST_OK;
1160 printf("%s: rejecting invalid wide negotiation from "
1161 "target %d (%d)\n", sc->sc_dev.dv_xname, target,
1162 siop_cmd->siop_table->msg_in[3]);
1163 siop_cmd->siop_table->t_msgout.count= htole32(1);
1164 siop_cmd->siop_table->t_msgout.addr =
1165 htole32(siop_cmd->dsa);
1166 siop_cmd->siop_table->msg_out[0] = MSG_MESSAGE_REJECT;
1167 siop_table_sync(siop_cmd,
1168 BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1169 CALL_SCRIPT(Ent_send_msgout);
1170 return;
1171 }
1172 siop_cmd->siop_table->id =
1173 htole32(sc->targets[target]->id);
1174 bus_space_write_1(sc->sc_rt, sc->sc_rh,
1175 SIOP_SCNTL3,
1176 (sc->targets[target]->id >> 24) & 0xff);
1177 /* we now need to do sync */
1178 siop_target->status = TARST_SYNC_NEG;
1179 siop_cmd->siop_table->msg_out[0] = MSG_EXTENDED;
1180 siop_cmd->siop_table->msg_out[1] = MSG_EXT_SDTR_LEN;
1181 siop_cmd->siop_table->msg_out[2] = MSG_EXT_SDTR;
1182 siop_cmd->siop_table->msg_out[3] = sc->minsync;
1183 siop_cmd->siop_table->msg_out[4] = sc->maxoff;
1184 siop_cmd->siop_table->t_msgout.count =
1185 htole32(MSG_EXT_SDTR_LEN + 2);
1186 siop_cmd->siop_table->t_msgout.addr = htole32(siop_cmd->dsa);
1187 siop_table_sync(siop_cmd,
1188 BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1189 CALL_SCRIPT(Ent_send_msgout);
1190 return;
1191 } else {
1192 /* target initiated wide negotiation */
1193 if (siop_cmd->siop_table->msg_in[3] >= MSG_EXT_WDTR_BUS_16_BIT
1194 && (sc->features & SF_BUS_WIDE)) {
1195 printf("%s: target %d using 16bit transfers\n",
1196 sc->sc_dev.dv_xname, target);
1197 siop_target->flags |= TARF_WIDE;
1198 sc->targets[target]->id |= SCNTL3_EWS << 24;
1199 siop_cmd->siop_table->msg_out[3] =
1200 MSG_EXT_WDTR_BUS_16_BIT;
1201 } else {
1202 printf("%s: target %d using 8bit transfers\n",
1203 sc->sc_dev.dv_xname, target);
1204 siop_target->flags &= ~SF_BUS_WIDE;
1205 sc->targets[target]->id &= ~(SCNTL3_EWS << 24);
1206 siop_cmd->siop_table->msg_out[3] =
1207 MSG_EXT_WDTR_BUS_8_BIT;
1208 }
1209 siop_cmd->siop_table->id =
1210 htole32(sc->targets[target]->id);
1211 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL3,
1212 (sc->targets[target]->id >> 24) & 0xff);
1213 /*
1214 * we did reset wide parameters, so fall back to async,
1215 * but don't shedule a sync neg, target should initiate it
1216 */
1217 siop_target->status = TARST_OK;
1218 siop_cmd->siop_table->msg_out[0] = MSG_EXTENDED;
1219 siop_cmd->siop_table->msg_out[1] = MSG_EXT_WDTR_LEN;
1220 siop_cmd->siop_table->msg_out[2] = MSG_EXT_WDTR;
1221 siop_cmd->siop_table->t_msgout.count=
1222 htole32(MSG_EXT_WDTR_LEN + 2);
1223 siop_cmd->siop_table->t_msgout.addr = htole32(siop_cmd->dsa);
1224 siop_table_sync(siop_cmd,
1225 BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1226 CALL_SCRIPT(Ent_send_msgout);
1227 }
1228 }
1229
1230 void
1231 siop_sdtr_neg(siop_cmd)
1232 struct siop_cmd *siop_cmd;
1233 {
1234 struct siop_softc *sc = siop_cmd->siop_target->siop_sc;
1235 struct siop_target *siop_target = siop_cmd->siop_target;
1236 int target = siop_cmd->xs->sc_link->scsipi_scsi.target;
1237 int sync, offset, i;
1238 int send_msgout = 0;
1239
1240 sync = siop_cmd->siop_table->msg_in[3];
1241 offset = siop_cmd->siop_table->msg_in[4];
1242
1243 if (siop_target->status == TARST_SYNC_NEG) {
1244 /* we initiated sync negotiation */
1245 siop_target->status = TARST_OK;
1246 #ifdef DEBUG
1247 printf("sdtr: sync %d offset %d\n", sync, offset);
1248 #endif
1249 if (offset > sc->maxoff || sync < sc->minsync ||
1250 sync > sc->maxsync)
1251 goto reject;
1252 for (i = 0; i < sizeof(scf_period) / sizeof(scf_period[0]);
1253 i++) {
1254 if (sc->clock_period != scf_period[i].clock)
1255 continue;
1256 if (scf_period[i].period == sync) {
1257 /* ok, found it. we now are sync. */
1258 printf("%s: target %d now synchronous at "
1259 "%sMhz, offset %d\n", sc->sc_dev.dv_xname,
1260 target, scf_period[i].rate, offset);
1261 sc->targets[target]->id &=
1262 ~(SCNTL3_SCF_MASK << 24);
1263 sc->targets[target]->id |= scf_period[i].scf
1264 << (24 + SCNTL3_SCF_SHIFT);
1265 if (sync < 25) /* Ultra */
1266 sc->targets[target]->id |=
1267 SCNTL3_ULTRA << 24;
1268 else
1269 sc->targets[target]->id &=
1270 ~(SCNTL3_ULTRA << 24);
1271 sc->targets[target]->id &=
1272 ~(SCXFER_MO_MASK << 8);
1273 sc->targets[target]->id |=
1274 (offset & SCXFER_MO_MASK) << 8;
1275 goto end;
1276 }
1277 }
1278 /*
1279 * we didn't find it in our table, do async and send reject
1280 * msg
1281 */
1282 reject:
1283 send_msgout = 1;
1284 siop_cmd->siop_table->t_msgout.count= htole32(1);
1285 siop_cmd->siop_table->msg_out[0] = MSG_MESSAGE_REJECT;
1286 printf("%s: target %d asynchronous\n", sc->sc_dev.dv_xname,
1287 target);
1288 sc->targets[target]->id &= ~(SCNTL3_SCF_MASK << 24);
1289 sc->targets[target]->id &= ~(SCNTL3_ULTRA << 24);
1290 sc->targets[target]->id &= ~(SCXFER_MO_MASK << 8);
1291 } else { /* target initiated sync neg */
1292 #ifdef DEBUG
1293 printf("sdtr (target): sync %d offset %d\n", sync, offset);
1294 #endif
1295 if (offset == 0 || sync > sc->maxsync) { /* async */
1296 goto async;
1297 }
1298 if (offset > sc->maxoff)
1299 offset = sc->maxoff;
1300 if (sync < sc->minsync)
1301 sync = sc->minsync;
1302 /* look for sync period */
1303 for (i = 0; i < sizeof(scf_period) / sizeof(scf_period[0]);
1304 i++) {
1305 if (sc->clock_period != scf_period[i].clock)
1306 continue;
1307 if (scf_period[i].period == sync) {
1308 /* ok, found it. we now are sync. */
1309 printf("%s: target %d now synchronous at "
1310 "%sMhz, offset %d\n", sc->sc_dev.dv_xname,
1311 target, scf_period[i].rate, offset);
1312 sc->targets[target]->id &=
1313 ~(SCNTL3_SCF_MASK << 24);
1314 sc->targets[target]->id |= scf_period[i].scf
1315 << (24 + SCNTL3_SCF_SHIFT);
1316 if (sync < 25) /* Ultra */
1317 sc->targets[target]->id |=
1318 SCNTL3_ULTRA << 24;
1319 else
1320 sc->targets[target]->id &=
1321 ~(SCNTL3_ULTRA << 24);
1322 sc->targets[target]->id &=
1323 ~(SCXFER_MO_MASK << 8);
1324 sc->targets[target]->id |=
1325 (offset & SCXFER_MO_MASK) << 8;
1326 siop_cmd->siop_table->msg_out[0] = MSG_EXTENDED;
1327 siop_cmd->siop_table->msg_out[1] =
1328 MSG_EXT_SDTR_LEN;
1329 siop_cmd->siop_table->msg_out[2] = MSG_EXT_SDTR;
1330 siop_cmd->siop_table->msg_out[3] = sync;
1331 siop_cmd->siop_table->msg_out[4] = offset;
1332 siop_cmd->siop_table->t_msgout.count=
1333 htole32(MSG_EXT_SDTR_LEN + 2);
1334 send_msgout = 1;
1335 goto end;
1336 }
1337 }
1338 async:
1339 printf("%s: target %d asynchronous\n",
1340 sc->sc_dev.dv_xname, target);
1341 sc->targets[target]->id &= ~(SCNTL3_SCF_MASK << 24);
1342 sc->targets[target]->id &= ~(SCNTL3_ULTRA << 24);
1343 sc->targets[target]->id &= ~(SCXFER_MO_MASK << 8);
1344 siop_cmd->siop_table->msg_out[0] = MSG_EXTENDED;
1345 siop_cmd->siop_table->msg_out[1] = MSG_EXT_SDTR_LEN;
1346 siop_cmd->siop_table->msg_out[2] = MSG_EXT_SDTR;
1347 siop_cmd->siop_table->msg_out[3] = 0;
1348 siop_cmd->siop_table->msg_out[4] = 0;
1349 siop_cmd->siop_table->t_msgout.count=
1350 htole32(MSG_EXT_SDTR_LEN + 2);
1351 send_msgout = 1;
1352 }
1353 end:
1354 #ifdef DEBUG
1355 printf("id now 0x%x\n", sc->targets[target]->id);
1356 #endif
1357 siop_cmd->siop_table->id = htole32(sc->targets[target]->id);
1358 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL3,
1359 (sc->targets[target]->id >> 24) & 0xff);
1360 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCXFER,
1361 (sc->targets[target]->id >> 8) & 0xff);
1362 if (send_msgout) {
1363 siop_cmd->siop_table->t_msgout.addr = htole32(siop_cmd->dsa);
1364 siop_table_sync(siop_cmd,
1365 BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1366 CALL_SCRIPT(Ent_send_msgout);
1367 } else {
1368 CALL_SCRIPT(Ent_msgin_ack);
1369 }
1370 return;
1371 }
1372
1373 /*
1374 * handle a bus reset: reset chip, unqueue all active commands and report
1375 * loosage to upper layer.
1376 * As the upper layer may requeue immediatly we have to first store
1377 * all active commands in a temporary queue.
1378 */
1379 void
1380 siop_handle_reset(sc)
1381 struct siop_softc *sc;
1382 {
1383 struct cmd_list reset_list;
1384 struct siop_cmd *siop_cmd, *next_siop_cmd;
1385 int target, lun;
1386 /*
1387 * scsi bus reset. reset the chip and restart
1388 * the queue. Need to clean up all active commands
1389 */
1390 printf("%s: scsi bus reset\n", sc->sc_dev.dv_xname);
1391 /* stop, reset and restart the chip */
1392 siop_reset(sc);
1393 TAILQ_INIT(&reset_list);
1394 /* find all active commands */
1395 for (target = 0; target < sc->sc_link.scsipi_scsi.max_target;
1396 target++) {
1397 if (sc->targets[target] == NULL)
1398 continue;
1399 for (lun = 0; lun < 8; lun++) {
1400 for (siop_cmd =
1401 TAILQ_FIRST(&sc->targets[target]->active_list[lun]);
1402 siop_cmd != NULL; siop_cmd = next_siop_cmd) {
1403 next_siop_cmd = TAILQ_NEXT(siop_cmd, next);
1404 if (siop_cmd->status < CMDST_ACTIVE)
1405 continue;
1406 printf("cmd %p (target %d) in reset list\n",
1407 siop_cmd, target);
1408 TAILQ_REMOVE(
1409 &sc->targets[target]->active_list[lun],
1410 siop_cmd, next);
1411 TAILQ_INSERT_TAIL(&reset_list, siop_cmd, next);
1412 }
1413 }
1414 sc->targets[target]->status = TARST_ASYNC;
1415 sc->targets[target]->flags = ~(TARF_SYNC | TARF_WIDE);
1416 }
1417 for (siop_cmd = TAILQ_FIRST(&reset_list); siop_cmd != NULL;
1418 siop_cmd = next_siop_cmd) {
1419 next_siop_cmd = TAILQ_NEXT(siop_cmd, next);
1420 siop_cmd->xs->error = (siop_cmd->flags & CMDFL_TIMEOUT) ?
1421 XS_TIMEOUT : XS_RESET;
1422 printf("cmd %p about to be processed\n", siop_cmd);
1423 TAILQ_REMOVE(&reset_list, siop_cmd, next);
1424 siop_scsicmd_end(siop_cmd);
1425 TAILQ_INSERT_TAIL(&sc->free_list, siop_cmd, next);
1426 }
1427 }
1428
1429 void
1430 siop_minphys(bp)
1431 struct buf *bp;
1432 {
1433 minphys(bp);
1434 }
1435
1436 int
1437 siop_ioctl(link, cmd, arg, flag, p)
1438 struct scsipi_link *link;
1439 u_long cmd;
1440 caddr_t arg;
1441 int flag;
1442 struct proc *p;
1443 {
1444 struct siop_softc *sc = link->adapter_softc;
1445 u_int8_t scntl1;
1446 int s;
1447
1448 switch (cmd) {
1449 case SCBUSIORESET:
1450 s = splbio();
1451 scntl1 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1);
1452 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1,
1453 scntl1 | SCNTL1_RST);
1454 /* minimum 25 us, more time won't hurt */
1455 delay(100);
1456 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1, scntl1);
1457 splx(s);
1458 return (0);
1459 default:
1460 return (ENOTTY);
1461 }
1462 }
1463
1464 int
1465 siop_scsicmd(xs)
1466 struct scsipi_xfer *xs;
1467 {
1468 struct siop_softc *sc = (struct siop_softc *)xs->sc_link->adapter_softc;
1469 struct siop_cmd *siop_cmd;
1470 int s, error, i;
1471 int target = xs->sc_link->scsipi_scsi.target;
1472 int lun = xs->sc_link->scsipi_scsi.lun;
1473
1474 s = splbio();
1475 #ifdef DEBUG_SHED
1476 printf("starting cmd for %d:%d\n", target, lun);
1477 #endif
1478 siop_cmd = sc->free_list.tqh_first;
1479 if (siop_cmd) {
1480 TAILQ_REMOVE(&sc->free_list, siop_cmd, next);
1481 }
1482 splx(s);
1483 if (siop_cmd == NULL) {
1484 xs->error = XS_DRIVER_STUFFUP;
1485 return(TRY_AGAIN_LATER);
1486 }
1487 #ifdef DIAGNOSTIC
1488 if (siop_cmd->status != CMDST_FREE)
1489 panic("siop_scsicmd: new cmd not free");
1490 #endif
1491 if (sc->targets[target] == NULL) {
1492 sc->targets[target] =
1493 malloc(sizeof(struct siop_target), M_DEVBUF, M_NOWAIT);
1494 if (sc->targets[target] == NULL) {
1495 printf("%s: can't malloc memory for target %d\n",
1496 sc->sc_dev.dv_xname, target);
1497 xs->error = XS_DRIVER_STUFFUP;
1498 return(TRY_AGAIN_LATER);
1499 }
1500 sc->targets[target]->siop_sc = sc;
1501 sc->targets[target]->status = TARST_PROBING;
1502 sc->targets[target]->flags = 0;
1503 sc->targets[target]->id = sc->clock_div << 24; /* scntl3 */
1504 sc->targets[target]->id |= target << 16; /* id */
1505 /* sc->targets[target]->id |= 0x00 << 8; scxfer is 0 */
1506 for (i = 0; i < 8; i++)
1507 TAILQ_INIT(&sc->targets[target]->active_list[i]);
1508 }
1509 siop_cmd->siop_target = sc->targets[target];
1510 siop_cmd->xs = xs;
1511 siop_cmd->siop_table->id = htole32(sc->targets[target]->id);
1512 siop_cmd->siop_table->t_msgout.count= htole32(1);
1513 siop_cmd->siop_table->t_msgout.addr = htole32(siop_cmd->dsa);
1514 memset(siop_cmd->siop_table->msg_out, 0, 8);
1515 siop_cmd->siop_table->msg_out[0] = MSG_IDENTIFY(lun, 1);
1516 if (sc->targets[target]->status == TARST_ASYNC) {
1517 if (sc->features & SF_BUS_WIDE) {
1518 sc->targets[target]->status = TARST_WIDE_NEG;
1519 siop_cmd->siop_table->msg_out[1] = MSG_EXTENDED;
1520 siop_cmd->siop_table->msg_out[2] = MSG_EXT_WDTR_LEN;
1521 siop_cmd->siop_table->msg_out[3] = MSG_EXT_WDTR;
1522 siop_cmd->siop_table->msg_out[4] =
1523 MSG_EXT_WDTR_BUS_16_BIT;
1524 siop_cmd->siop_table->t_msgout.count=
1525 htole32(MSG_EXT_WDTR_LEN + 2 + 1);
1526 } else {
1527 sc->targets[target]->status = TARST_SYNC_NEG;
1528 siop_cmd->siop_table->msg_out[1] = MSG_EXTENDED;
1529 siop_cmd->siop_table->msg_out[2] = MSG_EXT_SDTR_LEN;
1530 siop_cmd->siop_table->msg_out[3] = MSG_EXT_SDTR;
1531 siop_cmd->siop_table->msg_out[4] = sc->minsync;
1532 siop_cmd->siop_table->msg_out[5] = sc->maxoff;
1533 siop_cmd->siop_table->t_msgout.count=
1534 htole32(MSG_EXT_SDTR_LEN + 2 +1);
1535 }
1536 }
1537 siop_cmd->siop_table->status = htole32(0xff); /* set invalid status */
1538
1539 /* load the DMA maps */
1540 error = bus_dmamap_load(sc->sc_dmat, siop_cmd->dmamap_cmd,
1541 xs->cmd, xs->cmdlen, NULL, BUS_DMA_NOWAIT);
1542 if (error) {
1543 printf("%s: unable to load cmd DMA map: %d",
1544 sc->sc_dev.dv_xname, error);
1545 xs->error = XS_DRIVER_STUFFUP;
1546 return(TRY_AGAIN_LATER);
1547 }
1548 siop_cmd->siop_table->cmd.count =
1549 htole32(siop_cmd->dmamap_cmd->dm_segs[0].ds_len);
1550 siop_cmd->siop_table->cmd.addr =
1551 htole32(siop_cmd->dmamap_cmd->dm_segs[0].ds_addr);
1552 if (xs->xs_control & (XS_CTL_DATA_IN | XS_CTL_DATA_OUT)) {
1553 error = bus_dmamap_load(sc->sc_dmat, siop_cmd->dmamap_data,
1554 xs->data, xs->datalen, NULL, BUS_DMA_NOWAIT);
1555 if (error) {
1556 printf("%s: unable to load cmd DMA map: %d",
1557 sc->sc_dev.dv_xname, error);
1558 xs->error = XS_DRIVER_STUFFUP;
1559 return(TRY_AGAIN_LATER);
1560 bus_dmamap_unload(sc->sc_dmat, siop_cmd->dmamap_cmd);
1561 }
1562 for (i = 0; i < siop_cmd->dmamap_data->dm_nsegs; i++) {
1563 siop_cmd->siop_table->data[i].count =
1564 htole32(siop_cmd->dmamap_data->dm_segs[i].ds_len);
1565 siop_cmd->siop_table->data[i].addr =
1566 htole32(siop_cmd->dmamap_data->dm_segs[i].ds_addr);
1567 }
1568 bus_dmamap_sync(sc->sc_dmat, siop_cmd->dmamap_data, 0,
1569 siop_cmd->dmamap_data->dm_mapsize,
1570 (xs->xs_control & XS_CTL_DATA_IN) ?
1571 BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE);
1572 }
1573 bus_dmamap_sync(sc->sc_dmat, siop_cmd->dmamap_cmd, 0,
1574 siop_cmd->dmamap_cmd->dm_mapsize, BUS_DMASYNC_PREWRITE);
1575 siop_table_sync(siop_cmd, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1576
1577 siop_cmd->status = CMDST_READY;
1578 s = splbio();
1579 TAILQ_INSERT_TAIL(&sc->targets[target]->active_list[lun],
1580 siop_cmd, next);
1581 siop_start(sc);
1582 splx(s);
1583 return (SUCCESSFULLY_QUEUED);
1584 }
1585
1586 void
1587 siop_start(sc)
1588 struct siop_softc *sc;
1589 {
1590 struct siop_cmd *siop_cmd;
1591 u_int32_t *scr;
1592 u_int32_t dsa;
1593 int timeout;
1594 int target, lun, slot;
1595 int newcmd = 0;
1596
1597 /*
1598 * first make sure to read valid data
1599 */
1600 siop_script_sync(sc, BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
1601
1602 /*
1603 * The queue management here is a bit tricky: the script always looks
1604 * at the slot from first to last, so if we always use the first
1605 * free slot commands can stay at the tail of the queue ~forever.
1606 * The algorithm used here is to restart from the head when we know
1607 * that the queue is empty, and only add commands after the last one.
1608 * When we're at the end of the queue wait for the script to clear it.
1609 * The best thing to do here would be to implement a circular queue,
1610 * but using only 53c720 features this can be "interesting".
1611 * A mid-way solution could be to implement 2 queues and swap orders.
1612 */
1613 slot = sc->sc_currshedslot;
1614 scr = &sc->sc_script[Ent_sheduler / 4 +
1615 (Ent_nextslot / 4) * slot];
1616 /*
1617 * if relative addr of first jump is not 0 the slot is free. As this is
1618 * the last used slot, all previous slots are free, we can restart
1619 * from 0.
1620 */
1621 if (scr[Ent_slot / 4 + 1] != 0) {
1622 slot = sc->sc_currshedslot = 0;
1623 } else {
1624 slot++;
1625 }
1626
1627 for (target = 0; target <= sc->sc_link.scsipi_scsi.max_target;
1628 target++) {
1629 if (sc->targets[target] == NULL)
1630 continue;
1631 for (lun = 0; lun < 8; lun++) {
1632 siop_cmd =
1633 sc->targets[target]->active_list[lun].tqh_first;
1634 if (siop_cmd == NULL)
1635 continue;
1636 if (siop_cmd->status != CMDST_READY &&
1637 siop_cmd->status != CMDST_SENSE)
1638 continue;
1639 /* find a free sheduler slot and load it */
1640 for (; slot < sc->sc_nshedslots; slot++) {
1641 scr = &sc->sc_script[Ent_sheduler / 4 +
1642 (Ent_nextslot / 4) * slot];
1643 /*
1644 * if relative addr of first jump is 0 the
1645 * slot isn't free
1646 */
1647 if (scr[Ent_slot / 4 + 1] == 0)
1648 continue;
1649 #ifdef DEBUG_SHED
1650 printf("using slot %d for DSA 0x%lx\n", slot,
1651 (u_long)siop_cmd->dsa);
1652 #endif
1653 /* note that we started a new command */
1654 newcmd = 1;
1655 /* mark command as active */
1656 if (siop_cmd->status == CMDST_READY)
1657 siop_cmd->status = CMDST_ACTIVE;
1658 else if (siop_cmd->status == CMDST_SENSE)
1659 siop_cmd->status = CMDST_SENSE_ACTIVE;
1660 else
1661 panic("siop_start: bad status");
1662 /* patch script with DSA addr */
1663 dsa = siop_cmd->dsa;
1664 /*
1665 * 0x78000000 is a 'move data8 to reg'. data8
1666 * is the second octet, reg offset is the third.
1667 */
1668 scr[Ent_idsa0 / 4] =
1669 htole32(0x78100000 |
1670 ((dsa & 0x000000ff) << 8));
1671 scr[Ent_idsa1 / 4] =
1672 htole32(0x78110000 |
1673 ( dsa & 0x0000ff00 ));
1674 scr[Ent_idsa2 / 4] =
1675 htole32(0x78120000 |
1676 ((dsa & 0x00ff0000) >> 8));
1677 scr[Ent_idsa3 / 4] =
1678 htole32(0x78130000 |
1679 ((dsa & 0xff000000) >> 16));
1680 /* handle timeout */
1681 if (siop_cmd->status == CMDST_ACTIVE) {
1682 if ((siop_cmd->xs->xs_control &
1683 XS_CTL_POLL) == 0) {
1684 /* start exire timer */
1685 timeout =
1686 siop_cmd->xs->timeout *
1687 hz / 1000;
1688 if (timeout == 0)
1689 timeout = 1;
1690 callout_reset(
1691 &siop_cmd->xs->xs_callout,
1692 timeout, siop_timeout,
1693 siop_cmd);
1694 }
1695 }
1696 /*
1697 * Change jump offset so that this slot will be
1698 * handled
1699 */
1700 scr[Ent_slot / 4 + 1] = 0;
1701 break;
1702 }
1703 /* no more free slot, no need to continue */
1704 if (slot == sc->sc_nshedslots) {
1705 goto end;
1706 }
1707 sc->sc_currshedslot = slot;
1708 }
1709 }
1710 end:
1711 /* if nothing changed no need to flush cache and wakeup script */
1712 if (newcmd == 0)
1713 return;
1714 /* make sure SCRIPT processor will read valid data */
1715 siop_script_sync(sc, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1716 /* Signal script it has some work to do */
1717 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_ISTAT, ISTAT_SIGP);
1718 /* and wait for IRQ */
1719 return;
1720 }
1721
1722 void
1723 siop_timeout(v)
1724 void *v;
1725 {
1726 struct siop_cmd *siop_cmd = v;
1727 struct siop_softc *sc = siop_cmd->siop_target->siop_sc;
1728 int s;
1729 u_int8_t scntl1;
1730
1731 scsi_print_addr(siop_cmd->xs->sc_link);
1732 printf("command timeout\n");
1733
1734 s = splbio();
1735 /* reset the scsi bus */
1736 scntl1 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1);
1737 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1,
1738 scntl1 | SCNTL1_RST);
1739 /* minimum 25 us, more time won't hurt */
1740 delay(100);
1741 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1, scntl1);
1742
1743 /* deactivate callout */
1744 callout_stop(&siop_cmd->xs->xs_callout);
1745 /* mark command has being timed out; siop_intr will handle it */
1746 /*
1747 * mark command has being timed out and just return;
1748 * the bus reset will generate an interrupt,
1749 * it will be handled in siop_intr()
1750 */
1751 siop_cmd->flags |= CMDFL_TIMEOUT;
1752 splx(s);
1753 return;
1754
1755 }
1756
1757 void
1758 siop_sdp(siop_cmd)
1759 struct siop_cmd *siop_cmd;
1760 {
1761 /* save data pointer. Handle async only for now */
1762 int offset, dbc, sstat;
1763 struct siop_softc *sc = siop_cmd->siop_target->siop_sc;
1764 scr_table_t *table; /* table to patch */
1765
1766 if ((siop_cmd->xs->xs_control & (XS_CTL_DATA_OUT | XS_CTL_DATA_IN))
1767 == 0)
1768 return; /* no data pointers to save */
1769 offset = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SCRATCHA + 1);
1770 if (offset >= SIOP_NSG) {
1771 printf("%s: bad offset in siop_sdp (%d)\n",
1772 sc->sc_dev.dv_xname, offset);
1773 return;
1774 }
1775 table = &siop_cmd->siop_table->data[offset];
1776 #ifdef DEBUG_DR
1777 printf("sdp: offset %d count=%d addr=0x%x ", offset,
1778 table->count, table->addr);
1779 #endif
1780 dbc = bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DBC) & 0x00ffffff;
1781 if (siop_cmd->xs->xs_control & XS_CTL_DATA_OUT) {
1782 /* need to account stale data in FIFO */
1783 /* XXX check for large fifo */
1784 dbc += (bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_DFIFO) -
1785 (dbc & 0x7f)) & 0x7f;
1786 sstat = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SSTAT0);
1787 if (sstat & SSTAT0_OLF)
1788 dbc++;
1789 if (sstat & SSTAT0_ORF)
1790 dbc++;
1791 if (siop_cmd->siop_target->flags & TARF_WIDE) {
1792 sstat = bus_space_read_1(sc->sc_rt, sc->sc_rh,
1793 SIOP_SSTAT2);
1794 if (sstat & SSTAT2_OLF1)
1795 dbc++;
1796 if (sstat & SSTAT2_ORF1)
1797 dbc++;
1798 }
1799 /* clear the FIFO */
1800 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3,
1801 bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3) |
1802 CTEST3_CLF);
1803 }
1804 table->addr =
1805 htole32(le32toh(table->addr) + le32toh(table->count) - dbc);
1806 table->count = htole32(dbc);
1807 #ifdef DEBUG_DR
1808 printf("now count=%d addr=0x%x\n", table->count, table->addr);
1809 #endif
1810 }
1811
1812 void
1813 siop_clearfifo(sc)
1814 struct siop_softc *sc;
1815 {
1816 int timeout = 0;
1817 int ctest3 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3);
1818
1819 #ifdef DEBUG_INTR
1820 printf("DMA fifo not empty !\n");
1821 #endif
1822 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3,
1823 ctest3 | CTEST3_CLF);
1824 while ((bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3) &
1825 CTEST3_CLF) != 0) {
1826 delay(1);
1827 if (++timeout > 1000) {
1828 printf("clear fifo failed\n");
1829 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3,
1830 bus_space_read_1(sc->sc_rt, sc->sc_rh,
1831 SIOP_CTEST3) & ~CTEST3_CLF);
1832 return;
1833 }
1834 }
1835 }
1836
1837 void
1838 siop_dump_script(sc)
1839 struct siop_softc *sc;
1840 {
1841 int i;
1842 siop_script_sync(sc, BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
1843 for (i = 0; i < CMD_OFF / 4; i += 2) {
1844 printf("0x%04x: 0x%08x 0x%08x", i * 4,
1845 le32toh(sc->sc_script[i]), le32toh(sc->sc_script[i+1]));
1846 if ((le32toh(sc->sc_script[i]) & 0xe0000000) == 0xc0000000) {
1847 i++;
1848 printf(" 0x%08x", le32toh(sc->sc_script[i+1]));
1849 }
1850 printf("\n");
1851 }
1852 }
1853
1854 #ifdef SIOP_STATS
1855 void
1856 siop_printstats()
1857 {
1858 printf("siop_stat_intr %d\n", siop_stat_intr);
1859 printf("siop_stat_intr_shortxfer %d\n", siop_stat_intr_shortxfer);
1860 printf("siop_stat_intr_xferdisc %d\n", siop_stat_intr_xferdisc);
1861 printf("siop_stat_intr_sdp %d\n", siop_stat_intr_sdp);
1862 printf("siop_stat_intr_reselect %d\n", siop_stat_intr_reselect);
1863 printf("siop_stat_intr_done %d\n", siop_stat_intr_done);
1864 }
1865 #endif
1866