scsi.c revision 1.2 1 /* $NetBSD: scsi.c,v 1.2 1999/03/26 06:54:40 dbj Exp $ */
2 /*
3 * Copyright (c) 1994, 1997 Rolf Grossmann
4 * All rights reserved.
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 Rolf Grossmann.
17 * 4. The name of the author may not be used to endorse or promote products
18 * derived from this software without specific prior written permission
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #include <sys/param.h>
33 #include <next68k/dev/espreg.h>
34 #include <dev/scsipi/scsi_message.h>
35 #if 0
36 #include <next/next/prominfo.h>
37 #else
38 #include <next68k/next68k/nextrom.h>
39 #endif
40 #include "scsireg.h"
41 #include "dmareg.h"
42 #include "scsivar.h"
43
44 #include <lib/libsa/stand.h>
45
46 struct scsi_softc scsi_softc, *sc = &scsi_softc;
47 char the_dma_buffer[MAX_DMASIZE+DMA_ENDALIGNMENT], *dma_buffer;
48
49 int scsi_msgin(void);
50 int dma_start(char *addr, int len);
51 int dma_done(void);
52
53 void scsi_init(void);
54 void scsierror(char *error);
55 short scsi_getbyte(volatile caddr_t sr);
56 int scsi_wait_for_intr(void);
57 int scsiicmd(char target, char lun,
58 u_char *cbuf, int clen, char *addr, int len);
59
60 #ifdef SCSI_DEBUG
61 #define DPRINTF(x) printf x;
62 #else
63 #define DPRINTF(x)
64 #endif
65
66 void
67 scsi_init(void)
68 {
69 volatile caddr_t sr;
70 struct dma_dev *dma;
71
72 sr = P_SCSI;
73 dma = (struct dma_dev *)P_SCSI_CSR;
74
75 dma_buffer = DMA_ALIGN(char *, the_dma_buffer);
76
77 P_FLOPPY[FLP_CTRL] &= ~FLC_82077_SEL; /* select SCSI chip */
78
79 /* first reset dma */
80 dma->dd_csr = DMACSR_RESET;
81 DELAY(200);
82 sr[ESP_DCTL] = ESPDCTL_20MHZ | ESPDCTL_INTENB | ESPDCTL_RESET;
83 DELAY(10);
84 sr[ESP_DCTL] = ESPDCTL_20MHZ | ESPDCTL_INTENB;
85 DELAY(10);
86
87 /* then reset the SCSI chip */
88 sr[ESP_CMD] = ESPCMD_RSTCHIP;
89 sr[ESP_CMD] = ESPCMD_NOP;
90 DELAY(500);
91
92 /* now reset the SCSI bus */
93 sr[ESP_CMD] = ESPCMD_RSTSCSI;
94 DELAY(18000000); /* XXX should be about 2-3 seconds at least */
95
96 /* then reset the SCSI chip again and initialize it properly */
97 sr[ESP_CMD] = ESPCMD_RSTCHIP;
98 sr[ESP_CMD] = ESPCMD_NOP;
99 DELAY(500);
100 sr[ESP_CFG1] = ESPCFG1_SLOW | ESPCFG1_BUSID;
101 sr[ESP_CFG2] = 0;
102 sr[ESP_CCF] = 4; /* S5RCLKCONV_FACTOR(20); */
103 sr[ESP_TIMEOUT] = 152; /* S5RSELECT_TIMEOUT(20,250); */
104 sr[ESP_SYNCOFF] = 0;
105 sr[ESP_SYNCTP] = 5;
106 /*
107 sc->sc_intrstatus = sr->s5r_intrstatus;
108 sc->sc_intrstatus = sr->s5r_intrstatus;
109 */
110 sr[ESP_CFG1] = ESPCFG1_PARENB | ESPCFG1_BUSID;
111
112 sc->sc_state = SCSI_IDLE;
113 }
114
115 void
116 scsierror(char *error)
117 {
118 printf("scsierror: %s.\n", error);
119 }
120
121 short
122 scsi_getbyte(volatile caddr_t sr)
123 {
124 if ((sr[ESP_FFLAG] & ESPFIFO_FF) == 0)
125 {
126 printf("getbyte: no data!\n");
127 return -1;
128 }
129 return sr[ESP_FIFO];
130 }
131
132 int
133 scsi_wait_for_intr(void)
134 {
135 #if 0
136 extern struct prominfo *pi;
137 volitle int = pi->pi_intrstat; /* ### use constant? */
138 #else
139 extern char *mg;
140 #define MON(type, off) (*(type *)((u_int) (mg) + off))
141 volatile int *intrstat = MON(volatile int *,MG_intrstat);
142 volatile int *intrmask = MON(volatile int *,MG_intrmask);
143 #endif
144 int count;
145
146 for(count = 0; count < SCSI_TIMEOUT; count++) {
147 DPRINTF((" *intrstat = 0x%x\t*intrmask = 0x%x\n",*intrstat,*intrmask));
148
149 if (*intrstat & SCSI_INTR)
150 return 0;
151 }
152
153 printf("scsiicmd: timed out.\n");
154 return -1;
155 }
156
157 int
158 scsiicmd(char target, char lun,
159 u_char *cbuf, int clen,
160 char *addr, int len)
161 {
162 volatile caddr_t sr;
163 int i;
164
165 DPRINTF(("scsiicmd: [%x, %d] -> %d (%lx, %d)\n",*cbuf, clen,
166 target, (long)addr, len));
167 sr = P_SCSI;
168
169 if (sc->sc_state != SCSI_IDLE) {
170 scsierror("scsiiscmd: bad state");
171 return EIO;
172 }
173 sc->sc_result = 0;
174
175 /* select target */
176 sr[ESP_CMD] = ESPCMD_FLUSH;
177 DELAY(10);
178 sr[ESP_SELID] = target;
179 sr[ESP_FIFO] = MSG_IDENTIFY(lun, 0);
180 for (i=0; i<clen; i++)
181 sr[ESP_FIFO] = cbuf[i];
182 sr[ESP_CMD] = ESPCMD_SELATN;
183 sc->sc_state = SCSI_SELECTING;
184
185 while(sc->sc_state != SCSI_DONE) {
186 if (scsi_wait_for_intr()) /* maybe we'd better use real intrs ? */
187 return EIO;
188
189 if (sc->sc_state == SCSI_DMA)
190 {
191 /* registers are not valid on dma intr */
192 sc->sc_status = sc->sc_seqstep = sc->sc_intrstatus = 0;
193 DPRINTF(("scsiicmd: dma intr\n"));
194 } else {
195 /* scsi processing */
196 sc->sc_status = sr[ESP_STAT];
197 sc->sc_seqstep = sr[ESP_STEP];
198 sc->sc_intrstatus = sr[ESP_INTR];
199 DPRINTF(("scsiicmd: regs[intr=%x, stat=%x, step=%x]\n",
200 sc->sc_intrstatus, sc->sc_status, sc->sc_seqstep));
201 }
202
203 if (sc->sc_intrstatus & ESPINTR_SBR) {
204 scsierror("scsi bus reset");
205 return EIO;
206 }
207
208 if ((sc->sc_status & ESPSTAT_GE)
209 || (sc->sc_intrstatus & ESPINTR_ILL)) {
210 scsierror("software error");
211 return EIO;
212 }
213 if (sc->sc_status & ESPSTAT_PE)
214 {
215 scsierror("parity error");
216 return EIO;
217 }
218
219 switch(sc->sc_state)
220 {
221 case SCSI_SELECTING:
222 if (sc->sc_intrstatus & ESPINTR_DIS)
223 {
224 sc->sc_state = SCSI_IDLE;
225 return EUNIT; /* device not present */
226 }
227
228 #define ESPINTR_DONE (ESPINTR_BS | ESPINTR_FC)
229 if ((sc->sc_intrstatus & ESPINTR_DONE) != ESPINTR_DONE)
230 {
231 scsierror("selection failed");
232 return EIO;
233 }
234 sc->sc_state = SCSI_HASBUS;
235 break;
236 case SCSI_HASBUS:
237 if (sc->sc_intrstatus & ESPINTR_DIS)
238 {
239 scsierror("target disconnected");
240 return EIO;
241 }
242 break;
243 case SCSI_DMA:
244 if (sc->sc_intrstatus & ESPINTR_DIS)
245 {
246 scsierror("target disconnected");
247 return EIO;
248 }
249 if (dma_done() != 0)
250 return EIO;
251 continue;
252 case SCSI_CLEANUP:
253 if (sc->sc_intrstatus & ESPINTR_DIS)
254 {
255 sc->sc_state = SCSI_DONE;
256 continue;
257 }
258 DPRINTF(("hmm ... no disconnect on cleanup?\n"));
259 sc->sc_state = SCSI_DONE; /* maybe ... */
260 break;
261 }
262
263 /* transfer information now */
264 switch(sc->sc_status & ESPSTAT_PHASE)
265 {
266 case DATA_IN_PHASE:
267 if (dma_start(addr, len) != 0)
268 return EIO;
269 break;
270 case DATA_OUT_PHASE:
271 scsierror("data out phase not implemented");
272 return EIO;
273 case STATUS_PHASE:
274 DPRINTF(("status phase: "));
275 sr[ESP_CMD] = ESPCMD_ICCS;
276 sc->sc_result = scsi_getbyte(sr);
277 DPRINTF(("status is 0x%x.\n", sc->sc_result));
278 break;
279 case MSG_IN_PHASE:
280 if (scsi_msgin() != 0)
281 return EIO;
282 break;
283 default:
284 DPRINTF(("phase not implemented: 0x%x.\n",
285 sc->sc_status & ESPSTAT_PHASE));
286 scsierror("bad phase");
287 return EIO;
288 }
289 }
290
291 sc->sc_state = SCSI_IDLE;
292 return -sc->sc_result;
293 }
294
295 int
296 scsi_msgin(void)
297 {
298 volatile caddr_t sr;
299 u_char msg;
300
301 sr = P_SCSI;
302
303 msg = scsi_getbyte(sr);
304 if (msg)
305 {
306 printf("unexpected msg: 0x%x.\n",msg);
307 return -1;
308 }
309 if ((sc->sc_intrstatus & ESPINTR_FC) == 0)
310 {
311 printf("not function complete.\n");
312 return -1;
313 }
314 sc->sc_state = SCSI_CLEANUP;
315 sr[ESP_CMD] = ESPCMD_MSGOK;
316 return 0;
317 }
318
319 int
320 dma_start(char *addr, int len)
321 {
322 volatile caddr_t sr;
323 struct dma_dev *dma;
324
325
326 sr = P_SCSI;
327 dma = (struct dma_dev *)P_SCSI_CSR;
328
329 if (len > MAX_DMASIZE)
330 {
331 scsierror("dma too long");
332 return -1;
333 }
334
335 if (addr == NULL || len == 0)
336 {
337 #if 0 /* I'd take that as an error in my code */
338 DPRINTF(("hmm ... no dma requested.\n"));
339 sr[ESP_TCL] = 0;
340 sr[ESP_TCM] = 1;
341 sr[ESP_CMD] = ESPCMD_NOP;
342 sr[ESP_CMD] = ESPCMD_DMA | ESPCMD_TRPAD;
343 return 0;
344 #else
345 scsierror("unrequested dma");
346 return -1;
347 #endif
348 }
349
350 DPRINTF(("dma start: %lx, %d byte.\n", (long)addr, len));
351
352 DPRINTF(("dma_bufffer: start: 0x%lx end: 0x%lx \n",
353 (long)dma_buffer,(long)DMA_ENDALIGN(char *, dma_buffer+len)));
354
355 sc->dma_addr = addr;
356 sc->dma_len = len;
357
358 sr[ESP_TCL] = len & 0xff;
359 sr[ESP_TCM] = len >> 8;
360 sr[ESP_CMD] = ESPCMD_DMA | ESPCMD_NOP;
361 sr[ESP_CMD] = ESPCMD_DMA | ESPCMD_TRANS;
362
363 #if 0
364 dma->dd_csr = DMACSR_READ | DMACSR_RESET;
365 dma->dd_next_initbuf = dma_buffer;
366 dma->dd_limit = DMA_ENDALIGN(char *, dma_buffer+len);
367 dma->dd_csr = DMACSR_READ | DMACSR_SETENABLE;
368 #else
369 dma->dd_csr = 0;
370 dma->dd_csr = DMACSR_INITBUF | DMACSR_READ | DMACSR_RESET;
371 dma->dd_next_initbuf = dma_buffer;
372 dma->dd_limit = DMA_ENDALIGN(char *, dma_buffer+len);
373 dma->dd_csr = DMACSR_READ | DMACSR_SETENABLE;
374 #endif
375
376 sr[ESP_DCTL] = ESPDCTL_20MHZ|ESPDCTL_INTENB|ESPDCTL_DMAMOD|ESPDCTL_DMARD;
377
378 sc->sc_state = SCSI_DMA;
379 return 0;
380 }
381
382 int
383 dma_done(void)
384 {
385 volatile caddr_t sr;
386 struct dma_dev *dma;
387 int count, state;
388
389 sr = P_SCSI;
390 dma = (struct dma_dev *)P_SCSI_CSR;
391
392 state = dma->dd_csr & (DMACSR_BUSEXC | DMACSR_COMPLETE
393 | DMACSR_SUPDATE | DMACSR_ENABLE);
394
395 count = sr[ESP_TCM]<<8 | sr[ESP_TCL];
396 DPRINTF(("dma state = 0x%x, remain = %d.\n", state, count));
397
398 if (state & DMACSR_ENABLE)
399 {
400
401 DPRINTF(("dma still enabled, flushing DCTL.\n"));
402
403 sr[ESP_DCTL] = ESPDCTL_20MHZ | ESPDCTL_INTENB | ESPDCTL_DMAMOD
404 | ESPDCTL_DMARD | ESPDCTL_FLUSH;
405 /* DELAY(5); */
406 sr[ESP_DCTL] = ESPDCTL_20MHZ | ESPDCTL_INTENB | ESPDCTL_DMAMOD
407 | ESPDCTL_DMARD;
408 /* DELAY(5); */
409
410 return 0;
411 }
412
413 sr[ESP_DCTL] = ESPDCTL_20MHZ | ESPDCTL_INTENB;
414 count = sr[ESP_TCM]<<8 | sr[ESP_TCL];
415 dma->dd_csr = DMACSR_RESET;
416
417 DPRINTF(("dma done. remain = %d, state = 0x%x.\n", count, state));
418
419 if (count != 0)
420 {
421 printf("WARNING: unexpected %d characters remain in dma\n",count);
422 scsierror("dma transfer incomplete");
423 #if 0
424 return -1;
425 #endif
426 }
427
428 if (state & DMACSR_COMPLETE)
429 {
430 bcopy(dma_buffer, sc->dma_addr, sc->dma_len);
431 sc->sc_state = SCSI_HASBUS;
432 return 0;
433 }
434 if (state & DMACSR_BUSEXC)
435 {
436 scsierror("dma failed");
437 return -1;
438 }
439 scsierror("dma not completed\n");
440
441 return -1;
442 }
443