/[gxemul]/upstream/0.3.8/src/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.8/src/devices/dev_asc.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 23 - (show annotations)
Mon Oct 8 16:19:43 2007 UTC (16 years, 8 months ago) by dpavlin
File MIME type: text/plain
File size: 31646 byte(s)
0.3.8
1 /*
2 * Copyright (C) 2003-2006 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.79 2006/01/01 13:17:16 debug Exp $
29 *
30 * 'asc' SCSI controller for some DECstation/DECsystem models and PICA-61.
31 *
32 * Supposed to support SCSI-1 and SCSI-2. I've not yet found any docs
33 * on NCR53C9X, so I'll try to implement this device from LSI53CF92A docs
34 * instead.
35 *
36 *
37 * Memory layout on DECstation:
38 *
39 * NCR53C94 registers at base + 0
40 * DMA address register at base + 0x40000
41 * 128K SRAM buffer at base + 0x80000
42 * ROM at base + 0xc0000
43 *
44 * Memory layout on PICA-61:
45 *
46 * I haven't had time to look this up yet, but length = 0x1000.
47 *
48 *
49 * TODO: This module needs a clean-up, and some testing to see that
50 * it works will all OSes that might use it (NetBSD, OpenBSD,
51 * Ultrix, Linux, Mach, OSF/1, Sprite, ...)
52 *
53 * Running Linux/DECstation 2.4.26 with no scsi disks attached causes
54 * a warning message to be printed by Linux. (Whether this is a bug,
55 * is is the way it works on real hardware, I don't know.)
56 */
57
58 #include <stdio.h>
59 #include <stdlib.h>
60 #include <string.h>
61
62 #include "cpu.h"
63 #include "devices.h"
64 #include "diskimage.h"
65 #include "machine.h"
66 #include "memory.h"
67 #include "misc.h"
68
69 #include "ncr53c9xreg.h"
70
71
72 /* #define ASC_DEBUG */
73 /* #define debug fatal */
74 /* #define ASC_FULL_REGISTER_ACCESS_DEBUG */
75 /* static int quiet_mode = 0; */
76
77 #define ASC_TICK_SHIFT 15
78
79 extern int quiet_mode;
80
81
82 #define ASC_FIFO_LEN 16
83 #define STATE_DISCONNECTED 0
84 #define STATE_INITIATOR 1
85 #define STATE_TARGET 2
86
87 #define PHASE_DATA_OUT 0
88 #define PHASE_DATA_IN 1
89 #define PHASE_COMMAND 2
90 #define PHASE_STATUS 3
91 #define PHASE_MSG_OUT 6
92 #define PHASE_MSG_IN 7
93
94
95 /* The controller's SCSI id: */
96 #define ASC_SCSI_ID 7
97
98 #define ASC_DMA_SIZE (128*1024)
99
100 struct asc_data {
101 int mode;
102
103 void *turbochannel;
104 int irq_nr;
105 int irq_caused_last_time;
106
107 /* Current state and transfer: */
108 int cur_state;
109 int cur_phase;
110 struct scsi_transfer *xferp;
111
112 /* FIFO: */
113 unsigned char fifo[ASC_FIFO_LEN];
114 int fifo_in;
115 int fifo_out;
116 int n_bytes_in_fifo; /* cached */
117
118 /* ATN signal: */
119 int atn;
120
121 /* Incoming dma data: */
122 unsigned char *incoming_data;
123 int incoming_len;
124 int incoming_data_addr;
125
126 /* Built-in DMA memory (for DECstation 5000/200): */
127 uint32_t dma_address_reg;
128 unsigned char *dma_address_reg_memory;
129 unsigned char *dma;
130
131 void *dma_controller_data;
132 size_t (*dma_controller)(void *dma_controller_data,
133 unsigned char *data, size_t len, int writeflag);
134
135 /* Read registers and write registers: */
136 uint32_t reg_ro[0x10];
137 uint32_t reg_wo[0x10];
138 };
139
140 /* (READ/WRITE name, if split) */
141 char *asc_reg_names[0x10] = {
142 "NCR_TCL", "NCR_TCM", "NCR_FIFO", "NCR_CMD",
143 "NCR_STAT/NCR_SELID", "NCR_INTR/NCR_TIMEOUT",
144 "NCR_STEP/NCR_SYNCTP", "NCR_FFLAG/NCR_SYNCOFF",
145 "NCR_CFG1", "NCR_CCF", "NCR_TEST", "NCR_CFG2",
146 "NCR_CFG3", "reg_0xd", "NCR_TCH", "reg_0xf"
147 };
148
149
150 /* This is referenced below. */
151 static int dev_asc_select(struct cpu *cpu, struct asc_data *d, int from_id,
152 int to_id, int dmaflag, int n_messagebytes);
153
154
155 /*
156 * dev_asc_tick():
157 *
158 * This function is called "every now and then" from the CPU
159 * main loop.
160 */
161 void dev_asc_tick(struct cpu *cpu, void *extra)
162 {
163 struct asc_data *d = extra;
164
165 if (d->reg_ro[NCR_STAT] & NCRSTAT_INT)
166 cpu_interrupt(cpu, d->irq_nr);
167 }
168
169
170 /*
171 * dev_asc_fifo_flush():
172 *
173 * Flush the fifo.
174 */
175 static void dev_asc_fifo_flush(struct asc_data *d)
176 {
177 d->fifo[0] = 0x00;
178 d->fifo_in = 0;
179 d->fifo_out = 0;
180 d->n_bytes_in_fifo = 0;
181 }
182
183
184 /*
185 * dev_asc_reset():
186 *
187 * Reset the state of the asc.
188 */
189 static void dev_asc_reset(struct asc_data *d)
190 {
191 d->cur_state = STATE_DISCONNECTED;
192 d->atn = 0;
193
194 if (d->xferp != NULL)
195 scsi_transfer_free(d->xferp);
196 d->xferp = NULL;
197
198 dev_asc_fifo_flush(d);
199
200 /* According to table 4.1 in the LSI53CF92A manual: */
201 memset(d->reg_wo, 0, sizeof(d->reg_wo));
202 d->reg_wo[NCR_TCH] = 0x94;
203 d->reg_wo[NCR_CCF] = 2;
204 memcpy(d->reg_ro, d->reg_wo, sizeof(d->reg_ro));
205 d->reg_wo[NCR_SYNCTP] = 5;
206 }
207
208
209 /*
210 * dev_asc_fifo_read():
211 *
212 * Read a byte from the asc FIFO.
213 */
214 static int dev_asc_fifo_read(struct asc_data *d)
215 {
216 int res = d->fifo[d->fifo_out];
217
218 if (d->fifo_in == d->fifo_out)
219 fatal("dev_asc: WARNING! FIFO overrun!\n");
220
221 d->fifo_out = (d->fifo_out + 1) % ASC_FIFO_LEN;
222 d->n_bytes_in_fifo --;
223
224 return res;
225 }
226
227
228 /*
229 * dev_asc_fifo_write():
230 *
231 * Write a byte to the asc FIFO.
232 */
233 static void dev_asc_fifo_write(struct asc_data *d, unsigned char data)
234 {
235 d->fifo[d->fifo_in] = data;
236 d->fifo_in = (d->fifo_in + 1) % ASC_FIFO_LEN;
237 d->n_bytes_in_fifo ++;
238
239 if (d->fifo_in == d->fifo_out)
240 fatal("dev_asc: WARNING! FIFO overrun on write!\n");
241 }
242
243
244 /*
245 * dev_asc_newxfer():
246 *
247 * Allocate memory for a new transfer.
248 */
249 static void dev_asc_newxfer(struct asc_data *d)
250 {
251 if (d->xferp != NULL) {
252 printf("WARNING! dev_asc_newxfer(): freeing previous"
253 " transfer\n");
254 scsi_transfer_free(d->xferp);
255 d->xferp = NULL;
256 }
257
258 d->xferp = scsi_transfer_alloc();
259 #if 0
260 d->xferp->get_data_out = dev_asc_get_data_out;
261 d->xferp->gdo_extra = (void *) d;
262 #endif
263 }
264
265
266 /*
267 * dev_asc_transfer():
268 *
269 * Transfer data from a SCSI device to the controller (or vice versa),
270 * depending on the current phase.
271 *
272 * Returns 1 if ok, 0 on error.
273 */
274 static int dev_asc_transfer(struct cpu *cpu, struct asc_data *d, int dmaflag)
275 {
276 int res = 1, all_done = 1;
277 int len, i, ch;
278
279 if (!quiet_mode)
280 debug(" { TRANSFER to/from id %i: ", d->reg_wo[NCR_SELID] & 7);
281
282 if (d->cur_phase == PHASE_DATA_IN) {
283 /* Data coming into the controller from external device: */
284 if (!dmaflag) {
285 if (d->xferp->data_in == NULL) {
286 fatal("no incoming data?\n");
287 res = 0;
288 } else {
289 /* TODO */
290 fatal("TODO..............\n");
291 len = d->reg_wo[NCR_TCL] +
292 d->reg_wo[NCR_TCM] * 256;
293
294 len--;
295 ch = d->incoming_data[d->incoming_data_addr];
296 debug(" %02x", ch);
297
298 d->incoming_data_addr ++;
299 dev_asc_fifo_write(d, ch);
300
301 if (len == 0) {
302 free(d->incoming_data);
303 d->incoming_data = NULL;
304 }
305
306 d->reg_ro[NCR_TCL] = len & 255;
307 d->reg_ro[NCR_TCM] = (len >> 8) & 255;
308 }
309 } else {
310 /* Copy from the incoming data into dma memory: */
311 if (d->xferp->data_in == NULL) {
312 fatal("no incoming DMA data?\n");
313 res = 0;
314 } else {
315 size_t len = d->xferp->data_in_len;
316 size_t len2 = d->reg_wo[NCR_TCL] +
317 d->reg_wo[NCR_TCM] * 256;
318 if (len2 == 0)
319 len2 = 65536;
320
321 if (len < len2) {
322 fatal("{ asc: data in, len=%i len2=%i "
323 "}\n", len, len2);
324 }
325
326 /* TODO: check len2 in a similar way? */
327 if (len + (d->dma_address_reg &
328 (ASC_DMA_SIZE-1)) > ASC_DMA_SIZE)
329 len = ASC_DMA_SIZE -
330 (d->dma_address_reg &
331 (ASC_DMA_SIZE-1));
332
333 if (len2 > len) {
334 memset(d->dma + (d->dma_address_reg &
335 (ASC_DMA_SIZE-1)), 0, len2);
336 len2 = len;
337 }
338
339 #ifdef ASC_DEBUG
340 if (!quiet_mode) {
341 int i;
342 for (i=0; i<len; i++)
343 debug(" %02x", d->xferp->
344 data_in[i]);
345 }
346 #endif
347
348 /*
349 * Are we using an external DMA controller?
350 * Then use it. Otherwise place the data in
351 * the DECstation 5000/200 built-in DMA
352 * region.
353 */
354 if (d->dma_controller != NULL)
355 d->dma_controller(
356 d->dma_controller_data,
357 d->xferp->data_in,
358 len2, 1);
359 else
360 memcpy(d->dma + (d->dma_address_reg &
361 (ASC_DMA_SIZE-1)),
362 d->xferp->data_in, len2);
363
364 if (d->xferp->data_in_len > len2) {
365 unsigned char *n;
366
367 if (d->dma_controller != NULL)
368 printf("WARNING!!!!!!!!! BUG!!!! Unexpected stuff..."
369 "len2=%i d->xferp->data_in_len=%i\n", (int)len2,
370 (int)d->xferp->data_in_len);
371
372 all_done = 0;
373 /* fatal("{ asc: multi-transfer"
374 " data_in, len=%i len2=%i }\n",
375 (int)len, (int)len2); */
376
377 d->xferp->data_in_len -= len2;
378 n = malloc(d->xferp->data_in_len);
379 if (n == NULL) {
380 fprintf(stderr, "out of memory"
381 " in dev_asc\n");
382 exit(1);
383 }
384 memcpy(n, d->xferp->data_in + len2,
385 d->xferp->data_in_len);
386 free(d->xferp->data_in);
387 d->xferp->data_in = n;
388
389 len = len2;
390 }
391
392 len = 0;
393
394 d->reg_ro[NCR_TCL] = len & 255;
395 d->reg_ro[NCR_TCM] = (len >> 8) & 255;
396
397 /* Successful DMA transfer: */
398 d->reg_ro[NCR_STAT] |= NCRSTAT_TC;
399 }
400 }
401 } else if (d->cur_phase == PHASE_DATA_OUT) {
402 /* Data going from the controller to an external device: */
403 if (!dmaflag) {
404 fatal("TODO.......asdgasin\n");
405 } else {
406 /* Copy data from DMA to data_out: */
407 int len = d->xferp->data_out_len;
408 int len2 = d->reg_wo[NCR_TCL] +
409 d->reg_wo[NCR_TCM] * 256;
410 if (len2 == 0)
411 len2 = 65536;
412
413 if (len == 0) {
414 fprintf(stderr, "d->xferp->data_out_len == "
415 "0 ?\n");
416 exit(1);
417 }
418
419 /* TODO: Make sure that len2 doesn't go outside
420 of the dma memory? */
421
422 /* fatal(" data out offset=%5i len=%5i\n",
423 d->xferp->data_out_offset, len2); */
424
425 if (d->xferp->data_out_offset + len2 >
426 d->xferp->data_out_len) {
427 len2 = d->xferp->data_out_len -
428 d->xferp->data_out_offset;
429 }
430
431 /*
432 * Are we using an external DMA controller? Then use
433 * it. Otherwise place the data in the DECstation
434 * 5000/200 built-in DMA region.
435 */
436 if (d->xferp->data_out == NULL) {
437 scsi_transfer_allocbuf(&d->xferp->data_out_len,
438 &d->xferp->data_out, len, 0);
439
440 if (d->dma_controller != NULL)
441 d->dma_controller(
442 d->dma_controller_data,
443 d->xferp->data_out,
444 len2, 0);
445 else
446 memcpy(d->xferp->data_out,
447 d->dma + (d->dma_address_reg &
448 (ASC_DMA_SIZE-1)), len2);
449 d->xferp->data_out_offset = len2;
450 } else {
451 /* Continuing a multi-transfer: */
452 if (d->dma_controller != NULL)
453 d->dma_controller(
454 d->dma_controller_data,
455 d->xferp->data_out +
456 d->xferp->data_out_offset,
457 len2, 0);
458 else
459 memcpy(d->xferp->data_out +
460 d->xferp->data_out_offset,
461 d->dma + (d->dma_address_reg &
462 (ASC_DMA_SIZE-1)), len2);
463 d->xferp->data_out_offset += len2;
464 }
465
466 /* If the disk wants more than we're DMAing,
467 then this is a multitransfer: */
468 if (d->xferp->data_out_offset !=
469 d->xferp->data_out_len) {
470 if (!quiet_mode)
471 debug("[ asc: data_out, multitransfer "
472 "len = %i, len2 = %i ]\n",
473 (int)len, (int)len2);
474 if (d->xferp->data_out_offset >
475 d->xferp->data_out_len)
476 fatal("[ asc data_out dma: too much?"
477 " ]\n");
478 else
479 all_done = 0;
480 }
481
482 #ifdef ASC_DEBUG
483 if (!quiet_mode) {
484 int i;
485 for (i=0; i<len; i++)
486 debug(" %02x", d->xferp->data_out[i]);
487 }
488 #endif
489 len = 0;
490
491 d->reg_ro[NCR_TCL] = len & 255;
492 d->reg_ro[NCR_TCM] = (len >> 8) & 255;
493
494 /* Successful DMA transfer: */
495 d->reg_ro[NCR_STAT] |= NCRSTAT_TC;
496 }
497 } else if (d->cur_phase == PHASE_MSG_OUT) {
498 if (!quiet_mode)
499 debug("MSG OUT: ");
500 /* Data going from the controller to an external device: */
501 if (!dmaflag) {
502 /* There should already be one byte in msg_out, so we
503 just extend the message: */
504 int oldlen = d->xferp->msg_out_len;
505 int newlen;
506
507 if (oldlen != 1) {
508 fatal(" (PHASE OUT MSG len == %i, "
509 "should be 1)\n", oldlen);
510 }
511
512 newlen = oldlen + d->n_bytes_in_fifo;
513 d->xferp->msg_out = realloc(d->xferp->msg_out, newlen);
514 d->xferp->msg_out_len = newlen;
515 if (d->xferp->msg_out == NULL) {
516 fprintf(stderr, "out of memory realloc'ing "
517 "msg_out\n");
518 exit(1);
519 }
520
521 i = oldlen;
522 while (d->fifo_in != d->fifo_out) {
523 ch = dev_asc_fifo_read(d);
524 d->xferp->msg_out[i++] = ch;
525 #ifdef ASC_DEBUG
526 debug("0x%02x ", ch);
527 #endif
528 }
529
530 #ifdef MACH
531 /* Super-ugly hack for Mach/PMAX: TODO: make nicer */
532 if (d->xferp->msg_out_len == 6 &&
533 (d->xferp->msg_out[0] == 0x80 ||
534 d->xferp->msg_out[0] == 0xc0) &&
535 d->xferp->msg_out[1] == 0x01 &&
536 d->xferp->msg_out[2] == 0x03 &&
537 d->xferp->msg_out[3] == 0x01 &&
538 d->xferp->msg_out[4] == 0x32 &&
539 d->xferp->msg_out[5] == 0x0f) {
540 fatal(" !! Mach/PMAX hack !! ");
541 all_done = 0;
542 d->cur_phase = PHASE_MSG_IN;
543 }
544 #endif
545 } else {
546 /* Copy data from DMA to msg_out: */
547 fatal("[ DMA MSG OUT: xxx TODO! ]");
548 /* TODO */
549 res = 0;
550 }
551 } else if (d->cur_phase == PHASE_MSG_IN) {
552 if (!quiet_mode)
553 debug(" MSG IN");
554 fatal("[ MACH HACK! ]");
555 /* Super-ugly hack for Mach/PMAX: TODO: make nicer */
556 dev_asc_fifo_write(d, 0x07);
557 d->cur_phase = PHASE_COMMAND;
558 all_done = 0;
559 } else if (d->cur_phase == PHASE_COMMAND) {
560 if (!quiet_mode)
561 debug(" COMMAND ==> select ");
562 res = dev_asc_select(cpu, d, d->reg_ro[NCR_CFG1] & 7,
563 d->reg_wo[NCR_SELID] & 7, dmaflag, 0);
564 return res;
565 } else {
566 fatal("!!! TODO: unknown/unimplemented phase "
567 "in transfer: %i\n", d->cur_phase);
568 }
569
570 /* Redo the command if data was just sent using DATA_OUT: */
571 if (d->cur_phase == PHASE_DATA_OUT) {
572 res = diskimage_scsicommand(cpu, d->reg_wo[NCR_SELID] & 7,
573 DISKIMAGE_SCSI, d->xferp);
574 }
575
576 if (all_done) {
577 if (d->cur_phase == PHASE_MSG_OUT)
578 d->cur_phase = PHASE_COMMAND;
579 else
580 d->cur_phase = PHASE_STATUS;
581 }
582
583 /*
584 * Cause an interrupt after the transfer:
585 *
586 * NOTE: Earlier I had this in here as well:
587 * d->reg_ro[NCR_INTR] |= NCRINTR_FC;
588 * but Linux/DECstation and OpenBSD/pmax seems to choke on that.
589 */
590 d->reg_ro[NCR_STAT] |= NCRSTAT_INT;
591 d->reg_ro[NCR_INTR] |= NCRINTR_BS;
592 d->reg_ro[NCR_STAT] = (d->reg_ro[NCR_STAT] & ~7) | d->cur_phase;
593 d->reg_ro[NCR_STEP] = (d->reg_ro[NCR_STEP] & ~7) | 4; /* 4? */
594
595 if (!quiet_mode)
596 debug("}");
597 return res;
598 }
599
600
601 /*
602 * dev_asc_select():
603 *
604 * Select a SCSI device, send msg bytes (if any), and send command bytes.
605 * (Call diskimage_scsicommand() to handle the command.)
606 *
607 * Return value: 1 if ok, 0 on error.
608 */
609 static int dev_asc_select(struct cpu *cpu, struct asc_data *d, int from_id,
610 int to_id, int dmaflag, int n_messagebytes)
611 {
612 int ok, len, i, ch;
613
614 if (!quiet_mode)
615 debug(" { SELECT id %i: ", to_id);
616
617 /*
618 * Message bytes, if any:
619 */
620 if (!quiet_mode)
621 debug("msg:");
622
623 if (n_messagebytes > 0) {
624 scsi_transfer_allocbuf(&d->xferp->msg_out_len,
625 &d->xferp->msg_out, n_messagebytes, 0);
626
627 i = 0;
628 while (n_messagebytes-- > 0) {
629 int ch = dev_asc_fifo_read(d);
630 if (!quiet_mode)
631 debug(" %02x", ch);
632 d->xferp->msg_out[i++] = ch;
633 }
634
635 if ((d->xferp->msg_out[0] & 0x7) != 0x00) {
636 debug(" (LUNs not implemented yet: 0x%02x) }",
637 d->xferp->msg_out[0]);
638 return 0;
639 }
640
641 if (((d->xferp->msg_out[0] & ~0x7) != 0xc0) &&
642 ((d->xferp->msg_out[0] & ~0x7) != 0x80)) {
643 fatal(" (Unimplemented msg out: 0x%02x) }",
644 d->xferp->msg_out[0]);
645 return 0;
646 }
647
648 if (d->xferp->msg_out_len > 1) {
649 fatal(" (Long msg out, not implemented yet;"
650 " len=%i) }", d->xferp->msg_out_len);
651 return 0;
652 }
653 } else {
654 if (!quiet_mode)
655 debug(" none");
656 }
657
658 /* Special case: SELATNS (with STOP sequence): */
659 if (d->cur_phase == PHASE_MSG_OUT) {
660 if (!quiet_mode)
661 debug(" MSG OUT DEBUG");
662 if (d->xferp->msg_out_len != 1) {
663 fatal(" (SELATNS: msg out len == %i, should be 1)",
664 d->xferp->msg_out_len);
665 return 0;
666 }
667
668 /* d->cur_phase = PHASE_COMMAND; */
669
670 /* According to the LSI manual: */
671 d->reg_ro[NCR_STAT] |= NCRSTAT_INT;
672 d->reg_ro[NCR_INTR] |= NCRINTR_FC;
673 d->reg_ro[NCR_INTR] |= NCRINTR_BS;
674 d->reg_ro[NCR_STAT] = (d->reg_ro[NCR_STAT] & ~7) | d->cur_phase;
675 d->reg_ro[NCR_STEP] = (d->reg_ro[NCR_STEP] & ~7) | 1;
676
677 if (!quiet_mode)
678 debug("}");
679 return 1;
680 }
681
682 /*
683 * Command bytes:
684 */
685 if (!quiet_mode)
686 debug(", cmd: ");
687
688 if (!dmaflag) {
689 if (!quiet_mode)
690 debug("[non-DMA] ");
691
692 scsi_transfer_allocbuf(&d->xferp->cmd_len,
693 &d->xferp->cmd, d->n_bytes_in_fifo, 0);
694
695 i = 0;
696 while (d->fifo_in != d->fifo_out) {
697 ch = dev_asc_fifo_read(d);
698 d->xferp->cmd[i++] = ch;
699 if (!quiet_mode)
700 debug("%02x ", ch);
701 }
702 } else {
703 if (!quiet_mode)
704 debug("[DMA] ");
705 len = d->reg_wo[NCR_TCL] + d->reg_wo[NCR_TCM] * 256;
706 if (len == 0)
707 len = 65536;
708
709 scsi_transfer_allocbuf(&d->xferp->cmd_len,
710 &d->xferp->cmd, len, 0);
711
712 for (i=0; i<len; i++) {
713 int ofs = d->dma_address_reg + i;
714 ch = d->dma[ofs & (ASC_DMA_SIZE-1)];
715 d->xferp->cmd[i] = ch;
716 if (!quiet_mode)
717 debug("%02x ", ch);
718 }
719
720 d->reg_ro[NCR_TCL] = len & 255;
721 d->reg_ro[NCR_TCM] = (len >> 8) & 255;
722
723 d->reg_ro[NCR_STAT] |= NCRSTAT_TC;
724 }
725
726 /*
727 * Call the SCSI device to perform the command:
728 */
729 ok = diskimage_scsicommand(cpu, to_id, DISKIMAGE_SCSI, d->xferp);
730
731
732 /* Cause an interrupt: */
733 d->reg_ro[NCR_STAT] |= NCRSTAT_INT;
734 d->reg_ro[NCR_INTR] |= NCRINTR_FC;
735 d->reg_ro[NCR_INTR] |= NCRINTR_BS;
736
737 if (ok == 2)
738 d->cur_phase = PHASE_DATA_OUT;
739 else if (d->xferp->data_in != NULL)
740 d->cur_phase = PHASE_DATA_IN;
741 else
742 d->cur_phase = PHASE_STATUS;
743
744 d->reg_ro[NCR_STAT] = (d->reg_ro[NCR_STAT] & ~7) | d->cur_phase;
745 d->reg_ro[NCR_STEP] = (d->reg_ro[NCR_STEP] & ~7) | 4; /* DONE (?) */
746
747 if (!quiet_mode)
748 debug("}");
749
750 return ok;
751 }
752
753
754 /*
755 * dev_asc_address_reg_access():
756 */
757 DEVICE_ACCESS(asc_address_reg)
758 {
759 struct asc_data *d = extra;
760
761 if (relative_addr + len > 4)
762 return 0;
763
764 if (writeflag==MEM_READ) {
765 memcpy(data, d->dma_address_reg_memory + relative_addr, len);
766 } else {
767 memcpy(d->dma_address_reg_memory + relative_addr, data, len);
768 }
769
770 return 1;
771 }
772
773
774 /*
775 * dev_asc_dma_access():
776 */
777 DEVICE_ACCESS(asc_dma)
778 {
779 struct asc_data *d = extra;
780
781 if (writeflag==MEM_READ) {
782 memcpy(data, d->dma + relative_addr, len);
783 #ifdef ASC_DEBUG
784 {
785 int i;
786 debug("[ asc: read from DMA addr 0x%05x:",
787 (int) relative_addr);
788 for (i=0; i<len; i++)
789 debug(" %02x", data[i]);
790 debug(" ]\n");
791 }
792 #endif
793
794 /* Don't return the common way, as that
795 would overwrite data. */
796 return 1;
797 } else {
798 memcpy(d->dma + relative_addr, data, len);
799 #ifdef ASC_DEBUG
800 {
801 int i;
802 debug("[ asc: write to DMA addr 0x%05x:",
803 (int) relative_addr);
804 for (i=0; i<len; i++)
805 debug(" %02x", data[i]);
806 debug(" ]\n");
807 }
808 #endif
809 /* Quick return. */
810 return 1;
811 }
812 }
813
814
815 /*
816 * dev_asc_access():
817 */
818 DEVICE_ACCESS(asc)
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 if (writeflag == MEM_WRITE)
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, DISKIMAGE_SCSI);
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_address_reg_memory = malloc(machine->arch_pagesize);
1265 d->dma = malloc(ASC_DMA_SIZE);
1266 if (d->dma == NULL || d->dma_address_reg_memory == NULL) {
1267 fprintf(stderr, "out of memory\n");
1268 exit(1);
1269 }
1270 memset(d->dma_address_reg_memory, 0, machine->arch_pagesize);
1271 memset(d->dma, 0, ASC_DMA_SIZE);
1272
1273 d->dma_controller = dma_controller;
1274 d->dma_controller_data = dma_controller_data;
1275
1276 memory_device_register(mem, "asc", baseaddr,
1277 mode == DEV_ASC_PICA? DEV_ASC_PICA_LENGTH : DEV_ASC_DEC_LENGTH,
1278 dev_asc_access, d, DM_DEFAULT, NULL);
1279
1280 if (mode == DEV_ASC_DEC) {
1281 memory_device_register(mem, "asc_dma_address_reg",
1282 baseaddr + 0x40000, 4096, dev_asc_address_reg_access, d,
1283 DM_DYNTRANS_OK | DM_DYNTRANS_WRITE_OK,
1284 (unsigned char *)&d->dma_address_reg_memory[0]);
1285 memory_device_register(mem, "asc_dma", baseaddr + 0x80000,
1286 ASC_DMA_SIZE, dev_asc_dma_access, d,
1287 DM_DYNTRANS_OK | DM_DYNTRANS_WRITE_OK, d->dma);
1288 }
1289
1290 machine_add_tickfunction(machine, dev_asc_tick, d, ASC_TICK_SHIFT);
1291 }
1292

  ViewVC Help
Powered by ViewVC 1.1.26