siop.c revision 1.4 1 /*
2 * Copyright (c) 1990 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Van Jacobson of Lawrence Berkeley Laboratory.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by the University of
19 * California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 *
36 * @(#)siop.c 7.5 (Berkeley) 5/4/91
37 * $Id: siop.c,v 1.4 1994/02/13 21:11:03 chopps Exp $
38 *
39 * MULTICONTROLLER support only working for multiple controllers of the
40 * same kind at the moment !!
41 *
42 */
43
44 /*
45 * AMIGA 53C710 scsi adaptor driver
46 */
47
48 #include "zeusscsi.h"
49 #include "magnumscsi.h"
50 #define NSIOP (NZEUSSCSI + NMAGNUMSCSI)
51 #if NSIOP > 0
52
53 #ifndef lint
54 static char rcsid[] = "$Header: /tank/opengrok/rsync2/NetBSD/src/sys/arch/amiga/dev/siop.c,v 1.4 1994/02/13 21:11:03 chopps Exp $";
55 #endif
56
57 /* need to know if any tapes have been configured */
58 #include "st.h"
59
60 #include <sys/param.h>
61 #include <sys/systm.h>
62 #include <sys/buf.h>
63 #include <amiga/dev/device.h>
64
65 #include <amiga/dev/scsidefs.h>
66 #include <amiga/dev/siopvar.h>
67 #include <amiga/dev/siopreg.h>
68
69 #include <amiga/amiga/custom.h>
70
71 #include <machine/cpu.h>
72
73 extern u_int kvtop();
74
75 /*
76 * SCSI delays
77 * In u-seconds, primarily for state changes on the SPC.
78 */
79 #define SCSI_CMD_WAIT 50000 /* wait per step of 'immediate' cmds */
80 #define SCSI_DATA_WAIT 50000 /* wait per data in/out step */
81 #define SCSI_INIT_WAIT 50000 /* wait per step (both) during init */
82
83 void siopstart (int unit);
84 int siopgo (int ctlr, int slave, int unit, struct buf *bp, struct scsi_fmt_cdb *cdb, int pad);
85 int siopintr2 (void);
86 void siopdone (int unit);
87 int siopustart (int unit);
88 int siopreq (register struct devqueue *dq);
89 void siopfree (register struct devqueue *dq);
90 void siopreset (int unit);
91 void siop_delay (int delay);
92 int siop_test_unit_rdy (int ctlr, int slave, int unit);
93 int siop_start_stop_unit (int ctlr, int slave, int unit, int start);
94 int siop_request_sense (int ctlr, int slave, int unit, u_char *buf, unsigned int len);
95 int siop_immed_command (int ctlr, int slave, int unit, struct scsi_fmt_cdb *cdb, u_char *buf, unsigned int len, int rd);
96 int siop_tt_read (int ctlr, int slave, int unit, u_char *buf, u_int len, daddr_t blk, int bshift);
97 int siop_tt_write (int ctlr, int slave, int unit, u_char *buf, u_int len, daddr_t blk, int bshift);
98 #if NST > 0
99 int siop_tt_oddio (int ctlr, int slave, int unit, u_char *buf, u_int len, int b_flags, int freedma);
100 #endif
101
102 #if NZEUSSCSI > 0
103 int zeusscsiinit();
104
105 struct driver zeusscsidriver = {
106 zeusscsiinit, "Zeusscsi", (int (*)())siopstart, (int (*)())siopgo,
107 (int (*)())siopintr2, (int (*)())siopdone,
108 siopustart, siopreq, siopfree, siopreset,
109 siop_delay, siop_test_unit_rdy, siop_start_stop_unit,
110 siop_request_sense, siop_immed_command, siop_tt_read, siop_tt_write,
111 #if NST > 0
112 siop_tt_oddio
113 #else
114 0
115 #endif
116 };
117 #endif
118
119 #if NMAGNUMSCSI > 0
120 int magnumscsiinit();
121
122 struct driver magnumscsidriver = {
123 magnumscsiinit, "Magnumscsi", (int (*)())siopstart, (int (*)())siopgo,
124 (int (*)())siopintr2, (int (*)())siopdone,
125 siopustart, siopreq, siopfree, siopreset,
126 siop_delay, siop_test_unit_rdy, siop_start_stop_unit,
127 siop_request_sense, siop_immed_command, siop_tt_read, siop_tt_write,
128 #if NST > 0
129 siop_tt_oddio
130 #else
131 0
132 #endif
133 };
134 #endif
135
136 /* 53C710 script */
137 unsigned long scripts[] = {
138 0x47000000, 0x00000298, /* 000 - 0 */
139 0x838b0000, 0x000000d0, /* 008 - 8 */
140 0x7a1b1000, 0x00000000, /* 010 - 16 */
141 0x828a0000, 0x00000088, /* 018 - 24 */
142 0x9e020000, 0x0000ff01, /* 020 - 32 */
143 0x72350000, 0x00000000, /* 028 - 40 */
144 0x808c0000, 0x00000048, /* 030 - 48 */
145 0x58000008, 0x00000000, /* 038 - 56 */
146 0x1e000024, 0x00000024, /* 040 - 64 */
147 0x838b0000, 0x00000090, /* 048 - 72 */
148 0x1f00002c, 0x0000002c, /* 050 - 80 */
149 0x838b0000, 0x00000080, /* 058 - 88 */
150 0x868a0000, 0xffffffd0, /* 060 - 96 */
151 0x838a0000, 0x00000070, /* 068 - 104 */
152 0x878a0000, 0x00000120, /* 070 - 112 */
153 0x80880000, 0x00000028, /* 078 - 120 */
154 0x1e000004, 0x00000004, /* 080 - 128 */
155 0x838b0000, 0x00000050, /* 088 - 136 */
156 0x868a0000, 0xffffffe8, /* 090 - 144 */
157 0x838a0000, 0x00000040, /* 098 - 152 */
158 0x878a0000, 0x000000f0, /* 0a0 - 160 */
159 0x9a020000, 0x0000ff02, /* 0a8 - 168 */
160 0x1a00000c, 0x0000000c, /* 0b0 - 176 */
161 0x878b0000, 0x00000130, /* 0b8 - 184 */
162 0x838a0000, 0x00000018, /* 0c0 - 192 */
163 0x818a0000, 0x000000b0, /* 0c8 - 200 */
164 0x808a0000, 0x00000080, /* 0d0 - 208 */
165 0x98080000, 0x0000ff03, /* 0d8 - 216 */
166 0x1b000014, 0x00000014, /* 0e0 - 224 */
167 0x72090000, 0x00000000, /* 0e8 - 232 */
168 0x6a340000, 0x00000000, /* 0f0 - 240 */
169 0x9f030000, 0x0000ff04, /* 0f8 - 248 */
170 0x1f00001c, 0x0000001c, /* 100 - 256 */
171 0x98040000, 0x0000ff26, /* 108 - 264 */
172 0x60000040, 0x00000000, /* 110 - 272 */
173 0x48000000, 0x00000000, /* 118 - 280 */
174 0x7c1bef00, 0x00000000, /* 120 - 288 */
175 0x72340000, 0x00000000, /* 128 - 296 */
176 0x980c0002, 0x0000fffc, /* 130 - 304 */
177 0x980c0008, 0x0000fffb, /* 138 - 312 */
178 0x980c0018, 0x0000fffd, /* 140 - 320 */
179 0x98040000, 0x0000fffe, /* 148 - 328 */
180 0x98080000, 0x0000ff00, /* 150 - 336 */
181 0x18000034, 0x00000034, /* 158 - 344 */
182 0x808b0000, 0x000001c0, /* 160 - 352 */
183 0x838b0000, 0xffffff70, /* 168 - 360 */
184 0x878a0000, 0x000000d0, /* 170 - 368 */
185 0x98080000, 0x0000ff05, /* 178 - 376 */
186 0x19000034, 0x00000034, /* 180 - 384 */
187 0x818b0000, 0x00000160, /* 188 - 392 */
188 0x80880000, 0xffffffd0, /* 190 - 400 */
189 0x1f00001c, 0x0000001c, /* 198 - 408 */
190 0x808c0001, 0x00000018, /* 1a0 - 416 */
191 0x980c0002, 0x0000ff08, /* 1a8 - 424 */
192 0x808c0004, 0x00000020, /* 1b0 - 432 */
193 0x98080000, 0x0000ff06, /* 1b8 - 440 */
194 0x60000040, 0x00000000, /* 1c0 - 448 */
195 0x1f00002c, 0x0000002c, /* 1c8 - 456 */
196 0x98080000, 0x0000ff07, /* 1d0 - 464 */
197 0x60000040, 0x00000000, /* 1d8 - 472 */
198 0x48000000, 0x00000000, /* 1e0 - 480 */
199 0x98080000, 0x0000ff09, /* 1e8 - 488 */
200 0x1f00001c, 0x0000001c, /* 1f0 - 496 */
201 0x808c0001, 0x00000018, /* 1f8 - 504 */
202 0x980c0002, 0x0000ff10, /* 200 - 512 */
203 0x808c0004, 0x00000020, /* 208 - 520 */
204 0x98080000, 0x0000ff11, /* 210 - 528 */
205 0x60000040, 0x00000000, /* 218 - 536 */
206 0x1f00002c, 0x0000002c, /* 220 - 544 */
207 0x98080000, 0x0000ff12, /* 228 - 552 */
208 0x60000040, 0x00000000, /* 230 - 560 */
209 0x48000000, 0x00000000, /* 238 - 568 */
210 0x98080000, 0x0000ff13, /* 240 - 576 */
211 0x1f00001c, 0x0000001c, /* 248 - 584 */
212 0x808c0001, 0x00000018, /* 250 - 592 */
213 0x980c0002, 0x0000ff14, /* 258 - 600 */
214 0x808c0004, 0x00000020, /* 260 - 608 */
215 0x98080000, 0x0000ff15, /* 268 - 616 */
216 0x60000040, 0x00000000, /* 270 - 624 */
217 0x1f00002c, 0x0000002c, /* 278 - 632 */
218 0x98080000, 0x0000ff16, /* 280 - 640 */
219 0x60000040, 0x00000000, /* 288 - 648 */
220 0x48000000, 0x00000000, /* 290 - 656 */
221 0x98080000, 0x0000ff17, /* 298 - 664 */
222 0x54000000, 0x00000040, /* 2a0 - 672 */
223 0x9f030000, 0x0000ff18, /* 2a8 - 680 */
224 0x1f00001c, 0x0000001c, /* 2b0 - 688 */
225 0x990b0000, 0x0000ff19, /* 2b8 - 696 */
226 0x980a0000, 0x0000ff20, /* 2c0 - 704 */
227 0x9f0a0000, 0x0000ff21, /* 2c8 - 712 */
228 0x9b0a0000, 0x0000ff22, /* 2d0 - 720 */
229 0x9e0a0000, 0x0000ff23, /* 2d8 - 728 */
230 0x98080000, 0x0000ff24, /* 2e0 - 736 */
231 0x98080000, 0x0000ff25, /* 2e8 - 744 */
232 0x76100800, 0x00000000, /* 2f0 - 752 */
233 0x80840700, 0x00000008, /* 2f8 - 760 */
234 0x7e110100, 0x00000000, /* 300 - 768 */
235 0x6a100000, 0x00000000, /* 308 - 776 */
236 0x19000034, 0x00000034, /* 310 - 784 */
237 0x818b0000, 0xffffffd0, /* 318 - 792 */
238 0x98080000, 0x0000ff27, /* 320 - 800 */
239 0x76100800, 0x00000000, /* 328 - 808 */
240 0x80840700, 0x00000008, /* 330 - 816 */
241 0x7e110100, 0x00000000, /* 338 - 824 */
242 0x6a100000, 0x00000000, /* 340 - 832 */
243 0x18000034, 0x00000034, /* 348 - 840 */
244 0x808b0000, 0xffffffd0, /* 350 - 848 */
245 0x98080000, 0x0000ff27 /* 358 - 856 */
246 };
247
248 #define Ent_msgout 0x00000018
249 #define Ent_cmd 0x000000a8
250 #define Ent_status 0x000000e0
251 #define Ent_msgin 0x000000f8
252 #define Ent_dataout 0x00000158
253 #define Ent_datain 0x00000180
254
255 struct siop_softc siop_softc[NSIOP];
256
257 int siop_cmd_wait = SCSI_CMD_WAIT;
258 int siop_data_wait = SCSI_DATA_WAIT;
259 int siop_init_wait = SCSI_INIT_WAIT;
260
261 static struct {
262 unsigned char x; /* period from sync request message */
263 unsigned char y; /* siop_period << 4 | sbcl */
264 } xxx[] = {
265 {0x0f, 0x01},
266 {0x13, 0x11},
267 {0x17, 0x21},
268 /* {0x17, 0x02}, */
269 {0x1b, 0x31},
270 {0x1d, 0x12},
271 {0x1e, 0x41},
272 /* {0x1e, 0x03}, */
273 {0x22, 0x51},
274 {0x23, 0x22},
275 {0x26, 0x61},
276 /* {0x26, 0x13}, */
277 {0x29, 0x32},
278 {0x2a, 0x71},
279 {0x2d, 0x23},
280 {0x2e, 0x42},
281 {0x34, 0x52},
282 {0x35, 0x33},
283 {0x3a, 0x62},
284 {0x3c, 0x43},
285 {0x40, 0x72},
286 {0x44, 0x53},
287 {0x4b, 0x63},
288 {0x53, 0x73}
289 };
290
291 scsi_period_to_siop (dev, target)
292 struct siop_softc *dev;
293 {
294 int period, offset, i, sxfer;
295
296 period = dev->sc_msg[4];
297 offset = dev->sc_msg[5];
298 sxfer = 0;
299 if (offset <= SIOP_MAX_OFFSET)
300 sxfer = offset;
301 for (i = 0; i < sizeof (xxx) / 2; ++i) {
302 if (period <= xxx[i].x) {
303 sxfer |= xxx[i].y & 0x70;
304 offset = xxx[i].y & 0x03;
305 break;
306 }
307 }
308 dev->sc_sync[target].period = sxfer;
309 dev->sc_sync[target].offset = offset;
310 #ifdef DEBUG
311 printf ("sync: siop_sxfr %02x, siop_sbcl %02x\n", sxfer, offset);
312 #endif
313 }
314
315 /* default to not inhibit sync negotiation on any drive */
316 u_char siop_inhibit_sync[NSIOP][8] = { 0, 0, 1, 0, 0, 0, 0 }; /* initialize, so patchable */
317 int siop_no_dma = 0;
318
319 /*
320 * XXX Set/reset long delays.
321 *
322 * if delay == 0, reset default delays
323 * if delay < 0, set both delays to default long initialization values
324 * if delay > 0, set both delays to this value
325 *
326 * Used when a devices is expected to respond slowly (e.g. during
327 * initialization).
328 */
329 void
330 siop_delay(delay)
331 int delay;
332 {
333 static int saved_cmd_wait, saved_data_wait;
334
335 if (delay) {
336 saved_cmd_wait = siop_cmd_wait;
337 saved_data_wait = siop_data_wait;
338 if (delay > 0)
339 siop_cmd_wait = siop_data_wait = delay;
340 else
341 siop_cmd_wait = siop_data_wait = siop_init_wait;
342 } else {
343 siop_cmd_wait = saved_cmd_wait;
344 siop_data_wait = saved_data_wait;
345 }
346 }
347
348 static int initialized[NSIOP];
349
350 #ifdef DEBUG
351 /* 0x01 - full debug */
352 /* 0x02 - DMA chaining */
353 /* 0x04 - siopintr */
354 /* 0x08 - phase mismatch */
355 int siop_debug = 0;
356 int siopsync_debug = 0;
357 int siopdma_hits = 0;
358 int siopdma_misses = 0;
359 #endif
360
361 static void
362 siopabort(dev, regs, where)
363 register struct siop_softc *dev;
364 volatile register siop_regmap_t *regs;
365 char *where;
366 {
367
368 printf ("siop%d: abort %s: dstat %02x, sstat0 %02x sbcl %02x\n",
369 dev->sc_ac->amiga_unit,
370 where, regs->siop_dstat, regs->siop_sstat0, regs->siop_sbcl);
371
372 if (dev->sc_flags & SIOP_SELECTED) {
373 #ifdef TODO
374 SET_SBIC_cmd (regs, SBIC_CMD_ABORT);
375 WAIT_CIP (regs);
376
377 GET_SBIC_asr (regs, asr);
378 if (asr & (SBIC_ASR_BSY|SBIC_ASR_LCI))
379 {
380 /* ok, get more drastic.. */
381
382 SET_SBIC_cmd (regs, SBIC_CMD_RESET);
383 DELAY(25);
384 SBIC_WAIT(regs, SBIC_ASR_INT, 0);
385 GET_SBIC_csr (regs, csr); /* clears interrupt also */
386
387 dev->sc_flags &= ~SIOP_SELECTED;
388 return;
389 }
390
391 do
392 {
393 SBIC_WAIT (regs, SBIC_ASR_INT, 0);
394 GET_SBIC_csr (regs, csr);
395 }
396 while ((csr != SBIC_CSR_DISC) && (csr != SBIC_CSR_DISC_1)
397 && (csr != SBIC_CSR_CMD_INVALID));
398 #endif
399
400 /* lets just hope it worked.. */
401 dev->sc_flags &= ~SIOP_SELECTED;
402 }
403 }
404
405 #if NZEUSSCSI > 0
406 int
407 zeusscsiinit(ac)
408 register struct amiga_ctlr *ac;
409 {
410 register struct siop_softc *dev = &siop_softc[ac->amiga_unit];
411
412 #ifdef DEBUG
413 if (siop_debug)
414 printf ("zeusscsiinit: addr %x unit %d scripts %x ds %x\n",
415 ac->amiga_addr, ac->amiga_unit, scripts, &dev->sc_ds);
416 #endif
417 if ((int) scripts & 3)
418 panic ("zeusscsiinit: scripts not on a longword boundary");
419 if ((long)&dev->sc_ds & 3)
420 panic("zeusscsiinit: data storage alignment error\n");
421 if (! ac->amiga_addr)
422 return 0;
423
424 if (initialized[ac->amiga_unit])
425 return 0;
426
427 initialized[ac->amiga_unit] = 1;
428
429 /* advance ac->amiga_addr to point to the real siop-registers */
430 ac->amiga_addr = (caddr_t) ((int)ac->amiga_addr + 0x4000);
431 dev->sc_clock_freq = 0xc0;
432
433 /* hardwired IPL */
434 ac->amiga_ipl = 6;
435 dev->sc_ac = ac;
436 dev->sc_dq.dq_driver = &zeusscsidriver;
437 dev->sc_sq.dq_forw = dev->sc_sq.dq_back = &dev->sc_sq;
438 siopreset (ac->amiga_unit);
439
440 /* For the ZEUS SCSI, both IPL6 and IPL2 interrupts have to be
441 enabled. The ZEUS SCSI generates IPL6 interrupts, which are
442 not blocked by splbio(). The ZEUS interrupt handler saves the
443 siop interrupt status information in siop_softc and sets the
444 PORTS interrupt to process the interrupt at IPL2.
445
446 make sure IPL2 interrupts are delivered to the cpu when siopintr6
447 generates some. Note that this does not yet enable siop-interrupts,
448 this is handled in siopgo, which selectively enables interrupts only
449 while DMA requests are pending.
450
451 Note that enabling PORTS interrupts also enables keyboard interrupts
452 as soon as the corresponding int-enable bit in CIA-A is set. */
453
454 #if 0 /* EXTER interrupts are enabled in the clock initialization */
455 custom.intreq = INTF_EXTER;
456 custom.intena = INTF_SETCLR | INTF_EXTER;
457 #endif
458 custom.intreq = INTF_PORTS;
459 custom.intena = INTF_SETCLR | INTF_PORTS;
460 return(1);
461 }
462 #endif
463
464 #if NMAGNUMSCSI > 0
465 int
466 magnumscsiinit(ac)
467 register struct amiga_ctlr *ac;
468 {
469 register struct siop_softc *dev = &siop_softc[ac->amiga_unit];
470
471 #ifdef DEBUG
472 if (siop_debug)
473 printf ("magnumscsiinit: addr %x unit %d scripts %x ds %x\n",
474 ac->amiga_addr, ac->amiga_unit, scripts, &dev->sc_ds);
475 #endif
476 if ((int) scripts & 3)
477 panic ("magnumscsiinit: scripts not on a longword boundary");
478 if ((long)&dev->sc_ds & 3)
479 panic("magnumscsiinit: data storage alignment error\n");
480 if (! ac->amiga_addr)
481 return 0;
482
483 if (initialized[ac->amiga_unit])
484 return 0;
485
486 initialized[ac->amiga_unit] = 1;
487
488 /* advance ac->amiga_addr to point to the real siop-registers */
489 ac->amiga_addr = (caddr_t) ((int)ac->amiga_addr + 0x8000);
490 dev->sc_clock_freq = 0x40; /* DCNTL = 25.01->37.5MHZ / SCLK/1.5 */
491
492 /* hardwired IPL */
493 ac->amiga_ipl = 2;
494 dev->sc_ac = ac;
495 dev->sc_dq.dq_driver = &magnumscsidriver;
496 dev->sc_sq.dq_forw = dev->sc_sq.dq_back = &dev->sc_sq;
497 siopreset (ac->amiga_unit);
498
499 /* make sure IPL2 interrupts are delivered to the cpu when the siop
500 generates some. Note that this does not yet enable siop-interrupts,
501 this is handled in siopgo, which selectively enables interrupts only
502 while DMA requests are pending.
503
504 Note that enabling PORTS interrupts also enables keyboard interrupts
505 as soon as the corresponding int-enable bit in CIA-A is set. */
506
507 custom.intreq = INTF_PORTS;
508 custom.intena = INTF_SETCLR | INTF_PORTS;
509 return(1);
510 }
511 #endif
512
513
514 void
515 siopreset(unit)
516 register int unit;
517 {
518 register struct siop_softc *dev = &siop_softc[unit];
519 volatile register siop_regmap_t *regs =
520 (siop_regmap_t *)dev->sc_ac->amiga_addr;
521 u_int i, s;
522 u_char my_id, csr;
523
524 if (dev->sc_flags & SIOP_ALIVE)
525 siopabort(dev, regs, "reset");
526
527 printf("siop%d: ", unit);
528
529 s = splbio();
530 my_id = 7;
531
532 /*
533 * Reset the chip
534 * XXX - is this really needed?
535 */
536 regs->siop_sien &= ~SIOP_SIEN_RST;
537 regs->siop_scntl1 |= SIOP_SCNTL1_RST;
538 for (i = 0; i < 1000; ++i)
539 ;
540 regs->siop_scntl1 &= ~SIOP_SCNTL1_RST;
541 regs->siop_sien |= SIOP_SIEN_RST;
542
543 /*
544 * Set up various chip parameters
545 */
546 regs->siop_istat = 0x40;
547 for (i = 0; i < 1000; ++i)
548 ;
549 regs->siop_istat = 0x00;
550 regs->siop_scntl0 = SIOP_ARB_FULL | SIOP_SCNTL0_EPC | SIOP_SCNTL0_EPG;
551 regs->siop_dcntl = dev->sc_clock_freq;
552 regs->siop_dmode = 0x80;
553 regs->siop_sien = 0x00; /* don't enable interrupts yet */
554 regs->siop_dien = 0x00; /* don't enable interrupts yet */
555 regs->siop_scid = 1 << my_id;
556 regs->siop_dwt = 0x00;
557 regs->siop_ctest0 |= 0x20; /* Enable Active Negation ?? */
558 regs->siop_ctest7 |= 0x02; /* TT1 */
559
560 /* will need to re-negotiate sync xfers */
561 bzero(&dev->sc_sync, sizeof (dev->sc_sync));
562
563 splx (s);
564
565 printf("siop id %d\n", my_id);
566 dev->sc_flags |= SIOP_ALIVE;
567 dev->sc_flags &= ~(SIOP_SELECTED | SIOP_DMA);
568 }
569
570 /*
571 * Setup Data Storage for 53C710 and start SCRIPTS processing
572 */
573
574 static void
575 siop_setup (dev, target, cbuf, clen, buf, len)
576 struct siop_softc *dev;
577 int target;
578 u_char *cbuf;
579 int clen;
580 u_char *buf;
581 int len;
582 {
583 volatile register siop_regmap_t *regs =
584 (siop_regmap_t *)dev->sc_ac->amiga_addr;
585 int i;
586 int nchain;
587 int count, tcount;
588 char *addr, *dmaend;
589
590 dev->sc_istat = 0;
591 dev->sc_lun = 0x80; /* XXX */
592 dev->sc_stat[0] = -1;
593 dev->sc_msg[0] = -1;
594 dev->sc_ds.scsi_addr = (0x10000 << target) | (dev->sc_sync[target].period << 8);
595 dev->sc_ds.idlen = 1;
596 dev->sc_ds.idbuf = (char *) kvtop(&dev->sc_lun);
597 dev->sc_ds.cmdlen = clen;
598 dev->sc_ds.cmdbuf = (char *) kvtop(cbuf);
599 dev->sc_ds.stslen = 1;
600 dev->sc_ds.stsbuf = (char *) kvtop(&dev->sc_stat[0]);
601 dev->sc_ds.msglen = 1;
602 dev->sc_ds.msgbuf = (char *) kvtop(&dev->sc_msg[0]);
603 dev->sc_ds.sdtrolen = 0;
604 dev->sc_ds.sdtrilen = 0;
605 dev->sc_ds.chain[0].datalen = len;
606 dev->sc_ds.chain[0].databuf = (char *) kvtop(buf);
607
608 if (dev->sc_sync[target].state == SYNC_START) {
609 if (siop_inhibit_sync[dev->sc_ac->amiga_unit][target]) {
610 dev->sc_sync[target].state = SYNC_DONE;
611 dev->sc_sync[target].offset = 0;
612 dev->sc_sync[target].period = 0;
613 #ifdef DEBUG
614 if (siopsync_debug)
615 printf ("Forcing target %d asynchronous\n", target);
616 #endif
617 }
618 else {
619 dev->sc_msg[1] = MSG_IDENTIFY;
620 dev->sc_msg[2] = MSG_EXT_MESSAGE;
621 dev->sc_msg[3] = 3;
622 dev->sc_msg[4] = MSG_SYNC_REQ;
623 dev->sc_msg[5] = 100/4; /* min period = 100 nsec */
624 dev->sc_msg[6] = SIOP_MAX_OFFSET;
625 dev->sc_ds.sdtrolen = 6;
626 dev->sc_ds.sdtrilen = sizeof (dev->sc_msg) - 1;
627 dev->sc_ds.sdtrobuf = dev->sc_ds.sdtribuf = (char *) kvtop(dev->sc_msg + 1);
628 dev->sc_sync[target].state = SYNC_SENT;
629 #ifdef DEBUG
630 if (siopsync_debug)
631 printf ("Sending sync request to target %d\n", target);
632 #endif
633 }
634 }
635
636 /*
637 * If length is > 1 page, check for consecutive physical pages
638 * Need to set up chaining if not
639 */
640 nchain = 0;
641 count = len;
642 addr = buf;
643 dmaend = NULL;
644 while (count > 0) {
645 dev->sc_ds.chain[nchain].databuf = (char *) kvtop (addr);
646 if (count < (tcount = NBPG - ((int) addr & PGOFSET)))
647 tcount = count;
648 dev->sc_ds.chain[nchain].datalen = tcount;
649 addr += tcount;
650 count -= tcount;
651 if (dev->sc_ds.chain[nchain].databuf == dmaend) {
652 dmaend += dev->sc_ds.chain[nchain].datalen;
653 dev->sc_ds.chain[--nchain].datalen += tcount;
654 #ifdef DEBUG
655 ++siopdma_hits;
656 #endif
657 }
658 else {
659 dmaend = dev->sc_ds.chain[nchain].databuf +
660 dev->sc_ds.chain[nchain].datalen;
661 dev->sc_ds.chain[nchain].datalen = tcount;
662 #ifdef DEBUG
663 ++siopdma_misses;
664 #endif
665 }
666 ++nchain;
667 }
668 #ifdef DEBUG
669 if (nchain != 1 && len != 0 && siop_debug & 3) {
670 printf ("DMA chaining set: %d\n", nchain);
671 for (i = 0; i < nchain; ++i) {
672 printf (" [%d] %8x %4x\n", i, dev->sc_ds.chain[i].databuf,
673 dev->sc_ds.chain[i].datalen);
674 }
675 }
676 #endif
677
678 regs->siop_sbcl = dev->sc_sync[target].offset;
679 if (dev->sc_ds.sdtrolen)
680 regs->siop_scratch = regs->siop_scratch | 0x100;
681 else
682 regs->siop_scratch = regs->siop_scratch & ~0xff00;
683 regs->siop_dsa = (long) kvtop(&dev->sc_ds);
684 DCIS(); /* push data cache */
685 regs->siop_dsp = (long) kvtop(scripts);
686 }
687
688 /*
689 * Process a DMA or SCSI interrupt from the 53C710 SIOP
690 */
691
692 static int
693 siop_checkintr(dev, istat, dstat, sstat0, status)
694 struct siop_softc *dev;
695 u_char istat;
696 u_char dstat;
697 u_char sstat0;
698 int *status;
699 {
700 volatile register siop_regmap_t *regs =
701 (siop_regmap_t *)dev->sc_ac->amiga_addr;
702 int target;
703
704 regs->siop_ctest8 |= 0x04;
705 while ((regs->siop_ctest1 & SIOP_CTEST1_FMT) == 0)
706 ;
707 regs->siop_ctest8 &= ~0x04;
708 #ifdef DEBUG
709 if (siop_debug & 1) {
710 DCIAS(kvtop(&dev->sc_stat)); /* XXX */
711 printf ("siopchkintr: istat %x dstat %x sstat0 %x dsps %x sbcl %x sts %x msg %x\n",
712 istat, dstat, sstat0, regs->siop_dsps, regs->siop_sbcl, dev->sc_stat[0], dev->sc_msg[0]);
713 }
714 #endif
715 if (dstat & SIOP_DSTAT_SIR && (regs->siop_dsps == 0xff00 ||
716 regs->siop_dsps == 0xfffc)) {
717 /* Normal completion status, or check condition */
718 if (regs->siop_dsa != (long) kvtop(&dev->sc_ds)) {
719 printf ("siop: invalid dsa: %x %x\n", regs->siop_dsa,
720 kvtop(&dev->sc_ds));
721 panic("*** siop DSA invalid ***");
722 }
723 target = dev->sc_slave;
724 if (dev->sc_sync[target].state == SYNC_SENT) {
725 #ifdef DEBUG
726 if (siopsync_debug)
727 printf ("sync msg in: %02x %02x %02x %02x %02x %02x\n",
728 dev->sc_msg[1], dev->sc_msg[2], dev->sc_msg[3],
729 dev->sc_msg[4], dev->sc_msg[5], dev->sc_msg[6]);
730 #endif
731 dev->sc_sync[target].state = SYNC_DONE;
732 dev->sc_sync[target].period = 0;
733 dev->sc_sync[target].offset = 0;
734 if (dev->sc_msg[1] == MSG_EXT_MESSAGE &&
735 dev->sc_msg[2] == 3 &&
736 dev->sc_msg[3] == MSG_SYNC_REQ) {
737 printf ("siop%d: target %d now synchronous, period=%dns, offset=%d\n",
738 dev->sc_ac->amiga_unit, target,
739 dev->sc_msg[4] * 4, dev->sc_msg[5]);
740 scsi_period_to_siop (dev, target);
741 }
742 }
743 DCIAS(kvtop(&dev->sc_stat)); /* XXX */
744 *status = dev->sc_stat[0];
745 return 1;
746 }
747 if (sstat0 & SIOP_SSTAT0_M_A) { /* Phase mismatch */
748 #ifdef DEBUG
749 if (siop_debug & 9)
750 printf ("Phase mismatch: %x dsp +%x\n", regs->siop_sbcl,
751 regs->siop_dsp - kvtop(scripts));
752 #endif
753 if ((regs->siop_sbcl & SIOP_REQ) == 0)
754 printf ("Phase mismatch: REQ not asserted! %02x\n",
755 regs->siop_sbcl);
756 switch (regs->siop_sbcl & 7) {
757 /*
758 * For data out and data in phase, check for DMA chaining
759 */
760
761 /*
762 * for message in, check for possible reject for sync request
763 */
764 case 0:
765 regs->siop_dsp = kvtop(scripts) + Ent_dataout;
766 break;
767 case 1:
768 regs->siop_dsp = kvtop(scripts) + Ent_datain;
769 break;
770 case 2:
771 regs->siop_dsp = kvtop(scripts) + Ent_cmd;
772 break;
773 case 3:
774 regs->siop_dsp = kvtop(scripts) + Ent_status;
775 break;
776 case 6:
777 regs->siop_dsp = kvtop(scripts) + Ent_msgout;
778 break;
779 case 7:
780 regs->siop_dsp = kvtop(scripts) + Ent_msgin;
781 break;
782 default:
783 goto bad_phase;
784 }
785 return 0;
786 }
787 if (sstat0 & SIOP_SSTAT0_STO) { /* Select timed out */
788 *status = -1;
789 return 1;
790 }
791 if (dstat & SIOP_DSTAT_SIR && regs->siop_dsps == 0xff05 &&
792 (regs->siop_sbcl & (SIOP_MSG | SIOP_CD)) == 0) {
793 printf ("DMA chaining failed\n");
794 siopreset (dev->sc_ac->amiga_unit);
795 *status = -1;
796 return 1;
797 }
798 if (dstat & SIOP_DSTAT_SIR && regs->siop_dsps == 0xff27) {
799 #ifdef DEBUG
800 if (siop_debug & 3)
801 printf ("DMA chaining completed: dsa %x dnad %x addr %x\n",
802 regs->siop_dsa, regs->siop_dnad, regs->siop_addr);
803 #endif
804 regs->siop_dsa = kvtop (&dev->sc_ds);
805 regs->siop_dsp = kvtop (scripts) + Ent_status;
806 return 0;
807 }
808 target = dev->sc_slave;
809 if (dstat & SIOP_DSTAT_SIR && regs->siop_dsps == 0xff26 &&
810 dev->sc_msg[0] == MSG_REJECT && dev->sc_sync[target].state == SYNC_SENT) {
811 dev->sc_sync[target].state = SYNC_DONE;
812 dev->sc_sync[target].period = 0;
813 dev->sc_sync[target].offset = 0;
814 dev->sc_ds.sdtrolen = 0;
815 dev->sc_ds.sdtrilen = 0;
816 #ifdef DEBUG
817 if (siopsync_debug || 1)
818 printf ("target %d rejected sync, going asynchronous\n", target);
819 #endif
820 siop_inhibit_sync[dev->sc_ac->amiga_unit][target] = -1;
821 if ((regs->siop_sbcl & 7) == 6) {
822 regs->siop_dsp = kvtop(scripts) + Ent_msgout;
823 return (0);
824 }
825 }
826 if (sstat0 == 0 && dstat & SIOP_DSTAT_SIR) {
827 DCIAS(kvtop(&dev->sc_stat));
828 printf ("SIOP interrupt: %x sts %x msg %x sbcl %x\n",
829 regs->siop_dsps, dev->sc_stat[0], dev->sc_msg[0],
830 regs->siop_sbcl);
831 siopreset (dev->sc_ac->amiga_unit);
832 *status = -1;
833 return 1;
834 }
835 bad_phase:
836 /*
837 * temporary panic for unhandled conditions
838 * displays various things about the 53C710 status and registers
839 * then panics
840 */
841 printf ("siopchkintr: target %x ds %x\n", target, &dev->sc_ds);
842 printf ("scripts %x ds %x regs %x dsp %x dcmd %x\n", kvtop(scripts),
843 kvtop(&dev->sc_ds), kvtop(regs), regs->siop_dsp, *((long *)®s->siop_dcmd));
844 printf ("siopchkintr: istat %x dstat %x sstat0 %x dsps %x dsa %x sbcl %x sts %x msg %x\n",
845 istat, dstat, sstat0, regs->siop_dsps, regs->siop_dsa, regs->siop_sbcl,
846 dev->sc_stat[0], dev->sc_msg[0]);
847 panic("siopchkintr: **** temp ****");
848 }
849
850 /*
851 * SCSI 'immediate' command: issue a command to some SCSI device
852 * and get back an 'immediate' response (i.e., do programmed xfer
853 * to get the response data). 'cbuf' is a buffer containing a scsi
854 * command of length clen bytes. 'buf' is a buffer of length 'len'
855 * bytes for data. The transfer direction is determined by the device
856 * (i.e., by the scsi bus data xfer phase). If 'len' is zero, the
857 * command must supply no data. 'xferphase' is the bus phase the
858 * caller expects to happen after the command is issued. It should
859 * be one of DATA_IN_PHASE, DATA_OUT_PHASE or STATUS_PHASE.
860 *
861 * XXX - 53C710 will use DMA, but no interrupts (it's a heck of a
862 * lot easier to do than to use programmed I/O).
863 *
864 */
865 static int
866 siopicmd(dev, target, cbuf, clen, buf, len)
867 struct siop_softc *dev;
868 int target;
869 u_char *cbuf;
870 int clen;
871 u_char *buf;
872 int len;
873 {
874 volatile register siop_regmap_t *regs =
875 (siop_regmap_t *)dev->sc_ac->amiga_addr;
876 int i;
877 int status;
878 u_char istat;
879 u_char dstat;
880 u_char sstat0;
881
882 if (dev->sc_flags & SIOP_SELECTED) {
883 printf ("siopicmd%d: bus busy\n", target);
884 return -1;
885 }
886 regs->siop_sien = 0x00; /* disable SCSI and DMA interrupts */
887 regs->siop_dien = 0x00;
888 dev->sc_flags |= SIOP_SELECTED;
889 dev->sc_slave = target;
890 #ifdef DEBUG
891 if (siop_debug & 1)
892 printf ("siopicmd: target %x cmd %02x ds %x\n", target,
893 cbuf[0], &dev->sc_ds);
894 #endif
895 siop_setup (dev, target, cbuf, clen, buf, len);
896
897 for (;;) {
898 /* use cmd_wait values? */
899 i = siop_cmd_wait << 1;
900 while (((istat = regs->siop_istat) &
901 (SIOP_ISTAT_SIP | SIOP_ISTAT_DIP)) == 0) {
902 if (--i <= 0) {
903 printf ("waiting: tgt %d cmd %02x sbcl %02x dsp %x (+%x) dcmd %x ds %x\n",
904 target, cbuf[0],
905 regs->siop_sbcl, regs->siop_dsp,
906 regs->siop_dsp - kvtop(scripts),
907 *((long *)®s->siop_dcmd), &dev->sc_ds);
908 i = siop_cmd_wait << 2;
909 }
910 DELAY(1);
911 }
912 dstat = regs->siop_dstat;
913 sstat0 = regs->siop_sstat0;
914 #ifdef DEBUG
915 if (siop_debug & 1) {
916 DCIAS(kvtop(&dev->sc_stat)); /* XXX should just invalidate dev->sc_stat */
917 printf ("siopicmd: istat %x dstat %x sstat0 %x dsps %x sbcl %x sts %x msg %x\n",
918 istat, dstat, sstat0, regs->siop_dsps, regs->siop_sbcl,
919 dev->sc_stat[0], dev->sc_msg[0]);
920 }
921 #endif
922 if (siop_checkintr(dev, istat, dstat, sstat0, &status)) {
923 dev->sc_flags &= ~SIOP_SELECTED;
924 return (status);
925 }
926 }
927 }
928
929 int
930 siop_test_unit_rdy(ctlr, slave, unit)
931 int ctlr, slave, unit;
932 {
933 register struct siop_softc *dev = &siop_softc[ctlr];
934 static struct scsi_cdb6 cdb = { CMD_TEST_UNIT_READY };
935
936 cdb.lun = unit;
937 return (siopicmd(dev, slave, (u_char *)&cdb, sizeof(cdb), (u_char *)0, 0));
938 }
939
940 int
941 siop_start_stop_unit (ctlr, slave, unit, start)
942 int ctlr, slave, unit;
943 {
944 register struct siop_softc *dev = &siop_softc[ctlr];
945 static struct scsi_cdb6 cdb = { CMD_LOADUNLOAD };
946
947 cdb.lun = unit;
948 /* we don't set the immediate bit, so we wait for the
949 command to succeed.
950 We also don't touch the LoEj bit, which is primarily meant
951 for floppies. */
952 cdb.len = start & 0x01;
953 return (siopicmd(dev, slave, (u_char *)&cdb, sizeof(cdb), (u_char *)0, 0));
954 }
955
956
957 int
958 siop_request_sense(ctlr, slave, unit, buf, len)
959 int ctlr, slave, unit;
960 u_char *buf;
961 unsigned len;
962 {
963 register struct siop_softc *dev = &siop_softc[ctlr];
964 static struct scsi_cdb6 cdb = { CMD_REQUEST_SENSE };
965
966 cdb.lun = unit;
967 cdb.len = len;
968 return (siopicmd(dev, slave, (u_char *)&cdb, sizeof(cdb), buf, len));
969 }
970
971 int
972 siop_immed_command(ctlr, slave, unit, cdb, buf, len, rd)
973 int ctlr, slave, unit;
974 struct scsi_fmt_cdb *cdb;
975 u_char *buf;
976 unsigned len;
977 {
978 register struct siop_softc *dev = &siop_softc[ctlr];
979
980 cdb->cdb[1] |= (unit << 5);
981 return (siopicmd(dev, slave, (u_char *) cdb->cdb, cdb->len, buf, len));
982 }
983
984 /*
985 * The following routines are test-and-transfer i/o versions of read/write
986 * for things like reading disk labels and writing core dumps. The
987 * routine scsigo should be used for normal data transfers, NOT these
988 * routines.
989 */
990 int
991 siop_tt_read(ctlr, slave, unit, buf, len, blk, bshift)
992 int ctlr, slave, unit;
993 u_char *buf;
994 u_int len;
995 daddr_t blk;
996 int bshift;
997 {
998 register struct siop_softc *dev = &siop_softc[ctlr];
999 struct scsi_cdb10 cdb;
1000 int stat;
1001 int old_wait = siop_data_wait;
1002
1003 #ifdef DEBUG
1004 if (siop_debug & 1)
1005 printf ("siop%d: tt_read blk %x\n", slave, blk);
1006 #endif
1007 siop_data_wait = 300000;
1008 bzero(&cdb, sizeof(cdb));
1009 cdb.cmd = CMD_READ_EXT;
1010 cdb.lun = unit;
1011 blk >>= bshift;
1012 cdb.lbah = blk >> 24;
1013 cdb.lbahm = blk >> 16;
1014 cdb.lbalm = blk >> 8;
1015 cdb.lbal = blk;
1016 cdb.lenh = len >> (8 + DEV_BSHIFT + bshift);
1017 cdb.lenl = len >> (DEV_BSHIFT + bshift);
1018 stat = siopicmd(dev, slave, (u_char *) &cdb, sizeof(cdb), buf, len);
1019 siop_data_wait = old_wait;
1020 return (stat);
1021 }
1022
1023 int
1024 siop_tt_write(ctlr, slave, unit, buf, len, blk, bshift)
1025 int ctlr, slave, unit;
1026 u_char *buf;
1027 u_int len;
1028 daddr_t blk;
1029 int bshift;
1030 {
1031 register struct siop_softc *dev = &siop_softc[ctlr];
1032 struct scsi_cdb10 cdb;
1033 int stat;
1034 int old_wait = siop_data_wait;
1035
1036 #ifdef DEBUG
1037 if (siop_debug)
1038 printf ("siop%d: tt_write blk %d from %08x\n", slave,
1039 blk, kvtop(buf));
1040 if (blk < 604)
1041 panic("siop_tt_write: writing block < 604");
1042 #endif
1043 siop_data_wait = 300000;
1044
1045 bzero(&cdb, sizeof(cdb));
1046 cdb.cmd = CMD_WRITE_EXT;
1047 cdb.lun = unit;
1048 blk >>= bshift;
1049 cdb.lbah = blk >> 24;
1050 cdb.lbahm = blk >> 16;
1051 cdb.lbalm = blk >> 8;
1052 cdb.lbal = blk;
1053 cdb.lenh = len >> (8 + DEV_BSHIFT + bshift);
1054 cdb.lenl = len >> (DEV_BSHIFT + bshift);
1055 stat = siopicmd(dev, slave, (u_char *) &cdb, sizeof(cdb), buf, len);
1056 siop_data_wait = old_wait;
1057 return (stat);
1058 }
1059
1060 int
1061 siopreq(dq)
1062 register struct devqueue *dq;
1063 {
1064 register struct devqueue *hq;
1065
1066 hq = &siop_softc[dq->dq_ctlr].sc_sq;
1067 insque(dq, hq->dq_back);
1068 #ifdef DEBUG
1069 if (siop_debug & 1)
1070 printf ("siopreq %d ", dq->dq_back == hq ? 1 : 0);
1071 #endif
1072 if (dq->dq_back == hq)
1073 return(1);
1074 return(0);
1075 }
1076
1077 int
1078 siopustart (int unit)
1079 {
1080 register struct siop_softc *dev = &siop_softc[unit];
1081
1082 #ifdef DEBUG
1083 if (siop_debug & 1)
1084 printf ("siop%d: ustart ", unit);
1085 #endif
1086 return(1);
1087 }
1088
1089 void
1090 siopstart (int unit)
1091 {
1092 register struct devqueue *dq;
1093
1094 #ifdef DEBUG
1095 if (siop_debug & 1)
1096 printf ("siop%d: start ", unit);
1097 #endif
1098 dq = siop_softc[unit].sc_sq.dq_forw;
1099 (dq->dq_driver->d_go)(dq->dq_unit);
1100 }
1101
1102 int
1103 siopgo(ctlr, slave, unit, bp, cdb, pad)
1104 int ctlr, slave, unit;
1105 struct buf *bp;
1106 struct scsi_fmt_cdb *cdb;
1107 int pad;
1108 {
1109 register struct siop_softc *dev = &siop_softc[ctlr];
1110 volatile register siop_regmap_t *regs =
1111 (siop_regmap_t *)dev->sc_ac->amiga_addr;
1112 int i;
1113 int nchain;
1114 int count, tcount;
1115 char *addr, *dmaend;
1116
1117 #ifdef DEBUG
1118 if (siop_debug & 1)
1119 printf ("siop%d: go ", slave);
1120 if ((cdb->cdb[1] & 1) == 0 &&
1121 ((cdb->cdb[0] == CMD_WRITE && cdb->cdb[2] == 0 && cdb->cdb[3] == 0) ||
1122 (cdb->cdb[0] == CMD_WRITE_EXT && cdb->cdb[2] == 0 && cdb->cdb[3] == 0
1123 && cdb->cdb[4] == 0)))
1124 panic ("siopgo: attempted write to block < 0x100");
1125 #endif
1126 cdb->cdb[1] |= unit << 5;
1127
1128 if (dev->sc_flags & SIOP_SELECTED) {
1129 printf ("siopgo%d: bus busy\n", slave);
1130 return 1;
1131 }
1132
1133 if (siop_no_dma) {
1134 register struct devqueue *dq;
1135
1136 /* in this case do the transfer with programmed I/O :-( This is
1137 probably still faster than doing the transfer with DMA into a
1138 buffer and copying it later to its final destination, comments? */
1139 /* XXX - 53C710 uses DMA, but non-interrupt */
1140 siopicmd (dev, slave, (u_char *) cdb->cdb, cdb->len,
1141 bp->b_un.b_addr, bp->b_bcount);
1142
1143 dq = dev->sc_sq.dq_forw;
1144 (dq->dq_driver->d_intr)(dq->dq_unit, dev->sc_stat[0]);
1145 return dev->sc_stat[0];
1146 }
1147
1148 dev->sc_flags |= SIOP_SELECTED | SIOP_DMA;
1149 dev->sc_slave = slave;
1150 /* enable SCSI and DMA interrupts */
1151 regs->siop_sien = SIOP_SIEN_M_A | SIOP_SIEN_STO | SIOP_SIEN_SEL | SIOP_SIEN_SGE |
1152 SIOP_SIEN_UDC | SIOP_SIEN_RST | SIOP_SIEN_PAR;
1153 regs->siop_dien = 0x20 | SIOP_DIEN_ABRT | SIOP_DIEN_SIR | SIOP_DIEN_WTD |
1154 SIOP_DIEN_OPC;
1155 #ifdef DEBUG
1156 if (siop_debug & 1)
1157 printf ("siopgo: target %x cmd %02x ds %x\n", slave, cdb->cdb[0], &dev->sc_ds);
1158 #endif
1159
1160 siop_setup(dev, slave, cdb->cdb, cdb->len, bp->b_un.b_addr, bp->b_bcount);
1161
1162 return (0);
1163 }
1164
1165 void
1166 siopdone (int unit)
1167 {
1168 volatile register siop_regmap_t *regs =
1169 (siop_regmap_t *)siop_softc[unit].sc_ac->amiga_addr;
1170
1171 #ifdef DEBUG
1172 if (siop_debug & 1)
1173 printf("siop%d: done called!\n", unit);
1174 #endif
1175 }
1176
1177 /*
1178 * Level 6 interrupt processing for the Progressive Peripherals Inc
1179 * Zeus SCSI. Because the level 6 interrupt is above splbio, the
1180 * interrupt status is saved and the INTF_PORTS interrupt is set.
1181 * This way, the actual processing of the interrupt can be deferred
1182 * until splbio is unblocked
1183 */
1184
1185 #if NZEUSSCSI > 0
1186 int
1187 siopintr6 ()
1188 {
1189 register struct siop_softc *dev;
1190 volatile register siop_regmap_t *regs;
1191 register u_char istat;
1192 int unit;
1193 int found = 0;
1194
1195 for (unit = 0, dev = siop_softc; unit < NSIOP; unit++, dev++) {
1196 if (!initialized[dev->sc_ac->amiga_unit])
1197 continue;
1198 if (dev->sc_ac->amiga_ipl != 6)
1199 continue;
1200 regs = (siop_regmap_t *)dev->sc_ac->amiga_addr;
1201 istat = regs->siop_istat;
1202 if ((istat & (SIOP_ISTAT_SIP | SIOP_ISTAT_DIP)) == 0)
1203 continue;
1204 if ((dev->sc_flags & (SIOP_DMA | SIOP_SELECTED)) == SIOP_SELECTED)
1205 continue; /* doing non-interrupt I/O */
1206 found++;
1207 dev->sc_istat = istat;
1208 dev->sc_dstat = regs->siop_dstat;
1209 dev->sc_sstat0 = regs->siop_sstat0;
1210 custom.intreq = INTF_EXTER;
1211 custom.intreq = INTF_SETCLR | INTF_PORTS;
1212 }
1213 return (found);
1214 }
1215 #endif
1216
1217 /*
1218 * Check for 53C710 interrupts
1219 */
1220
1221 int
1222 siopintr2 ()
1223 {
1224 register struct siop_softc *dev;
1225 volatile register siop_regmap_t *regs;
1226 register u_char istat, dstat, sstat0;
1227 register struct devqueue *dq;
1228 int unit;
1229 int status;
1230 int found = 0;
1231
1232 for (unit = 0, dev = siop_softc; unit < NSIOP; unit++, dev++) {
1233 if (!initialized[dev->sc_ac->amiga_unit])
1234 continue;
1235 regs = (siop_regmap_t *)dev->sc_ac->amiga_addr;
1236 if (dev->sc_ac->amiga_ipl == 6)
1237 istat = dev->sc_istat;
1238 else
1239 istat = regs->siop_istat;
1240 if ((istat & (SIOP_ISTAT_SIP | SIOP_ISTAT_DIP)) == 0)
1241 continue;
1242 if ((dev->sc_flags & (SIOP_DMA | SIOP_SELECTED)) == SIOP_SELECTED)
1243 continue; /* doing non-interrupt I/O */
1244 /* Got a valid interrupt on this device */
1245 found++;
1246 if (dev->sc_ac->amiga_ipl == 6) {
1247 dstat = dev->sc_dstat;
1248 sstat0 = dev->sc_sstat0;
1249 dev->sc_istat = 0;
1250 }
1251 else {
1252 dstat = regs->siop_dstat;
1253 sstat0 = regs->siop_sstat0;
1254 }
1255 #ifdef DEBUG
1256 if (siop_debug & 1)
1257 printf ("siop%d: intr istat %x dstat %x sstat0 %x\n",
1258 unit, istat, dstat, sstat0);
1259 if ((dev->sc_flags & SIOP_DMA) == 0) {
1260 printf ("siop%d: spurious interrupt? istat %x dstat %x sstat0 %x\n",
1261 unit, istat, dstat, sstat0);
1262 }
1263 #endif
1264
1265 #ifdef DEBUG
1266 if (siop_debug & 5) {
1267 DCIAS(kvtop(&dev->sc_stat));
1268 printf ("siopintr%d: istat %x dstat %x sstat0 %x dsps %x sbcl %x sts %x msg %x\n",
1269 unit, istat, dstat, sstat0, regs->siop_dsps,
1270 regs->siop_sbcl, dev->sc_stat[0], dev->sc_msg[0]);
1271 }
1272 #endif
1273 if (siop_checkintr (dev, istat, dstat, sstat0, &status)) {
1274 #if 1
1275 regs->siop_sien = 0;
1276 regs->siop_dien = 0;
1277 if (status == 0xff)
1278 printf ("siopintr: status == 0xff\n");
1279 #endif
1280 dev->sc_flags &= ~(SIOP_DMA | SIOP_SELECTED);
1281 dq = dev->sc_sq.dq_forw;
1282 (dq->dq_driver->d_intr)(dq->dq_unit, status);
1283 }
1284 }
1285 return (found);
1286 }
1287
1288 void
1289 siopfree(dq)
1290 register struct devqueue *dq;
1291 {
1292 register struct devqueue *hq;
1293
1294 #ifdef DEBUG
1295 if (siop_debug & 1)
1296 printf ("siopfree\n");
1297 #endif
1298 hq = &siop_softc[dq->dq_ctlr].sc_sq;
1299 remque(dq);
1300 if ((dq = hq->dq_forw) != hq)
1301 (dq->dq_driver->d_start)(dq->dq_unit);
1302 }
1303
1304 /*
1305 * (XXX) The following routine is needed for the SCSI tape driver
1306 * to read odd-size records.
1307 */
1308
1309 /* XXX - probably not needed for the 53C710 (and not implemented yet!) */
1310
1311 #if NST > 0
1312 int
1313 siop_tt_oddio(ctlr, slave, unit, buf, len, b_flags, freedma)
1314 int ctlr, slave, unit, b_flags;
1315 u_char *buf;
1316 u_int len;
1317 {
1318 register struct siop_softc *dev = &siop_softc[ctlr];
1319 struct scsi_cdb6 cdb;
1320 u_char iphase;
1321 int stat;
1322
1323 printf ("siop%d: tt_oddio\n", slave);
1324 #if 0
1325 /*
1326 * First free any DMA channel that was allocated.
1327 * We can't use DMA to do this transfer.
1328 */
1329 if (freedma)
1330 dev->dmafree(&dev->sc_dq);
1331 /*
1332 * Initialize command block
1333 */
1334 bzero(&cdb, sizeof(cdb));
1335 cdb.lun = unit;
1336 cdb.lbam = (len >> 16) & 0xff;
1337 cdb.lbal = (len >> 8) & 0xff;
1338 cdb.len = len & 0xff;
1339 if (buf == 0) {
1340 cdb.cmd = CMD_SPACE;
1341 cdb.lun |= 0x00;
1342 len = 0;
1343 iphase = MESG_IN_PHASE;
1344 } else if (b_flags & B_READ) {
1345 cdb.cmd = CMD_READ;
1346 iphase = DATA_IN_PHASE;
1347 } else {
1348 cdb.cmd = CMD_WRITE;
1349 iphase = DATA_OUT_PHASE;
1350 }
1351 /*
1352 * Perform command (with very long delays)
1353 */
1354 scsi_delay(30000000);
1355 stat = siopicmd(dev, slave, (u_char *) &cdb, sizeof(cdb), buf, len, iphase);
1356 scsi_delay(0);
1357 return (stat);
1358 #endif
1359 return -1;
1360 }
1361 #endif
1362 #endif
1363