/[gxemul]/upstream/0.3.1/devices/dev_asc.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Annotation of /upstream/0.3.1/devices/dev_asc.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3 - (hide annotations)
Mon Oct 8 16:17:52 2007 UTC (16 years, 7 months ago) by dpavlin
File MIME type: text/plain
File size: 31427 byte(s)
0.3.1
1 dpavlin 2 /*
2     * Copyright (C) 2003-2005 Anders Gavare. All rights reserved.
3     *
4     * Redistribution and use in source and binary forms, with or without
5     * modification, are permitted provided that the following conditions are met:
6     *
7     * 1. Redistributions of source code must retain the above copyright
8     * notice, this list of conditions and the following disclaimer.
9     * 2. Redistributions in binary form must reproduce the above copyright
10     * notice, this list of conditions and the following disclaimer in the
11     * documentation and/or other materials provided with the distribution.
12     * 3. The name of the author may not be used to endorse or promote products
13     * derived from this software without specific prior written permission.
14     *
15     * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16     * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17     * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18     * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19     * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20     * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21     * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22     * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23     * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24     * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25     * SUCH DAMAGE.
26     *
27     *
28     * $Id: dev_asc.c,v 1.70 2005/03/23 08:45:49 debug Exp $
29     *
30     * 'asc' SCSI controller for some DECstation/DECsystem models, and
31     * for PICA-61.
32     *
33     * Supposed to support SCSI-1 and SCSI-2. I've not yet found any docs
34     * on NCR53C9X, so I'll try to implement this device from LSI53CF92A docs
35     * instead.
36     *
37     *
38     * Memory layout on DECstation:
39     *
40     * NCR53C94 registers at base + 0
41     * DMA address register at base + 0x40000
42     * 128K SRAM buffer at base + 0x80000
43     * ROM at base + 0xc0000
44     *
45     * Memory layout on PICA-61:
46     *
47     * I haven't had time to look this up yet, but length = 0x1000.
48     *
49     *
50     * TODO: This module needs a clean-up, and some testing to see that
51     * it works will all OSes that might use it (NetBSD, OpenBSD,
52     * Ultrix, Linux, Mach, OSF/1, Sprite, ...)
53     */
54    
55     #include <stdio.h>
56     #include <stdlib.h>
57     #include <string.h>
58    
59     #include "cpu.h"
60     #include "devices.h"
61     #include "diskimage.h"
62     #include "machine.h"
63     #include "memory.h"
64     #include "misc.h"
65    
66     #include "ncr53c9xreg.h"
67    
68    
69     /* #define ASC_DEBUG */
70     /* #define debug fatal */
71     /* #define ASC_FULL_REGISTER_ACCESS_DEBUG */
72     /* static int quiet_mode = 0; */
73    
74     extern int quiet_mode;
75    
76    
77     #define ASC_FIFO_LEN 16
78     #define STATE_DISCONNECTED 0
79     #define STATE_INITIATOR 1
80     #define STATE_TARGET 2
81    
82     #define PHASE_DATA_OUT 0
83     #define PHASE_DATA_IN 1
84     #define PHASE_COMMAND 2
85     #define PHASE_STATUS 3
86     #define PHASE_MSG_OUT 6
87     #define PHASE_MSG_IN 7
88    
89    
90     /* The controller's SCSI id: */
91     #define ASC_SCSI_ID 7
92    
93     struct asc_data {
94     int mode;
95    
96     void *turbochannel;
97     int irq_nr;
98     int irq_caused_last_time;
99    
100     /* Current state and transfer: */
101     int cur_state;
102     int cur_phase;
103     struct scsi_transfer *xferp;
104    
105     /* FIFO: */
106     unsigned char fifo[ASC_FIFO_LEN];
107     int fifo_in;
108     int fifo_out;
109     int n_bytes_in_fifo; /* cached */
110    
111     /* ATN signal: */
112     int atn;
113    
114     /* Incoming dma data: */
115     unsigned char *incoming_data;
116     int incoming_len;
117     int incoming_data_addr;
118    
119     /* Built-in DMA memory (for DECstation 5000/200): */
120     uint32_t dma_address_reg;
121     unsigned char dma_address_reg_memory[4096];
122     /* NOTE: full page, for bintrans */
123     unsigned char dma[128 * 1024];
124    
125     void *dma_controller_data;
126     size_t (*dma_controller)(void *dma_controller_data,
127     unsigned char *data, size_t len, int writeflag);
128    
129     /* Read registers and write registers: */
130     uint32_t reg_ro[0x10];
131     uint32_t reg_wo[0x10];
132     };
133    
134     /* (READ/WRITE name, if split) */
135     char *asc_reg_names[0x10] = {
136     "NCR_TCL", "NCR_TCM", "NCR_FIFO", "NCR_CMD",
137     "NCR_STAT/NCR_SELID", "NCR_INTR/NCR_TIMEOUT",
138     "NCR_STEP/NCR_SYNCTP", "NCR_FFLAG/NCR_SYNCOFF",
139     "NCR_CFG1", "NCR_CCF", "NCR_TEST", "NCR_CFG2",
140     "NCR_CFG3", "reg_0xd", "NCR_TCH", "reg_0xf"
141     };
142    
143    
144     /* This is referenced below. */
145     static int dev_asc_select(struct cpu *cpu, struct asc_data *d, int from_id,
146     int to_id, int dmaflag, int n_messagebytes);
147    
148    
149     /*
150     * dev_asc_tick():
151     *
152     * This function is called "every now and then" from the CPU
153     * main loop.
154     */
155     void dev_asc_tick(struct cpu *cpu, void *extra)
156     {
157     struct asc_data *d = extra;
158    
159     if (d->reg_ro[NCR_STAT] & NCRSTAT_INT)
160     cpu_interrupt(cpu, d->irq_nr);
161     }
162    
163    
164     /*
165     * dev_asc_fifo_flush():
166     *
167     * Flush the fifo.
168     */
169     static void dev_asc_fifo_flush(struct asc_data *d)
170     {
171     d->fifo[0] = 0x00;
172     d->fifo_in = 0;
173     d->fifo_out = 0;
174     d->n_bytes_in_fifo = 0;
175     }
176    
177    
178     /*
179     * dev_asc_reset():
180     *
181     * Reset the state of the asc.
182     */
183     static void dev_asc_reset(struct asc_data *d)
184     {
185     d->cur_state = STATE_DISCONNECTED;
186     d->atn = 0;
187    
188     if (d->xferp != NULL)
189     scsi_transfer_free(d->xferp);
190     d->xferp = NULL;
191    
192     dev_asc_fifo_flush(d);
193    
194     /* According to table 4.1 in the LSI53CF92A manual: */
195     memset(d->reg_wo, 0, sizeof(d->reg_wo));
196     d->reg_wo[NCR_TCH] = 0x94;
197     d->reg_wo[NCR_CCF] = 2;
198     memcpy(d->reg_ro, d->reg_wo, sizeof(d->reg_ro));
199     d->reg_wo[NCR_SYNCTP] = 5;
200     }
201    
202    
203     /*
204     * dev_asc_fifo_read():
205     *
206     * Read a byte from the asc FIFO.
207     */
208     static int dev_asc_fifo_read(struct asc_data *d)
209     {
210     int res = d->fifo[d->fifo_out];
211    
212     if (d->fifo_in == d->fifo_out)
213     fatal("dev_asc: WARNING! FIFO overrun!\n");
214    
215     d->fifo_out = (d->fifo_out + 1) % ASC_FIFO_LEN;
216     d->n_bytes_in_fifo --;
217    
218     return res;
219     }
220    
221    
222     /*
223     * dev_asc_fifo_write():
224     *
225     * Write a byte to the asc FIFO.
226     */
227     static void dev_asc_fifo_write(struct asc_data *d, unsigned char data)
228     {
229     d->fifo[d->fifo_in] = data;
230     d->fifo_in = (d->fifo_in + 1) % ASC_FIFO_LEN;
231     d->n_bytes_in_fifo ++;
232    
233     if (d->fifo_in == d->fifo_out)
234     fatal("dev_asc: WARNING! FIFO overrun on write!\n");
235     }
236    
237    
238     /*
239     * dev_asc_newxfer():
240     *
241     * Allocate memory for a new transfer.
242     */
243     static void dev_asc_newxfer(struct asc_data *d)
244     {
245     if (d->xferp != NULL) {
246     printf("WARNING! dev_asc_newxfer(): freeing previous"
247     " transfer\n");
248     scsi_transfer_free(d->xferp);
249     d->xferp = NULL;
250     }
251    
252     d->xferp = scsi_transfer_alloc();
253     #if 0
254     d->xferp->get_data_out = dev_asc_get_data_out;
255     d->xferp->gdo_extra = (void *) d;
256     #endif
257     }
258    
259    
260     /*
261     * dev_asc_transfer():
262     *
263     * Transfer data from a SCSI device to the controller (or vice versa),
264     * depending on the current phase.
265     *
266     * Returns 1 if ok, 0 on error.
267     */
268     static int dev_asc_transfer(struct cpu *cpu, struct asc_data *d, int dmaflag)
269     {
270     int res = 1, all_done = 1;
271     int len, i, ch;
272    
273     if (!quiet_mode)
274     debug(" { TRANSFER to/from id %i: ", d->reg_wo[NCR_SELID] & 7);
275    
276     if (d->cur_phase == PHASE_DATA_IN) {
277     /* Data coming into the controller from external device: */
278     if (!dmaflag) {
279     if (d->xferp->data_in == NULL) {
280     fatal("no incoming data?\n");
281     res = 0;
282     } else {
283     /* TODO */
284     fatal("TODO..............\n");
285     len = d->reg_wo[NCR_TCL] +
286     d->reg_wo[NCR_TCM] * 256;
287    
288     len--;
289     ch = d->incoming_data[d->incoming_data_addr];
290     debug(" %02x", ch);
291    
292     d->incoming_data_addr ++;
293     dev_asc_fifo_write(d, ch);
294    
295     if (len == 0) {
296     free(d->incoming_data);
297     d->incoming_data = NULL;
298     }
299    
300     d->reg_ro[NCR_TCL] = len & 255;
301     d->reg_ro[NCR_TCM] = (len >> 8) & 255;
302     }
303     } else {
304     /* Copy from the incoming data into dma memory: */
305     if (d->xferp->data_in == NULL) {
306     fatal("no incoming DMA data?\n");
307     res = 0;
308     } else {
309     int len = d->xferp->data_in_len;
310     int len2 = d->reg_wo[NCR_TCL] +
311     d->reg_wo[NCR_TCM] * 256;
312     if (len2 == 0)
313     len2 = 65536;
314    
315     if (len < len2) {
316     fatal("{ asc: data in, len=%i len2=%i "
317     "}\n", len, len2);
318     }
319    
320     /* TODO: check len2 in a similar way? */
321     if (len + (d->dma_address_reg &
322     ((sizeof(d->dma)-1))) > sizeof(d->dma))
323     len = sizeof(d->dma) -
324     (d->dma_address_reg &
325     ((sizeof(d->dma)-1)));
326    
327     if (len2 > len) {
328     memset(d->dma + (d->dma_address_reg &
329     ((sizeof(d->dma)-1))), 0, len2);
330     len2 = len;
331     }
332    
333     #ifdef ASC_DEBUG
334     if (!quiet_mode) {
335     int i;
336     for (i=0; i<len; i++)
337     debug(" %02x", d->xferp->
338     data_in[i]);
339     }
340     #endif
341    
342     /*
343     * Are we using an external DMA controller?
344     * Then use it. Otherwise place the data in
345     * the DECstation 5000/200 built-in DMA
346     * region.
347     */
348     if (d->dma_controller != NULL)
349     d->dma_controller(
350     d->dma_controller_data,
351     d->xferp->data_in,
352     len2, 1);
353     else
354     memcpy(d->dma + (d->dma_address_reg &
355     ((sizeof(d->dma)-1))),
356     d->xferp->data_in, len2);
357    
358     if (d->xferp->data_in_len > len2) {
359     unsigned char *n;
360    
361     if (d->dma_controller != NULL)
362     printf("WARNING!!!!!!!!! BUG!!!! Unexpected stuff..."
363     "len2=%i d->xferp->data_in_len=%i\n", (int)len2,
364     (int)d->xferp->data_in_len);
365    
366     all_done = 0;
367     /* fatal("{ asc: multi-transfer"
368     " data_in, len=%i len2=%i }\n",
369     (int)len, (int)len2); */
370    
371     d->xferp->data_in_len -= len2;
372     n = malloc(d->xferp->data_in_len);
373     if (n == NULL) {
374     fprintf(stderr, "out of memory"
375     " in dev_asc\n");
376     exit(1);
377     }
378     memcpy(n, d->xferp->data_in + len2,
379     d->xferp->data_in_len);
380     free(d->xferp->data_in);
381     d->xferp->data_in = n;
382    
383     len = len2;
384     }
385    
386     len = 0;
387    
388     d->reg_ro[NCR_TCL] = len & 255;
389     d->reg_ro[NCR_TCM] = (len >> 8) & 255;
390    
391     /* Successful DMA transfer: */
392     d->reg_ro[NCR_STAT] |= NCRSTAT_TC;
393     }
394     }
395     } else if (d->cur_phase == PHASE_DATA_OUT) {
396     /* Data going from the controller to an external device: */
397     if (!dmaflag) {
398     fatal("TODO.......asdgasin\n");
399     } else {
400     /* Copy data from DMA to data_out: */
401     int len = d->xferp->data_out_len;
402     int len2 = d->reg_wo[NCR_TCL] +
403     d->reg_wo[NCR_TCM] * 256;
404     if (len2 == 0)
405     len2 = 65536;
406    
407     if (len == 0) {
408     fprintf(stderr, "d->xferp->data_out_len == "
409     "0 ?\n");
410     exit(1);
411     }
412    
413     /* TODO: Make sure that len2 doesn't go outside
414     of the dma memory? */
415    
416     /* fatal(" data out offset=%5i len=%5i\n",
417     d->xferp->data_out_offset, len2); */
418    
419     if (d->xferp->data_out_offset + len2 >
420     d->xferp->data_out_len) {
421     len2 = d->xferp->data_out_len -
422     d->xferp->data_out_offset;
423     }
424    
425     /*
426     * Are we using an external DMA controller? Then use
427     * it. Otherwise place the data in the DECstation
428     * 5000/200 built-in DMA region.
429     */
430     if (d->xferp->data_out == NULL) {
431     scsi_transfer_allocbuf(&d->xferp->data_out_len,
432     &d->xferp->data_out, len, 0);
433    
434     if (d->dma_controller != NULL)
435     d->dma_controller(
436     d->dma_controller_data,
437     d->xferp->data_out,
438     len2, 0);
439     else
440     memcpy(d->xferp->data_out,
441     d->dma + (d->dma_address_reg &
442     ((sizeof(d->dma)-1))), len2);
443     d->xferp->data_out_offset = len2;
444     } else {
445     /* Continuing a multi-transfer: */
446     if (d->dma_controller != NULL)
447     d->dma_controller(
448     d->dma_controller_data,
449     d->xferp->data_out +
450     d->xferp->data_out_offset,
451     len2, 0);
452     else
453     memcpy(d->xferp->data_out +
454     d->xferp->data_out_offset,
455     d->dma + (d->dma_address_reg &
456     ((sizeof(d->dma)-1))), len2);
457     d->xferp->data_out_offset += len2;
458     }
459    
460     /* If the disk wants more than we're DMAing,
461     then this is a multitransfer: */
462     if (d->xferp->data_out_offset !=
463     d->xferp->data_out_len) {
464     if (!quiet_mode)
465     debug("[ asc: data_out, multitransfer "
466     "len = %i, len2 = %i ]\n",
467     (int)len, (int)len2);
468     if (d->xferp->data_out_offset >
469     d->xferp->data_out_len)
470     fatal("[ asc data_out dma: too much?"
471     " ]\n");
472     else
473     all_done = 0;
474     }
475    
476     #ifdef ASC_DEBUG
477     if (!quiet_mode) {
478     int i;
479     for (i=0; i<len; i++)
480     debug(" %02x", d->xferp->data_out[i]);
481     }
482     #endif
483     len = 0;
484    
485     d->reg_ro[NCR_TCL] = len & 255;
486     d->reg_ro[NCR_TCM] = (len >> 8) & 255;
487    
488     /* Successful DMA transfer: */
489     d->reg_ro[NCR_STAT] |= NCRSTAT_TC;
490     }
491     } else if (d->cur_phase == PHASE_MSG_OUT) {
492     if (!quiet_mode)
493     debug("MSG OUT: ");
494     /* Data going from the controller to an external device: */
495     if (!dmaflag) {
496     /* There should already be one byte in msg_out, so we
497     just extend the message: */
498     int oldlen = d->xferp->msg_out_len;
499     int newlen;
500    
501     if (oldlen != 1) {
502     fatal(" (PHASE OUT MSG len == %i, "
503     "should be 1)\n", oldlen);
504     }
505    
506     newlen = oldlen + d->n_bytes_in_fifo;
507     d->xferp->msg_out = realloc(d->xferp->msg_out, newlen);
508     d->xferp->msg_out_len = newlen;
509     if (d->xferp->msg_out == NULL) {
510     fprintf(stderr, "out of memory realloc'ing "
511     "msg_out\n");
512     exit(1);
513     }
514    
515     i = oldlen;
516     while (d->fifo_in != d->fifo_out) {
517     ch = dev_asc_fifo_read(d);
518     d->xferp->msg_out[i++] = ch;
519     #ifdef ASC_DEBUG
520     debug("0x%02x ", ch);
521     #endif
522     }
523    
524     #ifdef MACH
525     /* Super-ugly hack for Mach/PMAX: TODO: make nicer */
526     if (d->xferp->msg_out_len == 6 &&
527     (d->xferp->msg_out[0] == 0x80 ||
528     d->xferp->msg_out[0] == 0xc0) &&
529     d->xferp->msg_out[1] == 0x01 &&
530     d->xferp->msg_out[2] == 0x03 &&
531     d->xferp->msg_out[3] == 0x01 &&
532     d->xferp->msg_out[4] == 0x32 &&
533     d->xferp->msg_out[5] == 0x0f) {
534     fatal(" !! Mach/PMAX hack !! ");
535     all_done = 0;
536     d->cur_phase = PHASE_MSG_IN;
537     }
538     #endif
539     } else {
540     /* Copy data from DMA to msg_out: */
541     fatal("[ DMA MSG OUT: xxx TODO! ]");
542     /* TODO */
543     res = 0;
544     }
545     } else if (d->cur_phase == PHASE_MSG_IN) {
546     if (!quiet_mode)
547     debug(" MSG IN");
548     fatal("[ MACH HACK! ]");
549     /* Super-ugly hack for Mach/PMAX: TODO: make nicer */
550     dev_asc_fifo_write(d, 0x07);
551     d->cur_phase = PHASE_COMMAND;
552     all_done = 0;
553     } else if (d->cur_phase == PHASE_COMMAND) {
554     if (!quiet_mode)
555     debug(" COMMAND ==> select ");
556     res = dev_asc_select(cpu, d, d->reg_ro[NCR_CFG1] & 7,
557     d->reg_wo[NCR_SELID] & 7, dmaflag, 0);
558     return res;
559     } else {
560     fatal("!!! TODO: unknown/unimplemented phase "
561     "in transfer: %i\n", d->cur_phase);
562     }
563    
564     /* Redo the command if data was just sent using DATA_OUT: */
565     if (d->cur_phase == PHASE_DATA_OUT) {
566     res = diskimage_scsicommand(cpu,
567     d->reg_wo[NCR_SELID] & 7, d->xferp);
568     }
569    
570     if (all_done) {
571     if (d->cur_phase == PHASE_MSG_OUT)
572     d->cur_phase = PHASE_COMMAND;
573     else
574     d->cur_phase = PHASE_STATUS;
575     }
576    
577     /*
578     * Cause an interrupt after the transfer:
579     *
580     * NOTE: Earlier I had this in here as well:
581     * d->reg_ro[NCR_INTR] |= NCRINTR_FC;
582     * but Linux/DECstation and OpenBSD/pmax seems to choke on that.
583     */
584     d->reg_ro[NCR_STAT] |= NCRSTAT_INT;
585     d->reg_ro[NCR_INTR] |= NCRINTR_BS;
586     d->reg_ro[NCR_STAT] = (d->reg_ro[NCR_STAT] & ~7) | d->cur_phase;
587     d->reg_ro[NCR_STEP] = (d->reg_ro[NCR_STEP] & ~7) | 4; /* 4? */
588    
589     if (!quiet_mode)
590     debug("}");
591     return res;
592     }
593    
594    
595     /*
596     * dev_asc_select():
597     *
598     * Select a SCSI device, send msg bytes (if any), and send command bytes.
599     * (Call diskimage_scsicommand() to handle the command.)
600     *
601     * Return value: 1 if ok, 0 on error.
602     */
603     static int dev_asc_select(struct cpu *cpu, struct asc_data *d, int from_id,
604     int to_id, int dmaflag, int n_messagebytes)
605     {
606     int ok, len, i, ch;
607    
608     if (!quiet_mode)
609     debug(" { SELECT id %i: ", to_id);
610    
611     /*
612     * Message bytes, if any:
613     */
614     if (!quiet_mode)
615     debug("msg:");
616    
617     if (n_messagebytes > 0) {
618     scsi_transfer_allocbuf(&d->xferp->msg_out_len,
619     &d->xferp->msg_out, n_messagebytes, 0);
620    
621     i = 0;
622     while (n_messagebytes-- > 0) {
623     int ch = dev_asc_fifo_read(d);
624     if (!quiet_mode)
625     debug(" %02x", ch);
626     d->xferp->msg_out[i++] = ch;
627     }
628    
629     if ((d->xferp->msg_out[0] & 0x7) != 0x00) {
630     debug(" (LUNs not implemented yet: 0x%02x) }",
631     d->xferp->msg_out[0]);
632     return 0;
633     }
634    
635     if (((d->xferp->msg_out[0] & ~0x7) != 0xc0) &&
636     ((d->xferp->msg_out[0] & ~0x7) != 0x80)) {
637     fatal(" (Unimplemented msg out: 0x%02x) }",
638     d->xferp->msg_out[0]);
639     return 0;
640     }
641    
642     if (d->xferp->msg_out_len > 1) {
643     fatal(" (Long msg out, not implemented yet;"
644     " len=%i) }", d->xferp->msg_out_len);
645     return 0;
646     }
647     } else {
648     if (!quiet_mode)
649     debug(" none");
650     }
651    
652     /* Special case: SELATNS (with STOP sequence): */
653     if (d->cur_phase == PHASE_MSG_OUT) {
654     if (!quiet_mode)
655     debug(" MSG OUT DEBUG");
656     if (d->xferp->msg_out_len != 1) {
657     fatal(" (SELATNS: msg out len == %i, should be 1)",
658     d->xferp->msg_out_len);
659     return 0;
660     }
661    
662     /* d->cur_phase = PHASE_COMMAND; */
663    
664     /* According to the LSI manual: */
665     d->reg_ro[NCR_STAT] |= NCRSTAT_INT;
666     d->reg_ro[NCR_INTR] |= NCRINTR_FC;
667     d->reg_ro[NCR_INTR] |= NCRINTR_BS;
668     d->reg_ro[NCR_STAT] = (d->reg_ro[NCR_STAT] & ~7) | d->cur_phase;
669     d->reg_ro[NCR_STEP] = (d->reg_ro[NCR_STEP] & ~7) | 1;
670    
671     if (!quiet_mode)
672     debug("}");
673     return 1;
674     }
675    
676     /*
677     * Command bytes:
678     */
679     if (!quiet_mode)
680     debug(", cmd: ");
681    
682     if (!dmaflag) {
683     if (!quiet_mode)
684     debug("[non-DMA] ");
685    
686     scsi_transfer_allocbuf(&d->xferp->cmd_len,
687     &d->xferp->cmd, d->n_bytes_in_fifo, 0);
688    
689     i = 0;
690     while (d->fifo_in != d->fifo_out) {
691     ch = dev_asc_fifo_read(d);
692     d->xferp->cmd[i++] = ch;
693     if (!quiet_mode)
694     debug("%02x ", ch);
695     }
696     } else {
697     if (!quiet_mode)
698     debug("[DMA] ");
699     len = d->reg_wo[NCR_TCL] + d->reg_wo[NCR_TCM] * 256;
700     if (len == 0)
701     len = 65536;
702    
703     scsi_transfer_allocbuf(&d->xferp->cmd_len,
704     &d->xferp->cmd, len, 0);
705    
706     for (i=0; i<len; i++) {
707     int ofs = d->dma_address_reg + i;
708     ch = d->dma[ofs & (sizeof(d->dma)-1)];
709     d->xferp->cmd[i] = ch;
710     if (!quiet_mode)
711     debug("%02x ", ch);
712     }
713    
714     d->reg_ro[NCR_TCL] = len & 255;
715     d->reg_ro[NCR_TCM] = (len >> 8) & 255;
716    
717     d->reg_ro[NCR_STAT] |= NCRSTAT_TC;
718     }
719    
720     /*
721     * Call the SCSI device to perform the command:
722     */
723     ok = diskimage_scsicommand(cpu, to_id, d->xferp);
724    
725    
726     /* Cause an interrupt: */
727     d->reg_ro[NCR_STAT] |= NCRSTAT_INT;
728     d->reg_ro[NCR_INTR] |= NCRINTR_FC;
729     d->reg_ro[NCR_INTR] |= NCRINTR_BS;
730    
731     if (ok == 2)
732     d->cur_phase = PHASE_DATA_OUT;
733     else if (d->xferp->data_in != NULL)
734     d->cur_phase = PHASE_DATA_IN;
735     else
736     d->cur_phase = PHASE_STATUS;
737    
738     d->reg_ro[NCR_STAT] = (d->reg_ro[NCR_STAT] & ~7) | d->cur_phase;
739     d->reg_ro[NCR_STEP] = (d->reg_ro[NCR_STEP] & ~7) | 4; /* DONE (?) */
740    
741     if (!quiet_mode)
742     debug("}");
743    
744     return ok;
745     }
746    
747    
748     /*
749     * dev_asc_address_reg_access():
750     */
751     int dev_asc_address_reg_access(struct cpu *cpu, struct memory *mem,
752     uint64_t relative_addr, unsigned char *data, size_t len,
753     int writeflag, void *extra)
754     {
755     struct asc_data *d = extra;
756    
757     if (relative_addr + len > 4)
758     return 0;
759    
760     if (writeflag==MEM_READ) {
761     memcpy(data, d->dma_address_reg_memory + relative_addr, len);
762     } else {
763     memcpy(d->dma_address_reg_memory + relative_addr, data, len);
764     }
765    
766     return 1;
767     }
768    
769    
770     /*
771     * dev_asc_dma_access():
772     */
773     int dev_asc_dma_access(struct cpu *cpu, struct memory *mem,
774     uint64_t relative_addr, unsigned char *data, size_t len,
775     int writeflag, void *extra)
776     {
777     struct asc_data *d = extra;
778    
779     if (writeflag==MEM_READ) {
780     memcpy(data, d->dma + relative_addr, len);
781     #ifdef ASC_DEBUG
782     {
783     int i;
784     debug("[ asc: read from DMA addr 0x%05x:",
785     (int) relative_addr);
786     for (i=0; i<len; i++)
787     debug(" %02x", data[i]);
788     debug(" ]\n");
789     }
790     #endif
791    
792     /* Don't return the common way, as that
793     would overwrite data. */
794     return 1;
795     } else {
796     memcpy(d->dma + relative_addr, data, len);
797     #ifdef ASC_DEBUG
798     {
799     int i;
800     debug("[ asc: write to DMA addr 0x%05x:",
801     (int) relative_addr);
802     for (i=0; i<len; i++)
803     debug(" %02x", data[i]);
804     debug(" ]\n");
805     }
806     #endif
807     /* Quick return. */
808     return 1;
809     }
810     }
811    
812    
813     /*
814     * dev_asc_access():
815     */
816     int dev_asc_access(struct cpu *cpu, struct memory *mem,
817     uint64_t relative_addr, unsigned char *data, size_t len,
818     int writeflag, void *extra)
819     {
820     int regnr;
821     struct asc_data *d = extra;
822     int target_exists;
823     int n_messagebytes = 0;
824     uint64_t idata = 0, odata = 0;
825    
826    
827     idata = memory_readmax64(cpu, data, len);
828    
829     #if 0
830     /* Debug stuff useful when trying to make dev_asc compatible
831     with the 'arc' emulation mode, which is different from
832     the DECstation mode. */
833     fatal("[ asc: writeflag=%i addr=%08x idata=%016llx ]\n",
834     writeflag, (int)relative_addr, (long long)idata);
835     #endif
836    
837     switch (d->mode) {
838     case DEV_ASC_DEC:
839     regnr = relative_addr / 4;
840     break;
841     case DEV_ASC_PICA:
842     default:
843     regnr = relative_addr;
844     }
845    
846     /* Controller's ID is fixed: */
847     d->reg_ro[NCR_CFG1] = (d->reg_ro[NCR_CFG1] & ~7) | ASC_SCSI_ID;
848    
849     d->reg_ro[NCR_FFLAG] = ((d->reg_ro[NCR_STEP] & 0x7) << 5)
850     + d->n_bytes_in_fifo;
851    
852     d->dma_address_reg =
853     d->dma_address_reg_memory[0] +
854     (d->dma_address_reg_memory[1] << 8) +
855     (d->dma_address_reg_memory[2] << 16) +
856     (d->dma_address_reg_memory[3] << 24);
857    
858     if (regnr < 0x10) {
859     if (regnr == NCR_FIFO) {
860     if (writeflag == MEM_WRITE)
861     dev_asc_fifo_write(d, idata);
862     else
863     odata = dev_asc_fifo_read(d);
864     } else {
865     if (writeflag==MEM_WRITE)
866     d->reg_wo[regnr] = idata;
867     else
868     odata = d->reg_ro[regnr];
869     }
870    
871     #ifdef ASC_FULL_REGISTER_ACCESS_DEBUG
872     if (!quiet_mode) {
873     if (writeflag==MEM_READ) {
874     debug("[ asc: read from %s: 0x%02x",
875     asc_reg_names[regnr], (int)odata);
876     } else {
877     debug("[ asc: write to %s: 0x%02x",
878     asc_reg_names[regnr], (int)idata);
879     }
880     }
881     #endif
882     } else if (relative_addr >= 0x300 && relative_addr < 0x600
883     && d->turbochannel != NULL) {
884     debug("[ asc: offset 0x%x, redirecting to turbochannel"
885     " access ]\n", relative_addr);
886     return dev_turbochannel_access(cpu, mem,
887     relative_addr, data, len, writeflag,
888     d->turbochannel);
889     } else {
890     if (writeflag==MEM_READ) {
891     fatal("[ asc: read from 0x%04x: 0x%02x ]\n",
892     relative_addr, (int)odata);
893     } else {
894     fatal("[ asc: write to 0x%04x: 0x%02x ]\n",
895     relative_addr, (int)idata);
896     }
897     }
898    
899     /*
900     * Some registers are read/write. Copy contents of
901     * reg_wo to reg_ro:
902     */
903     #if 0
904     d->reg_ro[ 0] = d->reg_wo[0]; /* Transfer count lo and */
905     d->reg_ro[ 1] = d->reg_wo[1]; /* middle */
906     #endif
907     d->reg_ro[ 2] = d->reg_wo[2];
908     d->reg_ro[ 3] = d->reg_wo[3];
909     d->reg_ro[ 8] = d->reg_wo[8];
910     d->reg_ro[ 9] = d->reg_wo[9];
911     d->reg_ro[10] = d->reg_wo[10];
912     d->reg_ro[11] = d->reg_wo[11];
913     d->reg_ro[12] = d->reg_wo[12];
914    
915     if (regnr == NCR_CMD && writeflag == MEM_WRITE) {
916     if (!quiet_mode)
917     debug(" ");
918    
919     /* TODO: Perhaps turn off others here too? */
920     d->reg_ro[NCR_INTR] &= ~NCRINTR_SBR;
921    
922     if (idata & NCRCMD_DMA) {
923     if (!quiet_mode)
924     debug("[DMA] ");
925    
926     /*
927     * DMA commands load the transfer count from the
928     * write-only registers to the read-only ones, and
929     * the Terminal Count bit is cleared.
930     */
931     d->reg_ro[NCR_TCL] = d->reg_wo[NCR_TCL];
932     d->reg_ro[NCR_TCM] = d->reg_wo[NCR_TCM];
933     d->reg_ro[NCR_TCH] = d->reg_wo[NCR_TCH];
934     d->reg_ro[NCR_STAT] &= ~NCRSTAT_TC;
935     }
936    
937     switch (idata & ~NCRCMD_DMA) {
938    
939     case NCRCMD_NOP:
940     if (!quiet_mode)
941     debug("NOP");
942     break;
943    
944     case NCRCMD_FLUSH:
945     if (!quiet_mode)
946     debug("FLUSH");
947     /* Flush the FIFO: */
948     dev_asc_fifo_flush(d);
949     break;
950    
951     case NCRCMD_RSTCHIP:
952     if (!quiet_mode)
953     debug("RSTCHIP");
954     /* Hardware reset. */
955     dev_asc_reset(d);
956     break;
957    
958     case NCRCMD_RSTSCSI:
959     if (!quiet_mode)
960     debug("RSTSCSI");
961     /* No interrupt if interrupts are disabled. */
962     if (!(d->reg_wo[NCR_CFG1] & NCRCFG1_SRR))
963     d->reg_ro[NCR_STAT] |= NCRSTAT_INT;
964     d->reg_ro[NCR_INTR] |= NCRINTR_SBR;
965     d->reg_ro[NCR_INTR] |= NCRINTR_FC;
966     d->cur_state = STATE_DISCONNECTED;
967     break;
968    
969     case NCRCMD_ENSEL:
970     if (!quiet_mode)
971     debug("ENSEL");
972     /* TODO */
973     break;
974    
975     case NCRCMD_ICCS:
976     if (!quiet_mode)
977     debug("ICCS");
978     /* Reveice a status byte + a message byte. */
979    
980     /* TODO: how about other status and message bytes? */
981     if (d->xferp != NULL && d->xferp->status != NULL)
982     dev_asc_fifo_write(d, d->xferp->status[0]);
983     else
984     dev_asc_fifo_write(d, 0x00);
985    
986     if (d->xferp != NULL && d->xferp->msg_in != NULL)
987     dev_asc_fifo_write(d, d->xferp->msg_in[0]);
988     else
989     dev_asc_fifo_write(d, 0x00);
990    
991     d->reg_ro[NCR_STAT] |= NCRSTAT_INT;
992     d->reg_ro[NCR_INTR] |= NCRINTR_FC;
993     /* d->reg_ro[NCR_INTR] |= NCRINTR_BS; */
994     d->reg_ro[NCR_STAT] = (d->reg_ro[NCR_STAT] & ~7) | 7;
995     /* ? probably 7 */
996     d->reg_ro[NCR_STEP] = (d->reg_ro[NCR_STEP] & ~7) | 4;
997     /* ? */
998     break;
999    
1000     case NCRCMD_MSGOK:
1001     /* Message is being Rejected if ATN is set,
1002     otherwise Accepted. */
1003     if (!quiet_mode) {
1004     debug("MSGOK");
1005     if (d->atn)
1006     debug("; Rejecting message");
1007     else
1008     debug("; Accepting message");
1009     }
1010     d->reg_ro[NCR_STAT] |= NCRSTAT_INT;
1011     d->reg_ro[NCR_INTR] |= NCRINTR_DIS;
1012    
1013     d->reg_ro[NCR_STAT] = (d->reg_ro[NCR_STAT] & ~7) |
1014     d->cur_phase; /* 6? */
1015     d->reg_ro[NCR_STEP] = (d->reg_ro[NCR_STEP] & ~7) |
1016     4; /* ? */
1017    
1018     d->cur_state = STATE_DISCONNECTED;
1019    
1020     if (d->xferp != NULL)
1021     scsi_transfer_free(d->xferp);
1022     d->xferp = NULL;
1023     break;
1024    
1025     case NCRCMD_SETATN:
1026     if (!quiet_mode)
1027     debug("SETATN");
1028     d->atn = 1;
1029     break;
1030    
1031     case NCRCMD_RSTATN:
1032     if (!quiet_mode)
1033     debug("RSTATN");
1034     d->atn = 0;
1035     break;
1036    
1037     case NCRCMD_SELNATN:
1038     case NCRCMD_SELATN:
1039     case NCRCMD_SELATNS:
1040     case NCRCMD_SELATN3:
1041     d->cur_phase = PHASE_COMMAND;
1042     switch (idata & ~NCRCMD_DMA) {
1043     case NCRCMD_SELATN:
1044     case NCRCMD_SELATNS:
1045     if ((idata & ~NCRCMD_DMA) == NCRCMD_SELATNS) {
1046     if (!quiet_mode)
1047     debug("SELATNS: select with "
1048     "atn and stop, id %i",
1049     d->reg_wo[NCR_SELID] & 7);
1050     d->cur_phase = PHASE_MSG_OUT;
1051     } else {
1052     if (!quiet_mode)
1053     debug("SELATN: select with atn"
1054     ", id %i",
1055     d->reg_wo[NCR_SELID] & 7);
1056     }
1057     n_messagebytes = 1;
1058     break;
1059     case NCRCMD_SELATN3:
1060     if (!quiet_mode)
1061     debug("SELNATN: select with atn3, "
1062     "id %i", d->reg_wo[NCR_SELID] & 7);
1063     n_messagebytes = 3;
1064     break;
1065     case NCRCMD_SELNATN:
1066     if (!quiet_mode)
1067     debug("SELNATN: select without atn, "
1068     "id %i", d->reg_wo[NCR_SELID] & 7);
1069     n_messagebytes = 0;
1070     }
1071    
1072     /* TODO: not just disk, but some generic
1073     SCSI device */
1074     target_exists = diskimage_exist(cpu->machine,
1075     d->reg_wo[NCR_SELID] & 7);
1076    
1077     if (target_exists) {
1078     /*
1079     * Select a SCSI device, send message bytes
1080     * (if any) and command bytes to the target.
1081     */
1082     int ok;
1083    
1084     dev_asc_newxfer(d);
1085    
1086     ok = dev_asc_select(cpu, d,
1087     d->reg_ro[NCR_CFG1] & 7,
1088     d->reg_wo[NCR_SELID] & 7,
1089     idata & NCRCMD_DMA? 1 : 0,
1090     n_messagebytes);
1091    
1092     if (ok)
1093     d->cur_state = STATE_INITIATOR;
1094     else {
1095     d->cur_state = STATE_DISCONNECTED;
1096     d->reg_ro[NCR_INTR] |= NCRINTR_DIS;
1097     d->reg_ro[NCR_STAT] |= NCRSTAT_INT;
1098     d->reg_ro[NCR_STEP] =
1099     (d->reg_ro[NCR_STEP] & ~7) | 0;
1100     if (d->xferp != NULL)
1101     scsi_transfer_free(d->xferp);
1102     d->xferp = NULL;
1103     }
1104     } else {
1105     /*
1106     * Selection failed, non-existant scsi ID:
1107     *
1108     * This is good enough to fool Ultrix, NetBSD,
1109     * OpenBSD and Linux to continue detection of
1110     * other IDs, without giving any warnings.
1111     */
1112     d->reg_ro[NCR_STAT] |= NCRSTAT_INT;
1113     d->reg_ro[NCR_INTR] |= NCRINTR_DIS;
1114     d->reg_ro[NCR_STEP] &= ~7;
1115     d->reg_ro[NCR_STEP] |= 0;
1116     dev_asc_fifo_flush(d);
1117     d->cur_state = STATE_DISCONNECTED;
1118     }
1119     break;
1120    
1121     case NCRCMD_TRPAD:
1122     if (!quiet_mode)
1123     debug("TRPAD");
1124    
1125     dev_asc_newxfer(d);
1126     {
1127     int ok;
1128    
1129     ok = dev_asc_transfer(cpu, d,
1130     idata & NCRCMD_DMA? 1 : 0);
1131     if (!ok) {
1132     d->cur_state = STATE_DISCONNECTED;
1133     d->reg_ro[NCR_INTR] |= NCRINTR_DIS;
1134     d->reg_ro[NCR_STAT] |= NCRSTAT_INT;
1135     d->reg_ro[NCR_STEP] = (d->reg_ro[
1136     NCR_STEP] & ~7) | 0;
1137     if (d->xferp != NULL)
1138     scsi_transfer_free(d->xferp);
1139     d->xferp = NULL;
1140     }
1141     }
1142     break;
1143    
1144     /* Old code which didn't work with Mach: */
1145     #if 0
1146     d->reg_ro[NCR_STAT] |= NCRSTAT_INT;
1147     d->reg_ro[NCR_INTR] |= NCRINTR_BS;
1148     d->reg_ro[NCR_INTR] |= NCRINTR_FC;
1149     d->reg_ro[NCR_STAT] |= NCRSTAT_TC;
1150    
1151     d->reg_ro[NCR_TCL] = 0;
1152     d->reg_ro[NCR_TCM] = 0;
1153    
1154     d->reg_ro[NCR_STEP] &= ~7;
1155     #if 0
1156     d->reg_ro[NCR_STEP] |= 0;
1157     dev_asc_fifo_flush(d);
1158     #else
1159     d->reg_ro[NCR_STEP] |= 4;
1160     #endif
1161     break;
1162     #endif
1163    
1164     case NCRCMD_TRANS:
1165     if (!quiet_mode)
1166     debug("TRANS");
1167    
1168     {
1169     int ok;
1170    
1171     ok = dev_asc_transfer(cpu, d,
1172     idata & NCRCMD_DMA? 1 : 0);
1173     if (!ok) {
1174     d->cur_state = STATE_DISCONNECTED;
1175     d->reg_ro[NCR_INTR] |= NCRINTR_DIS;
1176     d->reg_ro[NCR_STAT] |= NCRSTAT_INT;
1177     d->reg_ro[NCR_STEP] = (d->reg_ro[
1178     NCR_STEP] & ~7) | 0;
1179     if (d->xferp != NULL)
1180     scsi_transfer_free(d->xferp);
1181     d->xferp = NULL;
1182     }
1183     }
1184     break;
1185    
1186     default:
1187     fatal("(unimplemented asc cmd 0x%02x)", (int)idata);
1188     d->reg_ro[NCR_STAT] |= NCRSTAT_INT;
1189     d->reg_ro[NCR_INTR] |= NCRINTR_ILL;
1190     /*
1191     * TODO: exit or continue with Illegal command
1192     * interrupt?
1193     */
1194     exit(1);
1195     }
1196     }
1197    
1198     if (regnr == NCR_INTR && writeflag == MEM_READ) {
1199     /*
1200     * Reading the interrupt register de-asserts the
1201     * interrupt pin. Also, INTR, STEP, and STAT are all
1202     * cleared, according to page 64 of the LSI53CF92A manual,
1203     * if "interrupt output is true".
1204     */
1205     if (d->reg_ro[NCR_STAT] & NCRSTAT_INT) {
1206     d->reg_ro[NCR_INTR] = 0;
1207     d->reg_ro[NCR_STEP] = 0;
1208     d->reg_ro[NCR_STAT] = 0;
1209    
1210     /* For Mach/PMAX? TODO */
1211     d->reg_ro[NCR_STAT] = PHASE_COMMAND;
1212     }
1213    
1214     cpu_interrupt_ack(cpu, d->irq_nr);
1215     }
1216    
1217     if (regnr == NCR_CFG1) {
1218     /* TODO: other bits */
1219     if (!quiet_mode) {
1220     debug(" parity %s,", d->reg_ro[regnr] &
1221     NCRCFG1_PARENB? "enabled" : "disabled");
1222     debug(" scsi_id %i", d->reg_ro[regnr] & 0x7);
1223     }
1224     }
1225    
1226     #ifdef ASC_FULL_REGISTER_ACCESS_DEBUG
1227     debug(" ]\n");
1228     #endif
1229     dev_asc_tick(cpu, extra);
1230    
1231     if (writeflag == MEM_READ)
1232     memory_writemax64(cpu, data, len, odata);
1233    
1234     return 1;
1235     }
1236    
1237    
1238     /*
1239     * dev_asc_init():
1240     *
1241     * Register an 'asc' device.
1242     */
1243     void dev_asc_init(struct machine *machine, struct memory *mem,
1244     uint64_t baseaddr, int irq_nr, void *turbochannel,
1245     int mode,
1246     size_t (*dma_controller)(void *dma_controller_data,
1247     unsigned char *data, size_t len, int writeflag),
1248     void *dma_controller_data)
1249     {
1250     struct asc_data *d;
1251    
1252     d = malloc(sizeof(struct asc_data));
1253     if (d == NULL) {
1254     fprintf(stderr, "out of memory\n");
1255     exit(1);
1256     }
1257     memset(d, 0, sizeof(struct asc_data));
1258     d->irq_nr = irq_nr;
1259     d->turbochannel = turbochannel;
1260     d->mode = mode;
1261    
1262     d->reg_ro[NCR_CFG3] = NCRF9XCFG3_CDB;
1263    
1264     d->dma_controller = dma_controller;
1265     d->dma_controller_data = dma_controller_data;
1266    
1267     memory_device_register(mem, "asc", baseaddr,
1268     mode == DEV_ASC_PICA?
1269     DEV_ASC_PICA_LENGTH : DEV_ASC_DEC_LENGTH,
1270     dev_asc_access, d, MEM_DEFAULT, NULL);
1271    
1272     if (mode == DEV_ASC_DEC) {
1273     memory_device_register(mem, "asc_dma_address_reg",
1274     baseaddr + 0x40000, 4096, dev_asc_address_reg_access, d,
1275     MEM_BINTRANS_OK | MEM_BINTRANS_WRITE_OK,
1276     d->dma_address_reg_memory);
1277     memory_device_register(mem, "asc_dma", baseaddr + 0x80000,
1278     128*1024, dev_asc_dma_access, d,
1279     MEM_BINTRANS_OK | MEM_BINTRANS_WRITE_OK, d->dma);
1280     }
1281    
1282     machine_add_tickfunction(machine, dev_asc_tick, d, 15);
1283     }
1284    

  ViewVC Help
Powered by ViewVC 1.1.26