siop.c revision 1.2 1 /* $NetBSD: siop.c,v 1.2 2000/04/25 16:27:05 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 the University of
17 * California, Berkeley and its contributors.
18 * 4. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 *
34 */
35
36 /* SYM53c7/8xx PCI-SCSI I/O Processors driver */
37
38 #include <sys/param.h>
39 #include <sys/systm.h>
40 #include <sys/device.h>
41 #include <sys/malloc.h>
42 #include <sys/buf.h>
43 #include <sys/kernel.h>
44 #include <sys/scsiio.h>
45
46 #include <machine/endian.h>
47 #include <machine/bus.h>
48
49 #include <vm/vm.h>
50 #include <vm/vm_param.h>
51 #include <vm/vm_kern.h>
52
53 #include <dev/microcode/siop/siop.out>
54
55 #include <dev/scsipi/scsi_all.h>
56 #include <dev/scsipi/scsi_message.h>
57 #include <dev/scsipi/scsipi_all.h>
58
59 #include <dev/scsipi/scsiconf.h>
60
61 #include <dev/ic/siopreg.h>
62 #include <dev/ic/siopvar.h>
63
64 #undef DEBUG
65 #undef DEBUG_INTR
66 #undef DEBUG_SHED
67 #undef DUMP_SCRIPT
68
69 #define SIOP_STATS
70
71 #ifndef SIOP_DEFAULT_TARGET
72 #define SIOP_DEFAULT_TARGET 7
73 #endif
74
75 #define MEM_SIZE 8192
76 #define CMD_OFF 4096
77
78 /* tables used by SCRIPT */
79 typedef struct scr_table {
80 u_int32_t count;
81 u_int32_t addr;
82 } scr_table_t ;
83
84 /* Number of scatter/gather entries */
85 #define SIOP_NSG (MAXPHYS/NBPG + 1)
86
87 /*
88 * This structure interfaces the SCRIPT with the driver; it describes a full
89 * transfert. It lives in the same chunk of DMA-safe memory as the script.
90 */
91 struct siop_xfer {
92 u_int8_t msg_out[8]; /* 0 */
93 u_int8_t msg_in[8]; /* 8 */
94 int status; /* 16 */
95 u_int32_t id; /* 20 */
96 u_int32_t pad1; /* 24 */
97 scr_table_t t_msgin; /* 28 */
98 scr_table_t t_extmsgin; /* 36 */
99 scr_table_t t_extmsgdata; /* 44 */
100 scr_table_t t_extmsgtag; /* 52 */
101 scr_table_t t_msgout; /* 60 */
102 scr_table_t cmd; /* 68 */
103 scr_table_t t_status; /* 76 */
104 scr_table_t data[SIOP_NSG]; /* 84 */
105 };
106
107 /*
108 * This decribes a command handled by the SCSI controller
109 * These are chained in either a free list or a active list
110 * We have one queue per target + (one at the adapter's target for probe)
111 */
112 struct siop_cmd {
113 TAILQ_ENTRY (siop_cmd) next;
114 struct siop_softc *siop_sc; /* pointer to adapter */
115 struct scsipi_xfer *xs; /* xfer from the upper level */
116 struct siop_xfer *siop_table; /* tables dealing with this xfer */
117 bus_addr_t dsa; /* DSA value to load */
118 bus_dmamap_t dmamap_cmd;
119 bus_dmamap_t dmamap_data;
120 struct scsipi_sense rs_cmd; /* request sense command buffer */
121 int status;
122 int flags;
123 };
124
125 /* status defs */
126 #define CMDST_FREE 0 /* cmd slot is free */
127 #define CMDST_READY 1 /* cmd slot is waiting for processing */
128 #define CMDST_ACTIVE 2 /* cmd slot is being processed */
129 #define CMDST_SENSE 3 /* cmd slot is being requesting sense */
130 #define CMDST_SENSE_ACTIVE 4 /* request sense active */
131 #define CMDST_SENSE_DONE 5 /* request sense done */
132 #define CMDST_DONE 6 /* cmd slot has been processed */
133 /* flags defs */
134 #define CMDFL_TIMEOUT 0x0001 /* cmd timed out */
135
136 /* initial number of cmd descriptors */
137 #define SIOP_NCMD 10
138
139 void siop_reset __P((struct siop_softc *));
140 void siop_handle_reset __P((struct siop_softc *));
141 void siop_scsicmd_end __P((struct siop_cmd *));
142 void siop_start __P((struct siop_softc *));
143 void siop_timeout __P((void *));
144 void siop_minphys __P((struct buf *));
145 int siop_ioctl __P((struct scsipi_link *, u_long,
146 caddr_t, int, struct proc *));
147 int siop_scsicmd __P((struct scsipi_xfer *));
148 void siop_sdp __P((struct siop_cmd *));
149 void siop_ssg __P((struct siop_cmd *));
150 void siop_dump_script __P((struct siop_softc *));
151
152 struct scsipi_adapter siop_adapter = {
153 0,
154 siop_scsicmd,
155 siop_minphys,
156 siop_ioctl,
157 NULL,
158 };
159
160 struct scsipi_device siop_dev = {
161 NULL,
162 NULL,
163 NULL,
164 NULL,
165 };
166
167 #ifdef SIOP_STATS
168 static int siop_stat_intr = 0;
169 static int siop_stat_intr_shortxfer = 0;
170 static int siop_stat_intr_sdp = 0;
171 static int siop_stat_intr_done = 0;
172 static int siop_stat_intr_reselect = 0;
173 static int siop_stat_intr_xferdisc = 0;
174 void siop_printstats __P((void));
175 #define INCSTAT(x) x++
176 #else
177 #define INCSTAT(x)
178 #endif
179
180 static __inline__ void siop_table_sync __P((struct siop_cmd *, int));
181 static __inline__ void
182 siop_table_sync(siop_cmd, ops)
183 struct siop_cmd *siop_cmd;
184 int ops;
185 {
186 struct siop_softc *sc = siop_cmd->siop_sc;
187 bus_addr_t offset;
188
189 offset = sc->sc_scriptdma->dm_segs[0].ds_addr - siop_cmd->dsa;
190 bus_dmamap_sync(sc->sc_dmat, sc->sc_scriptdma, offset,
191 sizeof(struct siop_xfer), ops);
192 }
193
194 static __inline__ void siop_script_sync __P((struct siop_softc *, int));
195 static __inline__ void
196 siop_script_sync(sc, ops)
197 struct siop_softc *sc;
198 int ops;
199 {
200 bus_dmamap_sync(sc->sc_dmat, sc->sc_scriptdma, 0, CMD_OFF, ops);
201 }
202
203 void
204 siop_attach(sc)
205 struct siop_softc *sc;
206 {
207 int error, i;
208 bus_dma_segment_t seg;
209 int rseg;
210
211 /*
212 * Allocate DMA-safe memory for the script itself and internal
213 * variables and map it.
214 */
215 error = bus_dmamem_alloc(sc->sc_dmat, MEM_SIZE,
216 NBPG, 0, &seg, 1, &rseg, BUS_DMA_NOWAIT);
217 if (error) {
218 printf("%s: unable to allocate script DMA memory, error = %d\n",
219 sc->sc_dev.dv_xname, error);
220 return;
221 }
222 error = bus_dmamem_map(sc->sc_dmat, &seg, rseg, MEM_SIZE,
223 (caddr_t *)&sc->sc_script, BUS_DMA_NOWAIT|BUS_DMA_COHERENT);
224 if (error) {
225 printf("%s: unable to map script DMA memory, error = %d\n",
226 sc->sc_dev.dv_xname, error);
227 return;
228 }
229 error = bus_dmamap_create(sc->sc_dmat, MEM_SIZE, 1,
230 MEM_SIZE, 0, BUS_DMA_NOWAIT, &sc->sc_scriptdma);
231 if (error) {
232 printf("%s: unable to create script DMA map, error = %d\n",
233 sc->sc_dev.dv_xname, error);
234 return;
235 }
236 error = bus_dmamap_load(sc->sc_dmat, sc->sc_scriptdma, sc->sc_script,
237 MEM_SIZE, NULL, BUS_DMA_NOWAIT);
238 if (error) {
239 printf("%s: unable to load script DMA map, error = %d\n",
240 sc->sc_dev.dv_xname, error);
241 return;
242 }
243 TAILQ_INIT(&sc->free_list);
244 for (i = 0; i < 16; i++)
245 TAILQ_INIT(&sc->active_list[i]);
246 /* allocate cmd list */
247 sc->cmds =
248 malloc(sizeof(struct siop_cmd) * SIOP_NCMD, M_DEVBUF, M_NOWAIT);
249 if (sc->cmds == NULL) {
250 printf("%s: can't allocate memory for command descriptors\n",
251 sc->sc_dev.dv_xname);
252 return;
253 }
254 for (i = 0; i < SIOP_NCMD; i++) {
255 error = bus_dmamap_create(sc->sc_dmat, MAXPHYS, SIOP_NSG,
256 MAXPHYS, 0, BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW,
257 &sc->cmds[i].dmamap_data);
258 if (error) {
259 printf("%s: unable to create data DMA map for cbd %d\n",
260 sc->sc_dev.dv_xname, error);
261 return;
262 }
263 error = bus_dmamap_create(sc->sc_dmat,
264 sizeof(struct scsipi_generic), 1,
265 sizeof(struct scsipi_generic), 0,
266 BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW,
267 &sc->cmds[i].dmamap_cmd);
268 if (error) {
269 printf("%s: unable to create cmd DMA map for cbd %d\n",
270 sc->sc_dev.dv_xname, error);
271 return;
272 }
273 sc->cmds[i].siop_sc = sc;
274 sc->cmds[i].siop_table =
275 &((struct siop_xfer *)(&sc->sc_script[CMD_OFF/4]))[i];
276 sc->cmds[i].dsa = sc->sc_scriptdma->dm_segs[0].ds_addr +
277 CMD_OFF + i * sizeof(struct siop_xfer);
278 sc->cmds[i].status = CMDST_FREE;
279 sc->cmds[i].siop_table->t_msgout.count= htole32(1);
280 sc->cmds[i].siop_table->t_msgout.addr =
281 htole32(sc->cmds[i].dsa);
282 sc->cmds[i].siop_table->t_msgin.count= htole32(1);
283 sc->cmds[i].siop_table->t_msgin.addr =
284 htole32(sc->cmds[i].dsa + 8);
285 sc->cmds[i].siop_table->t_extmsgin.count= htole32(2);
286 sc->cmds[i].siop_table->t_extmsgin.addr =
287 htole32(htole32(sc->cmds[i].siop_table->t_msgin.addr) + 1);
288 sc->cmds[i].siop_table->t_status.count= htole32(1);
289 sc->cmds[i].siop_table->t_status.addr =
290 htole32(htole32(sc->cmds[i].siop_table->t_msgin.addr) + 8);
291 TAILQ_INSERT_TAIL(&sc->free_list, &sc->cmds[i], next);
292 #ifdef DEBUG
293 printf("tables[%d]: out=0x%x in=0x%x status=0x%x\n", i,
294 sc->cmds[i].siop_table->t_msgin.addr,
295 sc->cmds[i].siop_table->t_msgout.addr,
296 sc->cmds[i].siop_table->t_status.addr);
297 #endif
298 }
299 /* compute number of sheduler slots */
300 sc->sc_nshedslots = (
301 CMD_OFF /* memory size allocated for scripts */
302 - sizeof(siop_script) /* memory for main script */
303 + 8 /* extra NOP at end of main script */
304 - sizeof(endslot_script) /* memory needed at end of sheduler */
305 ) / (sizeof(slot_script) - 8);
306 #ifdef DEBUG
307 printf("%s: script size = %d, PHY addr=0x%x, VIRT=%p nslots %d\n",
308 sc->sc_dev.dv_xname, (int)sizeof(siop_script),
309 (u_int)sc->sc_scriptdma->dm_segs[0].ds_addr, sc->sc_script,
310 sc->sc_nshedslots);
311 #endif
312
313 sc->sc_link.adapter_softc = sc;
314 sc->sc_link.openings = 1;
315 sc->sc_link.scsipi_scsi.channel = SCSI_CHANNEL_ONLY_ONE;
316 sc->sc_link.scsipi_scsi.max_target =
317 (sc->features & SF_BUS_WIDE) ? 15 : 7;
318 sc->sc_link.scsipi_scsi.max_lun = 7;
319 sc->sc_link.scsipi_scsi.adapter_target = bus_space_read_1(sc->sc_rt,
320 sc->sc_rh, SIOP_SCID);
321 if (sc->sc_link.scsipi_scsi.adapter_target == 0 ||
322 sc->sc_link.scsipi_scsi.adapter_target >
323 sc->sc_link.scsipi_scsi.max_target)
324 sc->sc_link.scsipi_scsi.adapter_target = SIOP_DEFAULT_TARGET;
325 sc->sc_link.type = BUS_SCSI;
326 sc->sc_link.adapter = &siop_adapter;
327 sc->sc_link.device = &siop_dev;
328 sc->sc_link.flags = 0;
329
330 siop_reset(sc);
331 #ifdef DUMP_SCRIPT
332 siop_dump_script(sc);
333 #endif
334
335 config_found((struct device*)sc, &sc->sc_link, scsiprint);
336 }
337
338 void
339 siop_reset(sc)
340 struct siop_softc *sc;
341 {
342 int i;
343 u_int32_t *scr;
344 bus_addr_t physaddr;
345 /* reset the chip */
346 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_ISTAT, ISTAT_SRST);
347 delay(1000);
348 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_ISTAT, 0);
349
350 /* copy and patch the script */
351 memcpy(sc->sc_script, siop_script, sizeof(siop_script));
352 /* copy the sheduler slots script */
353 for (i = 0; i < sc->sc_nshedslots; i++) {
354 scr = &sc->sc_script[Ent_sheduler / 4 + (Ent_nextslot / 4) * i];
355 physaddr = sc->sc_scriptdma->dm_segs[0].ds_addr + Ent_sheduler
356 + Ent_nextslot * i;
357 memcpy(scr, slot_script, sizeof(slot_script));
358 /*
359 * save current jump offset and patch MOVE MEMORY operands
360 * to restore it.
361 */
362 scr[Ent_slotdata/4 + 1] = scr[Ent_slot/4 + 1];
363 scr[E_slot_nextp_Used[0]] = htole32(physaddr + Ent_slot + 4);
364 scr[E_slot_shed_addrsrc_Used[0]] = htole32(physaddr +
365 Ent_slotdata + 4);
366 /* JUMP selected, in main script */
367 scr[E_slot_abs_selected_Used[0]] =
368 htole32(sc->sc_scriptdma->dm_segs[0].ds_addr + Ent_selected);
369 /* JUMP addr if SELECT fail */
370 scr[E_slot_abs_reselect_Used[0]] =
371 htole32(sc->sc_scriptdma->dm_segs[0].ds_addr + Ent_reselect);
372 }
373 /* Now the final JUMP */
374 scr = &sc->sc_script[Ent_sheduler / 4 +
375 (Ent_nextslot / 4) * sc->sc_nshedslots];
376 memcpy(scr, endslot_script, sizeof(endslot_script));
377 scr[E_endslot_abs_reselect_Used[0]] =
378 htole32(sc->sc_scriptdma->dm_segs[0].ds_addr + Ent_reselect);
379
380 /* init registers */
381 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL0,
382 SCNTL0_ARB_MASK | SCNTL0_EPC | SCNTL0_AAP);
383 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1, 0);
384 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL3, 0x3);
385 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_DIEN, 0xff);
386 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SIEN0,
387 0xff & ~(SIEN0_CMP | SIEN0_SEL | SIEN0_RSL));
388 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SIEN1,
389 0xff & ~(SIEN1_HTH | SIEN1_GEN));
390 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST2, STEST2_EXT);
391 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STEST3, STEST3_TE);
392 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_STIME0,
393 (0xb << STIME0_SEL_SHIFT));
394 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCID,
395 sc->sc_link.scsipi_scsi.adapter_target | SCID_RRE);
396 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_RESPID0,
397 1 << sc->sc_link.scsipi_scsi.adapter_target);
398 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_DCNTL, 0);
399
400 /* start script */
401 siop_script_sync(sc, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
402 bus_space_write_4(sc->sc_rt, sc->sc_rh, SIOP_DSP,
403 htole32(sc->sc_scriptdma->dm_segs[0].ds_addr + Ent_reselect));
404 }
405
406 #if 0
407 #define CALL_SCRIPT(ent) do {\
408 printf ("start script DSA 0x%lx DSP 0x%lx\n", \
409 htole32(siop_cmd->dsa), \
410 htole32(sc->sc_scriptdma->dm_segs[0].ds_addr + ent)); \
411 bus_space_write_4(sc->sc_rt, sc->sc_rh, SIOP_DSP, htole32(sc->sc_scriptdma->dm_segs[0].ds_addr + ent)); \
412 } while (0)
413 #else
414 #define CALL_SCRIPT(ent) do {\
415 bus_space_write_4(sc->sc_rt, sc->sc_rh, SIOP_DSP, htole32(sc->sc_scriptdma->dm_segs[0].ds_addr + ent)); \
416 } while (0)
417 #endif
418
419 int
420 siop_intr(v)
421 void *v;
422 {
423 struct siop_softc *sc = v;
424 struct siop_cmd *siop_cmd;
425 struct scsipi_xfer *xs;
426 u_int8_t istat, sist0, sist1, sstat1, dstat, scntl1;
427 u_int32_t irqcode;
428 int need_reset = 0;
429 int offset, target;
430 bus_addr_t dsa;
431
432 istat = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_ISTAT);
433 if ((istat & (ISTAT_INTF | ISTAT_DIP | ISTAT_SIP)) == 0)
434 return 0;
435 INCSTAT(siop_stat_intr);
436 if (istat & ISTAT_INTF) {
437 printf("INTRF\n");
438 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_ISTAT, ISTAT_INTF);
439 }
440 /* use DSA to find the current siop_cmd */
441 dsa = bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSA);
442 if (dsa >= sc->sc_scriptdma->dm_segs[0].ds_addr + CMD_OFF &&
443 dsa < sc->sc_scriptdma->dm_segs[0].ds_addr + CMD_OFF +
444 SIOP_NCMD * sizeof(struct siop_xfer)) {
445 dsa -= sc->sc_scriptdma->dm_segs[0].ds_addr + CMD_OFF;
446 siop_cmd = &sc->cmds[dsa / sizeof(struct siop_xfer)];
447 siop_table_sync(siop_cmd,
448 BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
449 } else {
450 printf("%s: current DSA invalid\n",
451 sc->sc_dev.dv_xname);
452 siop_cmd = NULL;
453 }
454 if (istat & ISTAT_DIP) {
455 u_int32_t *p;
456 dstat = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_DSTAT);
457 if (dstat & DSTAT_SSI) {
458 printf("single step dsp 0x%08x dsa 0x08%x\n",
459 bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSP),
460 bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSA));
461 if ((dstat & ~(DSTAT_DFE | DSTAT_SSI)) == 0 &&
462 (istat & ISTAT_SIP) == 0) {
463 bus_space_write_1(sc->sc_rt, sc->sc_rh,
464 SIOP_DCNTL, bus_space_read_1(sc->sc_rt,
465 sc->sc_rh, SIOP_DCNTL) | DCNTL_STD);
466 }
467 return 1;
468 }
469 if (dstat & ~(DSTAT_SIR | DSTAT_DFE | DSTAT_SSI)) {
470 printf("DMA IRQ:");
471 if (dstat & DSTAT_IID)
472 printf(" Illegal instruction");
473 if (dstat & DSTAT_ABRT)
474 printf(" abort");
475 if (dstat & DSTAT_BF)
476 printf(" bus fault");
477 if (dstat & DSTAT_MDPE)
478 printf(" parity");
479 if (dstat & DSTAT_DFE)
480 printf(" dma fifo empty");
481 printf(", DSP=0x%x DSA=0x%x: ",
482 bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSP),
483 bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSA));
484 p = sc->sc_script +
485 (bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSP) -
486 sc->sc_scriptdma->dm_segs[0].ds_addr - 8) / 4;
487 printf("0x%x 0x%x 0x%x 0x%x\n", p[0], p[1], p[2], p[3]);
488 if (siop_cmd)
489 printf("last msg_in=0x%x status=0x%x\n",
490 siop_cmd->siop_table->msg_in[0],
491 htole32(siop_cmd->siop_table->status));
492 need_reset = 1;
493 }
494 }
495 if (istat & ISTAT_SIP) {
496 /*
497 * SCSI interrupt. If current command is not active,
498 * we don't need siop_cmd
499 */
500 if (siop_cmd->status != CMDST_ACTIVE &&
501 siop_cmd->status != CMDST_SENSE_ACTIVE) {
502 siop_cmd = NULL;
503 }
504 if (istat & ISTAT_DIP)
505 delay(1);
506 sist0 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SIST0);
507 delay(1);
508 sist1 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SIST1);
509 sstat1 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SSTAT1);
510 #if 0
511 printf("scsi interrupt, sist0=0x%x sist1=0x%x sstat1=0x%x "
512 "DSA=0x%x DSP=0x%x\n", sist0, sist1,
513 bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SSTAT1),
514 bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSA),
515 bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSP));
516 #endif
517 if (siop_cmd)
518 xs = siop_cmd->xs;
519 if (sist0 & SIST0_RST) {
520 siop_handle_reset(sc);
521 siop_start(sc);
522 /* no table to flush here */
523 return 1;
524 }
525 if (sist0 & SIST0_SGE) {
526 if (siop_cmd)
527 scsi_print_addr(xs->sc_link);
528 else
529 printf("%s:", sc->sc_dev.dv_xname);
530 printf("scsi gross error\n");
531 goto reset;
532 }
533 if ((sist0 & SIST0_MA) && need_reset == 0) {
534 if (siop_cmd) {
535 switch (sstat1 & SSTAT1_PHASE_MASK) {
536 case SSTAT1_PHASE_STATUS:
537 /*
538 * previous phase may be aborted for any reason
539 * ( for example, the target has less data to
540 * transfer than requested). Just go to status
541 * and the command should terminate.
542 */
543 INCSTAT(siop_stat_intr_shortxfer);
544 CALL_SCRIPT(Ent_status);
545 /* no table to flush here */
546 return 1;
547 case SSTAT1_PHASE_MSGIN:
548 /*
549 * target may be ready to disconnect
550 * Save data pointers just in case.
551 */
552 INCSTAT(siop_stat_intr_xferdisc);
553 siop_sdp(siop_cmd);
554 siop_table_sync(siop_cmd,
555 BUS_DMASYNC_PREREAD |
556 BUS_DMASYNC_PREWRITE);
557 CALL_SCRIPT(Ent_msgin);
558 return 1;
559 }
560 printf("%s: unexpected phase mismatch %d\n",
561 sc->sc_dev.dv_xname,
562 sstat1 & SSTAT1_PHASE_MASK);
563 } else {
564 printf("%s: phase mismatch without command\n",
565 sc->sc_dev.dv_xname);
566 }
567 need_reset = 1;
568 }
569 if (sist0 & SIST0_PAR) {
570 /* parity error, reset */
571 if (siop_cmd)
572 scsi_print_addr(xs->sc_link);
573 else
574 printf("%s:", sc->sc_dev.dv_xname);
575 printf("parity error\n");
576 need_reset = 1;
577 }
578 if ((sist1 & SIST1_STO) && need_reset == 0) {
579 /* selection time out, assume there's no device here */
580 if (siop_cmd) {
581 siop_cmd->status = CMDST_DONE;
582 xs->error = XS_SELTIMEOUT;
583 goto end;
584 } else {
585 printf("%s: selection timeout without "
586 "command\n", sc->sc_dev.dv_xname);
587 need_reset = 1;
588 }
589 }
590 if (sist0 & SIST0_UDC) {
591 /*
592 * unexpected disconnect. Usually the target signals
593 * a fatal condition this way. Attempt to get sense.
594 */
595 if (siop_cmd)
596 goto check_sense;
597 printf("%s: unexpected disconnect without "
598 "command\n", sc->sc_dev.dv_xname);
599 goto reset;
600 }
601 /* Else it's an unhandled exeption (for now). */
602 printf("%s: unhandled scsi interrupt, sist0=0x%x sist1=0x%x "
603 "sstat1=0x%x DSA=0x%x DSP=0x%x\n", sc->sc_dev.dv_xname,
604 sist0, sist1,
605 bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SSTAT1),
606 bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSA),
607 bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSP));
608 if (siop_cmd) {
609 siop_cmd->status = CMDST_DONE;
610 xs->error = XS_SELTIMEOUT;
611 goto end;
612 }
613 need_reset = 1;
614 }
615 if (need_reset) {
616 reset:
617 /* fatal error, reset the bus */
618 scntl1 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1);
619 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1,
620 scntl1 | SCNTL1_RST);
621 /* minimum 25 us, more time won't hurt */
622 delay(100);
623 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1, scntl1);
624 /* no table to flush here */
625 return 1;
626 }
627
628
629 if ((istat & ISTAT_DIP) && (dstat & DSTAT_SIR)) { /* script interrupt */
630 irqcode = bus_space_read_4(sc->sc_rt, sc->sc_rh,
631 SIOP_DSPS);
632 #ifdef DEBUG_INTR
633 printf("script interrupt 0x%x\n", irqcode);
634 #endif
635 /*
636 * an inactive command is only valid if it's a reselect
637 * interrupt: we'll change siop_cmd to point to the rigth one
638 * just here
639 */
640 if (irqcode != A_int_resel &&
641 siop_cmd->status != CMDST_ACTIVE &&
642 siop_cmd->status != CMDST_SENSE_ACTIVE) {
643 printf("%s: Aie, no command (IRQ code 0x%x current "
644 "status %d) !\n", sc->sc_dev.dv_xname,
645 irqcode, siop_cmd->status);
646 xs = NULL;
647 } else
648 xs = siop_cmd->xs;
649 switch(irqcode) {
650 case A_int_err:
651 printf("error, DSP=0x%x\n",
652 bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DSP));
653 if (xs) {
654 xs->error = XS_SELTIMEOUT;
655 goto end;
656 } else {
657 goto reset;
658 }
659 case A_int_msgin:
660 if (xs)
661 scsi_print_addr(xs->sc_link);
662 else
663 printf("%s: ", sc->sc_dev.dv_xname);
664 if (siop_cmd->siop_table->msg_in[0] ==
665 MSG_MESSAGE_REJECT) {
666 printf("scsi message reject, message sent "
667 "was 0x%x\n",
668 siop_cmd->siop_table->msg_out[0]);
669 if (siop_cmd->siop_table->msg_out[0] ==
670 MSG_MESSAGE_REJECT) {
671 /* MSG_REJECT for a MSG_REJECT !*/
672 goto reset;
673 }
674 /* no table to flush here */
675 CALL_SCRIPT(Ent_msgin_ack);
676 return 1;
677 }
678 printf("unhandled message 0x%x\n",
679 siop_cmd->siop_table->msg_in[0]);
680 siop_cmd->siop_table->t_msgout.count= htole32(1);
681 siop_cmd->siop_table->t_msgout.addr =
682 htole32(siop_cmd->dsa);
683 siop_cmd->siop_table->msg_out[0] = MSG_MESSAGE_REJECT;
684 siop_table_sync(siop_cmd,
685 BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
686 CALL_SCRIPT(Ent_send_msgout);
687 return 1;
688 case A_int_extmsgin:
689 #ifdef DEBUG_INTR
690 printf("extended message: msg 0x%x len %d\n",
691 siop_cmd->siop_table->msg_in[2],
692 siop_cmd->siop_table->msg_in[1]);
693 #endif
694 siop_cmd->siop_table->t_extmsgdata.count =
695 htole32(siop_cmd->siop_table->msg_in[1] - 1);
696 siop_cmd->siop_table->t_extmsgdata.addr =
697 htole32(
698 htole32(siop_cmd->siop_table->t_extmsgin.addr)
699 + 2);
700 siop_table_sync(siop_cmd,
701 BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
702 CALL_SCRIPT(Ent_get_extmsgdata);
703 return 1;
704 case A_int_extmsgdata:
705 #ifdef DEBUG_INTR
706 {
707 int i;
708 printf("extended message: 0x%x, data:",
709 siop_cmd->siop_table->msg_in[2]);
710 for (i = 3; i < 2 + siop_cmd->siop_table->msg_in[1];
711 i++)
712 printf(" 0x%x",
713 siop_cmd->siop_table->msg_in[i]);
714 printf("\n");
715 }
716 #endif
717 if (siop_cmd->siop_table->msg_in[2] == MSG_EXT_SDTR) {
718 /* anserw with async for now */
719 siop_cmd->siop_table->msg_out[0] = MSG_EXTENDED;
720 siop_cmd->siop_table->msg_out[1] =
721 MSG_EXT_SDTR_LEN;
722 siop_cmd->siop_table->msg_out[2] = MSG_EXT_SDTR;
723 siop_cmd->siop_table->msg_out[3] = 0;
724 siop_cmd->siop_table->msg_out[4] = 0;
725 siop_cmd->siop_table->t_msgout.count =
726 htole32(MSG_EXT_SDTR_LEN + 2);
727 siop_cmd->siop_table->t_msgout.addr =
728 htole32(siop_cmd->dsa);
729 } else {
730 /* send a message reject */
731 siop_cmd->siop_table->t_msgout.count =
732 htole32(1);
733 siop_cmd->siop_table->t_msgout.addr =
734 htole32(siop_cmd->dsa);
735 siop_cmd->siop_table->msg_out[0] =
736 MSG_MESSAGE_REJECT;
737 }
738 siop_table_sync(siop_cmd,
739 BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
740 CALL_SCRIPT(Ent_send_msgout);
741 return 1;
742 case A_int_resel: /* reselected */
743 INCSTAT(siop_stat_intr_reselect);
744 if ((siop_cmd->siop_table->msg_in[0] & 0x80) == 0) {
745 printf("%s: reselect without identify (%d)\n",
746 sc->sc_dev.dv_xname,
747 siop_cmd->siop_table->msg_in[0]);
748 goto reset;
749 }
750 target = bus_space_read_1(sc->sc_rt,
751 sc->sc_rh, SIOP_SCRATCHA);
752 if ((target & 0x80) == 0) {
753 printf("reselect without id (%d)\n", target);
754 goto reset;
755 }
756 target &= 0x0f;
757 #ifdef DEBUG_DR
758 printf("reselected by target %d lun %d\n",
759 target,
760 siop_cmd->siop_table->msg_in[0] & 0x07);
761 #endif
762 siop_cmd =
763 sc->active_list[target].tqh_first;
764 if (siop_cmd == NULL) {
765 printf("%s: reselected without cmd\n",
766 sc->sc_dev.dv_xname);
767 goto reset;
768 }
769 bus_space_write_4(sc->sc_rt, sc->sc_rh, SIOP_DSA, \
770 htole32(siop_cmd->dsa));
771 /* no table to flush */
772 CALL_SCRIPT(Ent_selected);
773 return 1;
774 case A_int_disc:
775 INCSTAT(siop_stat_intr_sdp);
776 offset = bus_space_read_1(sc->sc_rt, sc->sc_rh,
777 SIOP_SCRATCHA + 1);
778 #ifdef DEBUG_DR
779 printf("disconnect offset %d\n", offset);
780 #endif
781 if (offset > SIOP_NSG) {
782 printf("%s: bad offset for disconnect (%d)\n",
783 sc->sc_dev.dv_xname, offset);
784 goto reset;
785 }
786 /*
787 * offset == SIOP_NSG may be a valid condition if
788 * we get a sdp when the xfer is done.
789 * Don't call memmove in this case.
790 */
791 if (offset < SIOP_NSG) {
792 memmove(&siop_cmd->siop_table->data[0],
793 &siop_cmd->siop_table->data[offset],
794 (SIOP_NSG - offset) * sizeof(scr_table_t));
795 siop_table_sync(siop_cmd,
796 BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
797 }
798 CALL_SCRIPT(Ent_sheduler);
799 return 1;
800 case A_int_resfail:
801 printf("reselect failed\n");
802 CALL_SCRIPT(Ent_sheduler);
803 return 1;
804 case A_int_done:
805 if (xs == NULL) {
806 printf("%s: done without command\n",
807 sc->sc_dev.dv_xname);
808 siop_cmd->status = 0;
809 CALL_SCRIPT(Ent_sheduler);
810 siop_start(sc);
811 return 1;
812 }
813 #if 0
814 printf("done, taget id 0x%x last msg in=0x%x "
815 "status=0x%x\n",
816 siop_cmd->siop_table->id,
817 siop_cmd->siop_table->msg_in[0],
818 htole32(siop_cmd->siop_table->status));
819 #endif
820 INCSTAT(siop_stat_intr_done);
821 if (siop_cmd->status == CMDST_SENSE_ACTIVE)
822 siop_cmd->status = CMDST_SENSE_DONE;
823 else
824 siop_cmd->status = CMDST_DONE;
825 switch(htole32(siop_cmd->siop_table->status)) {
826 case SCSI_OK:
827 xs->error = (siop_cmd->status == CMDST_DONE) ?
828 XS_NOERROR : XS_SENSE;
829 break;
830 case SCSI_BUSY:
831 xs->error = XS_BUSY;
832 break;
833 case SCSI_CHECK:
834 check_sense:
835 if (siop_cmd->status == CMDST_SENSE_DONE) {
836 /* request sense on a request sense ? */
837 printf("request sense failed\n");
838 xs->error = XS_DRIVER_STUFFUP;
839 } else {
840 siop_cmd->status = CMDST_SENSE;
841 }
842 break;
843 case 0xff:
844 /*
845 * the status byte was not updated, cmd was
846 * aborted
847 */
848 xs->error = XS_SELTIMEOUT;
849 break;
850 default:
851 xs->error = XS_DRIVER_STUFFUP;
852 }
853 goto end;
854 default:
855 printf("unknown irqcode %x\n", irqcode);
856 xs->error = XS_SELTIMEOUT;
857 goto end;
858 }
859 return 1;
860 }
861 /* We just should't get there */
862 panic("siop_intr: I shouldn't be there !");
863 return 1;
864 end:
865 siop_scsicmd_end(siop_cmd);
866 if (siop_cmd->status == CMDST_FREE) {
867 TAILQ_REMOVE(&sc->active_list[xs->sc_link->scsipi_scsi.target],
868 siop_cmd, next);
869 TAILQ_INSERT_TAIL(&sc->free_list, siop_cmd, next);
870 }
871 bus_space_write_4(sc->sc_rt, sc->sc_rh, SIOP_DSP,
872 htole32(sc->sc_scriptdma->dm_segs[0].ds_addr + Ent_reselect));
873 siop_start(sc);
874 return 1;
875 }
876
877 void
878 siop_scsicmd_end(siop_cmd)
879 struct siop_cmd *siop_cmd;
880 {
881 struct scsipi_xfer *xs = siop_cmd->xs;
882 struct siop_softc *sc = siop_cmd->siop_sc;
883
884 if (siop_cmd->status != CMDST_SENSE_DONE &&
885 xs->xs_control & (XS_CTL_DATA_IN | XS_CTL_DATA_OUT)) {
886 bus_dmamap_sync(sc->sc_dmat, siop_cmd->dmamap_data, 0,
887 siop_cmd->dmamap_data->dm_mapsize,
888 (xs->xs_control & XS_CTL_DATA_IN) ?
889 BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
890 bus_dmamap_unload(sc->sc_dmat, siop_cmd->dmamap_data);
891 }
892 bus_dmamap_unload(sc->sc_dmat, siop_cmd->dmamap_cmd);
893 if (siop_cmd->status == CMDST_SENSE) {
894 /* issue a request sense for this target */
895 int error, i;
896 siop_cmd->rs_cmd.opcode = REQUEST_SENSE;
897 siop_cmd->rs_cmd.byte2 = xs->sc_link->scsipi_scsi.lun << 5;
898 siop_cmd->rs_cmd.unused[0] = siop_cmd->rs_cmd.unused[1] = 0;
899 siop_cmd->rs_cmd.length = sizeof(struct scsipi_sense_data);
900 siop_cmd->rs_cmd.control = 0;
901 siop_cmd->siop_table->status = htole32(0xff); /*invalid status*/
902 siop_cmd->siop_table->t_msgout.count= htole32(1);
903 siop_cmd->siop_table->t_msgout.addr = htole32(siop_cmd->dsa);
904 siop_cmd->siop_table->msg_out[0] =
905 MSG_IDENTIFY(xs->sc_link->scsipi_scsi.lun, 1);
906 error = bus_dmamap_load(sc->sc_dmat, siop_cmd->dmamap_cmd,
907 &siop_cmd->rs_cmd, sizeof(struct scsipi_sense),
908 NULL, BUS_DMA_NOWAIT);
909 if (error) {
910 printf("%s: unable to load cmd DMA map: %d",
911 sc->sc_dev.dv_xname, error);
912 xs->error = XS_DRIVER_STUFFUP;
913 goto out;
914 }
915 siop_cmd->siop_table->cmd.count =
916 htole32(siop_cmd->dmamap_cmd->dm_segs[0].ds_len);
917 siop_cmd->siop_table->cmd.addr =
918 htole32(siop_cmd->dmamap_cmd->dm_segs[0].ds_addr);
919 error = bus_dmamap_load(sc->sc_dmat, siop_cmd->dmamap_data,
920 &xs->sense.scsi_sense, sizeof(struct scsipi_sense_data),
921 NULL, BUS_DMA_NOWAIT);
922 if (error) {
923 printf("%s: unable to load sense DMA map: %d",
924 sc->sc_dev.dv_xname, error);
925 xs->error = XS_DRIVER_STUFFUP;
926 bus_dmamap_unload(sc->sc_dmat, siop_cmd->dmamap_cmd);
927 goto out;
928 }
929 for (i = 0; i < siop_cmd->dmamap_data->dm_nsegs; i++) {
930 siop_cmd->siop_table->data[i].count =
931 htole32(siop_cmd->dmamap_data->dm_segs[i].ds_len);
932 siop_cmd->siop_table->data[i].addr =
933 htole32(siop_cmd->dmamap_data->dm_segs[i].ds_addr);
934 }
935 bus_dmamap_sync(sc->sc_dmat, siop_cmd->dmamap_data, 0,
936 siop_cmd->dmamap_data->dm_mapsize, BUS_DMASYNC_PREREAD);
937 bus_dmamap_sync(sc->sc_dmat, siop_cmd->dmamap_cmd, 0,
938 siop_cmd->dmamap_cmd->dm_mapsize, BUS_DMASYNC_PREWRITE);
939 siop_table_sync(siop_cmd, BUS_DMASYNC_PREWRITE);
940 #if 0
941 bus_dmamap_sync(sc->sc_dmat, sc->sc_scriptdma, CMD_OFF,
942 sc->sc_scriptdma->dm_mapsize - CMD_OFF,
943 BUS_DMASYNC_PREWRITE);
944 #endif
945 return;
946 } else if (siop_cmd->status == CMDST_SENSE_DONE) {
947 bus_dmamap_sync(sc->sc_dmat, siop_cmd->dmamap_data, 0,
948 siop_cmd->dmamap_data->dm_mapsize, BUS_DMASYNC_POSTREAD);
949 bus_dmamap_unload(sc->sc_dmat, siop_cmd->dmamap_data);
950 }
951 out:
952 callout_stop(&siop_cmd->xs->xs_callout);
953 siop_cmd->status = CMDST_FREE;
954 xs->xs_status |= XS_STS_DONE;
955 xs->resid = 0;
956 scsipi_done (xs);
957 }
958
959 /*
960 * handle a bus reset: reset chip, unqueue all active commands and report
961 * loosage to upper layer.
962 * As the upper layer may requeue immediatly we have to first store
963 * all active commands in a temporary queue.
964 */
965 void
966 siop_handle_reset(sc)
967 struct siop_softc *sc;
968 {
969 struct cmd_list reset_list;
970 struct siop_cmd *siop_cmd, *next_siop_cmd;
971 int target;
972 /*
973 * scsi bus reset. reset the chip and restart
974 * the queue. Need to clean up all active commands
975 */
976 printf("%s: scsi bus reset\n", sc->sc_dev.dv_xname);
977 /* stop, reset and restart the chip */
978 siop_reset(sc);
979 TAILQ_INIT(&reset_list);
980 /* find all active commands */
981 for (target = 0; target < 16; target++) {
982 for (siop_cmd = TAILQ_FIRST(&sc->active_list[target]);
983 siop_cmd != NULL; siop_cmd = next_siop_cmd) {
984 next_siop_cmd = TAILQ_NEXT(siop_cmd, next);
985 if (siop_cmd->status < CMDST_ACTIVE)
986 continue;
987 printf("cmd %p (target %d) in reset list\n", siop_cmd,
988 target);
989 TAILQ_REMOVE( &sc->active_list[target], siop_cmd, next);
990 TAILQ_INSERT_TAIL(&reset_list, siop_cmd, next);
991 }
992 }
993 for (siop_cmd = TAILQ_FIRST(&reset_list); siop_cmd != NULL;
994 siop_cmd = next_siop_cmd) {
995 next_siop_cmd = TAILQ_NEXT(siop_cmd, next);
996 siop_cmd->xs->error = (siop_cmd->flags & CMDFL_TIMEOUT) ?
997 XS_TIMEOUT : XS_RESET;
998 printf("cmd %p about to be processed\n", siop_cmd);
999 TAILQ_REMOVE(&reset_list, siop_cmd, next);
1000 siop_scsicmd_end(siop_cmd);
1001 TAILQ_INSERT_TAIL(&sc->free_list, siop_cmd, next);
1002 }
1003 }
1004
1005 void
1006 siop_minphys(bp)
1007 struct buf *bp;
1008 {
1009 minphys(bp);
1010 }
1011
1012 int
1013 siop_ioctl(link, cmd, arg, flag, p)
1014 struct scsipi_link *link;
1015 u_long cmd;
1016 caddr_t arg;
1017 int flag;
1018 struct proc *p;
1019 {
1020 struct siop_softc *sc = link->adapter_softc;
1021 u_int8_t scntl1;
1022 int s;
1023
1024 switch (cmd) {
1025 case SCBUSIORESET:
1026 s = splbio();
1027 scntl1 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1);
1028 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1,
1029 scntl1 | SCNTL1_RST);
1030 /* minimum 25 us, more time won't hurt */
1031 delay(100);
1032 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1, scntl1);
1033 splx(s);
1034 return (0);
1035 default:
1036 return (ENOTTY);
1037 }
1038 }
1039
1040 int
1041 siop_scsicmd(xs)
1042 struct scsipi_xfer *xs;
1043 {
1044 struct siop_softc *sc = (struct siop_softc *)xs->sc_link->adapter_softc;
1045 struct siop_cmd *siop_cmd;
1046 int s, error, i;
1047 u_int32_t id;
1048
1049 s = splbio();
1050 #if 0
1051 printf("starting cmd for %d:%d\n", xs->sc_link->scsipi_scsi.target,xs->sc_link->scsipi_scsi.lun);
1052 #endif
1053 siop_cmd = sc->free_list.tqh_first;
1054 if (siop_cmd) {
1055 TAILQ_REMOVE(&sc->free_list, siop_cmd, next);
1056 }
1057 splx(s);
1058 if (siop_cmd == NULL) {
1059 xs->error = XS_DRIVER_STUFFUP;
1060 return(TRY_AGAIN_LATER);
1061 }
1062 #ifdef DIAGNOSTIC
1063 if (siop_cmd->status != CMDST_FREE)
1064 panic("siop_scsicmd: new cmd not free");
1065 #endif
1066 siop_cmd->xs = xs;
1067 id = 0x3 << 24; /* scntl3 */
1068 id |= xs->sc_link->scsipi_scsi.target << 16; /* id */
1069 id |= 0xe0 << 8; /* scxfer */
1070 siop_cmd->siop_table->id = htole32(id);
1071 siop_cmd->siop_table->t_msgout.count= htole32(1);
1072 siop_cmd->siop_table->t_msgout.addr = htole32(siop_cmd->dsa);
1073 siop_cmd->siop_table->msg_out[0] =
1074 MSG_IDENTIFY(xs->sc_link->scsipi_scsi.lun, 1);
1075 siop_cmd->siop_table->status = htole32(0xff); /* set invalid status */
1076
1077 /* load the DMA maps */
1078 error = bus_dmamap_load(sc->sc_dmat, siop_cmd->dmamap_cmd,
1079 xs->cmd, xs->cmdlen, NULL, BUS_DMA_NOWAIT);
1080 if (error) {
1081 printf("%s: unable to load cmd DMA map: %d",
1082 sc->sc_dev.dv_xname, error);
1083 xs->error = XS_DRIVER_STUFFUP;
1084 return(TRY_AGAIN_LATER);
1085 }
1086 siop_cmd->siop_table->cmd.count =
1087 htole32(siop_cmd->dmamap_cmd->dm_segs[0].ds_len);
1088 siop_cmd->siop_table->cmd.addr =
1089 htole32(siop_cmd->dmamap_cmd->dm_segs[0].ds_addr);
1090 if (xs->xs_control & (XS_CTL_DATA_IN | XS_CTL_DATA_OUT)) {
1091 error = bus_dmamap_load(sc->sc_dmat, siop_cmd->dmamap_data,
1092 xs->data, xs->datalen, NULL, BUS_DMA_NOWAIT);
1093 if (error) {
1094 printf("%s: unable to load cmd DMA map: %d",
1095 sc->sc_dev.dv_xname, error);
1096 xs->error = XS_DRIVER_STUFFUP;
1097 return(TRY_AGAIN_LATER);
1098 bus_dmamap_unload(sc->sc_dmat, siop_cmd->dmamap_cmd);
1099 }
1100 for (i = 0; i < siop_cmd->dmamap_data->dm_nsegs; i++) {
1101 siop_cmd->siop_table->data[i].count =
1102 htole32(siop_cmd->dmamap_data->dm_segs[i].ds_len);
1103 siop_cmd->siop_table->data[i].addr =
1104 htole32(siop_cmd->dmamap_data->dm_segs[i].ds_addr);
1105 }
1106 bus_dmamap_sync(sc->sc_dmat, siop_cmd->dmamap_data, 0,
1107 siop_cmd->dmamap_data->dm_mapsize,
1108 (xs->xs_control & XS_CTL_DATA_IN) ?
1109 BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE);
1110 }
1111 bus_dmamap_sync(sc->sc_dmat, siop_cmd->dmamap_cmd, 0,
1112 siop_cmd->dmamap_cmd->dm_mapsize, BUS_DMASYNC_PREWRITE);
1113 siop_table_sync(siop_cmd, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1114 #if 0
1115 bus_dmamap_sync(sc->sc_dmat, sc->sc_scriptdma, 0,
1116 sc->sc_scriptdma->dm_mapsize, BUS_DMASYNC_PREWRITE);
1117 #endif
1118
1119 siop_cmd->status = CMDST_READY;
1120 s = splbio();
1121 TAILQ_INSERT_TAIL(&sc->active_list[xs->sc_link->scsipi_scsi.target],
1122 siop_cmd, next);
1123 siop_start(sc);
1124 splx(s);
1125 return (SUCCESSFULLY_QUEUED);
1126 }
1127
1128 void
1129 siop_start(sc)
1130 struct siop_softc *sc;
1131 {
1132 struct siop_cmd *siop_cmd;
1133 u_int32_t *scr;
1134 u_int32_t dsa;
1135 u_int8_t *dsap = (u_int8_t *)&dsa;
1136 int timeout;
1137 int target, slot;
1138 int newcmd = 0;
1139
1140 /*
1141 * first make sure to read valid data
1142 */
1143 siop_script_sync(sc, BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
1144
1145 /*
1146 * no need to restart at slot 0 each time we're looking for a free
1147 * slot; init slot before the target loop.
1148 */
1149 slot = 0;
1150 for (target = 0; target < 16; target++) {
1151 siop_cmd = sc->active_list[target].tqh_first;
1152 if (siop_cmd == NULL)
1153 continue;
1154 if (siop_cmd->status != CMDST_READY &&
1155 siop_cmd->status != CMDST_SENSE)
1156 continue;
1157 /* mark command as active (if not reqsense) and start script */
1158 if (siop_cmd->status == CMDST_READY)
1159 siop_cmd->status = CMDST_ACTIVE;
1160 else if (siop_cmd->status == CMDST_SENSE)
1161 siop_cmd->status = CMDST_SENSE_ACTIVE;
1162 else
1163 panic("siop_start: bad status");
1164 /* find a free sheduler slot and load it */
1165 for (; slot < sc->sc_nshedslots; slot++) {
1166 scr = &sc->sc_script[Ent_sheduler / 4 +
1167 (Ent_nextslot / 4) * slot];
1168 /*
1169 * if relative addr of first jump is 0 the slot isn't
1170 * free
1171 */
1172 if (scr[Ent_slot / 4 + 1] == 0)
1173 continue;
1174 #ifdef DEBUG_SHED
1175 printf("using slot %d\n", slot);
1176 #endif
1177 /* record that we started at last one new comand */
1178 newcmd = 1;
1179 /* ok, patch script with DSA addr */
1180 dsa = siop_cmd->dsa;
1181 /*
1182 * 0x78000000 is a 'move data8 to reg'. data8 is the
1183 * second octet, reg offset is the third.
1184 */
1185 scr[Ent_idsa0 / 4] =
1186 htole32(0x78100000 | (dsap[0] << 8));
1187 scr[Ent_idsa1 / 4] =
1188 htole32(0x78110000 | (dsap[1] << 8));
1189 scr[Ent_idsa2 / 4] =
1190 htole32(0x78120000 | (dsap[2] << 8));
1191 scr[Ent_idsa3 / 4] =
1192 htole32(0x78130000 | (dsap[3] << 8));
1193 /* change status of cmd */
1194 if (siop_cmd->status == CMDST_ACTIVE) {
1195 if ((siop_cmd->xs->xs_control & XS_CTL_POLL)
1196 == 0) {
1197 /* start exire timer */
1198 timeout =
1199 siop_cmd->xs->timeout * hz / 1000;
1200 if (timeout == 0)
1201 timeout = 1;
1202 callout_reset(&siop_cmd->xs->xs_callout,
1203 timeout, siop_timeout, siop_cmd);
1204 }
1205 }
1206 /*
1207 * Change jump offset so that this slot will be
1208 * handled
1209 */
1210 scr[Ent_slot / 4 + 1] = 0;
1211 break;
1212 }
1213 /* if we didn't find any free slot no need to try next target */
1214 if (slot == sc->sc_nshedslots)
1215 break;
1216 }
1217 /* if nothing changed no need to flush cache and wakeup script */
1218 if (newcmd == 0)
1219 return;
1220 /* make sure SCRIPT processor will read valid data */
1221 siop_script_sync(sc, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1222 /* Signal script it has some work to do */
1223 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_ISTAT, ISTAT_SIGP);
1224 /* and wait for IRQ */
1225 return;
1226 }
1227
1228 void
1229 siop_timeout(v)
1230 void *v;
1231 {
1232 struct siop_cmd *siop_cmd = v;
1233 struct siop_softc *sc = siop_cmd->siop_sc;
1234 int s;
1235 u_int8_t scntl1;
1236
1237 scsi_print_addr(siop_cmd->xs->sc_link);
1238 printf("command timeout\n");
1239
1240 s = splbio();
1241 /* reset the scsi bus */
1242 scntl1 = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1);
1243 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1,
1244 scntl1 | SCNTL1_RST);
1245 /* minimum 25 us, more time won't hurt */
1246 delay(100);
1247 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_SCNTL1, scntl1);
1248
1249 /* desactivate callout */
1250 callout_stop(&siop_cmd->xs->xs_callout);
1251 /* mark command has being timed out; siop_intr will handle it */
1252 /*
1253 * mark command has being timed out and just return;
1254 * the bus reset will generate an interrupt,
1255 * it will be handled in siop_intr()
1256 */
1257 siop_cmd->flags |= CMDFL_TIMEOUT;
1258 splx(s);
1259 return;
1260
1261 }
1262
1263 void
1264 siop_sdp(siop_cmd)
1265 struct siop_cmd *siop_cmd;
1266 {
1267 /* save data pointer. Handle async only for now */
1268 int offset, dbc, sstat;
1269 struct siop_softc *sc = siop_cmd->siop_sc;
1270 scr_table_t *table; /* table to patch */
1271
1272 if ((siop_cmd->xs->xs_control & (XS_CTL_DATA_OUT | XS_CTL_DATA_IN))
1273 == 0)
1274 return; /* no data pointers to save */
1275 offset = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SCRATCHA + 1);
1276 if (offset >= SIOP_NSG) {
1277 printf("%s: bad offset in siop_sdp (%d)\n",
1278 sc->sc_dev.dv_xname, offset);
1279 return;
1280 }
1281 table = &siop_cmd->siop_table->data[offset];
1282 #ifdef DEBUG_DR
1283 printf("sdp: offset %d count=%d addr=0x%x ", offset,
1284 table->count, table->addr);
1285 #endif
1286 dbc = bus_space_read_4(sc->sc_rt, sc->sc_rh, SIOP_DBC) & 0x00ffffff;
1287 if (siop_cmd->xs->xs_control & XS_CTL_DATA_OUT) {
1288 /* need to account stale data in FIFO */
1289 /* XXX check for large fifo */
1290 dbc += (bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_DFIFO) -
1291 (dbc & 0x7f)) & 0x7f;
1292 sstat = bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_SSTAT0);
1293 if (sstat & SSTAT0_OLF)
1294 dbc++;
1295 if (sstat & SSTAT0_ORF)
1296 dbc++;
1297 /* XXX check sstat1 for wide adapters */
1298 /* Flush the FIFO */
1299 bus_space_write_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3,
1300 bus_space_read_1(sc->sc_rt, sc->sc_rh, SIOP_CTEST3) |
1301 CTEST3_CLF);
1302 }
1303 table->addr =
1304 htole32(htole32(table->addr) + htole32(table->count) - dbc);
1305 table->count = htole32(dbc);
1306 #ifdef DEBUG_DR
1307 printf("now count=%d addr=0x%x\n", table->count, table->addr);
1308 #endif
1309 }
1310
1311 void
1312 siop_dump_script(sc)
1313 struct siop_softc *sc;
1314 {
1315 int i;
1316 siop_script_sync(sc, BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
1317 for (i = 0; i < CMD_OFF / 4; i += 2) {
1318 printf("0x%04x: 0x%08x 0x%08x", i * 4, sc->sc_script[i],
1319 sc->sc_script[i+1]);
1320 if ((sc->sc_script[i] & 0xe0000000) == 0xc0000000) {
1321 i++;
1322 printf(" 0x%08x", sc->sc_script[i+1]);
1323 }
1324 printf("\n");
1325 }
1326 }
1327
1328 #ifdef SIOP_STATS
1329 void
1330 siop_printstats()
1331 {
1332 printf("siop_stat_intr %d\n", siop_stat_intr);
1333 printf("siop_stat_intr_shortxfer %d\n", siop_stat_intr_shortxfer);
1334 printf("siop_stat_intr_xferdisc %d\n", siop_stat_intr_xferdisc);
1335 printf("siop_stat_intr_sdp %d\n", siop_stat_intr_sdp);
1336 printf("siop_stat_intr_reselect %d\n", siop_stat_intr_reselect);
1337 printf("siop_stat_intr_done %d\n", siop_stat_intr_done);
1338 }
1339 #endif
1340