scsi.c revision 1.2.26.1 1 /* $NetBSD: scsi.c,v 1.2.26.1 2002/06/20 03:40:24 nathanw 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/ic/ncr53c9xreg.h>
35 #include <dev/scsipi/scsi_message.h>
36 #if 0
37 #include <next/next/prominfo.h>
38 #else
39 #include <next68k/next68k/nextrom.h>
40 #endif
41 #include "scsireg.h"
42 #include "dmareg.h"
43 #include "scsivar.h"
44
45 #include <lib/libsa/stand.h>
46
47 struct scsi_softc scsi_softc, *sc = &scsi_softc;
48 char the_dma_buffer[MAX_DMASIZE+DMA_ENDALIGNMENT], *dma_buffer;
49
50 int scsi_msgin(void);
51 int dma_start(char *addr, int len);
52 int dma_done(void);
53
54 void scsi_init(void);
55 void scsierror(char *error);
56 short scsi_getbyte(volatile caddr_t sr);
57 int scsi_wait_for_intr(void);
58 int scsiicmd(char target, char lun,
59 u_char *cbuf, int clen, char *addr, int len);
60
61 #ifdef SCSI_DEBUG
62 #define DPRINTF(x) printf x;
63 #else
64 #define DPRINTF(x)
65 #endif
66
67 void
68 scsi_init(void)
69 {
70 volatile caddr_t sr;
71 struct dma_dev *dma;
72
73 sr = P_SCSI;
74 dma = (struct dma_dev *)P_SCSI_CSR;
75
76 dma_buffer = DMA_ALIGN(char *, the_dma_buffer);
77
78 P_FLOPPY[FLP_CTRL] &= ~FLC_82077_SEL; /* select SCSI chip */
79
80 /* first reset dma */
81 dma->dd_csr = DMACSR_RESET;
82 DELAY(200);
83 sr[ESP_DCTL] = ESPDCTL_20MHZ | ESPDCTL_INTENB | ESPDCTL_RESET;
84 DELAY(10);
85 sr[ESP_DCTL] = ESPDCTL_20MHZ | ESPDCTL_INTENB;
86 DELAY(10);
87
88 /* then reset the SCSI chip */
89 sr[NCR_CMD] = NCRCMD_RSTCHIP;
90 sr[NCR_CMD] = NCRCMD_NOP;
91 DELAY(500);
92
93 /* now reset the SCSI bus */
94 sr[NCR_CMD] = NCRCMD_RSTSCSI;
95 DELAY(18000000); /* XXX should be about 2-3 seconds at least */
96
97 /* then reset the SCSI chip again and initialize it properly */
98 sr[NCR_CMD] = NCRCMD_RSTCHIP;
99 sr[NCR_CMD] = NCRCMD_NOP;
100 DELAY(500);
101 sr[NCR_CFG1] = NCRCFG1_SLOW | NCRCFG1_BUSID;
102 sr[NCR_CFG2] = 0;
103 sr[NCR_CCF] = 4; /* S5RCLKCONV_FACTOR(20); */
104 sr[NCR_TIMEOUT] = 152; /* S5RSELECT_TIMEOUT(20,250); */
105 sr[NCR_SYNCOFF] = 0;
106 sr[NCR_SYNCTP] = 5;
107 /*
108 sc->sc_intrstatus = sr->s5r_intrstatus;
109 sc->sc_intrstatus = sr->s5r_intrstatus;
110 */
111 sr[NCR_CFG1] = NCRCFG1_PARENB | NCRCFG1_BUSID;
112
113 sc->sc_state = SCSI_IDLE;
114 }
115
116 void
117 scsierror(char *error)
118 {
119 printf("scsierror: %s.\n", error);
120 }
121
122 short
123 scsi_getbyte(volatile caddr_t sr)
124 {
125 if ((sr[NCR_FFLAG] & NCRFIFO_FF) == 0)
126 {
127 printf("getbyte: no data!\n");
128 return -1;
129 }
130 return sr[NCR_FIFO];
131 }
132
133 int
134 scsi_wait_for_intr(void)
135 {
136 #if 0
137 extern struct prominfo *pi;
138 volitle int = pi->pi_intrstat; /* ### use constant? */
139 #else
140 extern char *mg;
141 #define MON(type, off) (*(type *)((u_int) (mg) + off))
142 volatile int *intrstat = MON(volatile int *,MG_intrstat);
143 volatile int *intrmask = MON(volatile int *,MG_intrmask);
144 #endif
145 int count;
146
147 for(count = 0; count < SCSI_TIMEOUT; count++) {
148 DPRINTF((" *intrstat = 0x%x\t*intrmask = 0x%x\n",*intrstat,*intrmask));
149
150 if (*intrstat & SCSI_INTR)
151 return 0;
152 }
153
154 printf("scsiicmd: timed out.\n");
155 return -1;
156 }
157
158 int
159 scsiicmd(char target, char lun,
160 u_char *cbuf, int clen,
161 char *addr, int len)
162 {
163 volatile caddr_t sr;
164 int i;
165
166 DPRINTF(("scsiicmd: [%x, %d] -> %d (%lx, %d)\n",*cbuf, clen,
167 target, (long)addr, len));
168 sr = P_SCSI;
169
170 if (sc->sc_state != SCSI_IDLE) {
171 scsierror("scsiiscmd: bad state");
172 return EIO;
173 }
174 sc->sc_result = 0;
175
176 /* select target */
177 sr[NCR_CMD] = NCRCMD_FLUSH;
178 DELAY(10);
179 sr[NCR_SELID] = target;
180 sr[NCR_FIFO] = MSG_IDENTIFY(lun, 0);
181 for (i=0; i<clen; i++)
182 sr[NCR_FIFO] = cbuf[i];
183 sr[NCR_CMD] = NCRCMD_SELATN;
184 sc->sc_state = SCSI_SELECTING;
185
186 while(sc->sc_state != SCSI_DONE) {
187 if (scsi_wait_for_intr()) /* maybe we'd better use real intrs ? */
188 return EIO;
189
190 if (sc->sc_state == SCSI_DMA)
191 {
192 /* registers are not valid on dma intr */
193 sc->sc_status = sc->sc_seqstep = sc->sc_intrstatus = 0;
194 DPRINTF(("scsiicmd: dma intr\n"));
195 } else {
196 /* scsi processing */
197 sc->sc_status = sr[NCR_STAT];
198 sc->sc_seqstep = sr[NCR_STEP];
199 sc->sc_intrstatus = sr[NCR_INTR];
200 DPRINTF(("scsiicmd: regs[intr=%x, stat=%x, step=%x]\n",
201 sc->sc_intrstatus, sc->sc_status, sc->sc_seqstep));
202 }
203
204 if (sc->sc_intrstatus & NCRINTR_SBR) {
205 scsierror("scsi bus reset");
206 return EIO;
207 }
208
209 if ((sc->sc_status & NCRSTAT_GE)
210 || (sc->sc_intrstatus & NCRINTR_ILL)) {
211 scsierror("software error");
212 return EIO;
213 }
214 if (sc->sc_status & NCRSTAT_PE)
215 {
216 scsierror("parity error");
217 return EIO;
218 }
219
220 switch(sc->sc_state)
221 {
222 case SCSI_SELECTING:
223 if (sc->sc_intrstatus & NCRINTR_DIS)
224 {
225 sc->sc_state = SCSI_IDLE;
226 return EUNIT; /* device not present */
227 }
228
229 #define NCRINTR_DONE (NCRINTR_BS | NCRINTR_FC)
230 if ((sc->sc_intrstatus & NCRINTR_DONE) != NCRINTR_DONE)
231 {
232 scsierror("selection failed");
233 return EIO;
234 }
235 sc->sc_state = SCSI_HASBUS;
236 break;
237 case SCSI_HASBUS:
238 if (sc->sc_intrstatus & NCRINTR_DIS)
239 {
240 scsierror("target disconnected");
241 return EIO;
242 }
243 break;
244 case SCSI_DMA:
245 if (sc->sc_intrstatus & NCRINTR_DIS)
246 {
247 scsierror("target disconnected");
248 return EIO;
249 }
250 if (dma_done() != 0)
251 return EIO;
252 continue;
253 case SCSI_CLEANUP:
254 if (sc->sc_intrstatus & NCRINTR_DIS)
255 {
256 sc->sc_state = SCSI_DONE;
257 continue;
258 }
259 DPRINTF(("hmm ... no disconnect on cleanup?\n"));
260 sc->sc_state = SCSI_DONE; /* maybe ... */
261 break;
262 }
263
264 /* transfer information now */
265 switch(sc->sc_status & NCRSTAT_PHASE)
266 {
267 case DATA_IN_PHASE:
268 if (dma_start(addr, len) != 0)
269 return EIO;
270 break;
271 case DATA_OUT_PHASE:
272 scsierror("data out phase not implemented");
273 return EIO;
274 case STATUS_PHASE:
275 DPRINTF(("status phase: "));
276 sr[NCR_CMD] = NCRCMD_ICCS;
277 sc->sc_result = scsi_getbyte(sr);
278 DPRINTF(("status is 0x%x.\n", sc->sc_result));
279 break;
280 case MSG_IN_PHASE:
281 if (scsi_msgin() != 0)
282 return EIO;
283 break;
284 default:
285 DPRINTF(("phase not implemented: 0x%x.\n",
286 sc->sc_status & NCRSTAT_PHASE));
287 scsierror("bad phase");
288 return EIO;
289 }
290 }
291
292 sc->sc_state = SCSI_IDLE;
293 return -sc->sc_result;
294 }
295
296 int
297 scsi_msgin(void)
298 {
299 volatile caddr_t sr;
300 u_char msg;
301
302 sr = P_SCSI;
303
304 msg = scsi_getbyte(sr);
305 if (msg)
306 {
307 printf("unexpected msg: 0x%x.\n",msg);
308 return -1;
309 }
310 if ((sc->sc_intrstatus & NCRINTR_FC) == 0)
311 {
312 printf("not function complete.\n");
313 return -1;
314 }
315 sc->sc_state = SCSI_CLEANUP;
316 sr[NCR_CMD] = NCRCMD_MSGOK;
317 return 0;
318 }
319
320 int
321 dma_start(char *addr, int len)
322 {
323 volatile caddr_t sr;
324 struct dma_dev *dma;
325
326
327 sr = P_SCSI;
328 dma = (struct dma_dev *)P_SCSI_CSR;
329
330 if (len > MAX_DMASIZE)
331 {
332 scsierror("dma too long");
333 return -1;
334 }
335
336 if (addr == NULL || len == 0)
337 {
338 #if 0 /* I'd take that as an error in my code */
339 DPRINTF(("hmm ... no dma requested.\n"));
340 sr[NCR_TCL] = 0;
341 sr[NCR_TCM] = 1;
342 sr[NCR_CMD] = NCRCMD_NOP;
343 sr[NCR_CMD] = NCRCMD_DMA | NCRCMD_TRPAD;
344 return 0;
345 #else
346 scsierror("unrequested dma");
347 return -1;
348 #endif
349 }
350
351 DPRINTF(("dma start: %lx, %d byte.\n", (long)addr, len));
352
353 DPRINTF(("dma_bufffer: start: 0x%lx end: 0x%lx \n",
354 (long)dma_buffer,(long)DMA_ENDALIGN(char *, dma_buffer+len)));
355
356 sc->dma_addr = addr;
357 sc->dma_len = len;
358
359 sr[NCR_TCL] = len & 0xff;
360 sr[NCR_TCM] = len >> 8;
361 sr[NCR_CMD] = NCRCMD_DMA | NCRCMD_NOP;
362 sr[NCR_CMD] = NCRCMD_DMA | NCRCMD_TRANS;
363
364 #if 0
365 dma->dd_csr = DMACSR_READ | DMACSR_RESET;
366 dma->dd_next_initbuf = dma_buffer;
367 dma->dd_limit = DMA_ENDALIGN(char *, dma_buffer+len);
368 dma->dd_csr = DMACSR_READ | DMACSR_SETENABLE;
369 #else
370 dma->dd_csr = 0;
371 dma->dd_csr = DMACSR_INITBUF | DMACSR_READ | DMACSR_RESET;
372 dma->dd_next_initbuf = dma_buffer;
373 dma->dd_limit = DMA_ENDALIGN(char *, dma_buffer+len);
374 dma->dd_csr = DMACSR_READ | DMACSR_SETENABLE;
375 #endif
376
377 sr[ESP_DCTL] = ESPDCTL_20MHZ|ESPDCTL_INTENB|ESPDCTL_DMAMOD|ESPDCTL_DMARD;
378
379 sc->sc_state = SCSI_DMA;
380 return 0;
381 }
382
383 int
384 dma_done(void)
385 {
386 volatile caddr_t sr;
387 struct dma_dev *dma;
388 int count, state;
389
390 sr = P_SCSI;
391 dma = (struct dma_dev *)P_SCSI_CSR;
392
393 state = dma->dd_csr & (DMACSR_BUSEXC | DMACSR_COMPLETE
394 | DMACSR_SUPDATE | DMACSR_ENABLE);
395
396 count = sr[NCR_TCM]<<8 | sr[NCR_TCL];
397 DPRINTF(("dma state = 0x%x, remain = %d.\n", state, count));
398
399 if (state & DMACSR_ENABLE)
400 {
401
402 DPRINTF(("dma still enabled, flushing DCTL.\n"));
403
404 sr[ESP_DCTL] = ESPDCTL_20MHZ | ESPDCTL_INTENB | ESPDCTL_DMAMOD
405 | ESPDCTL_DMARD | ESPDCTL_FLUSH;
406 /* DELAY(5); */
407 sr[ESP_DCTL] = ESPDCTL_20MHZ | ESPDCTL_INTENB | ESPDCTL_DMAMOD
408 | ESPDCTL_DMARD;
409 /* DELAY(5); */
410
411 return 0;
412 }
413
414 sr[ESP_DCTL] = ESPDCTL_20MHZ | ESPDCTL_INTENB;
415 count = sr[NCR_TCM]<<8 | sr[NCR_TCL];
416 dma->dd_csr = DMACSR_RESET;
417
418 DPRINTF(("dma done. remain = %d, state = 0x%x.\n", count, state));
419
420 if (count != 0)
421 {
422 printf("WARNING: unexpected %d characters remain in dma\n",count);
423 scsierror("dma transfer incomplete");
424 #if 0
425 return -1;
426 #endif
427 }
428
429 if (state & DMACSR_COMPLETE)
430 {
431 bcopy(dma_buffer, sc->dma_addr, sc->dma_len);
432 sc->sc_state = SCSI_HASBUS;
433 return 0;
434 }
435 if (state & DMACSR_BUSEXC)
436 {
437 scsierror("dma failed");
438 return -1;
439 }
440 scsierror("dma not completed\n");
441
442 return -1;
443 }
444