/[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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3 - (show 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 /*
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