--- trunk/src/devices/dev_asc.c 2007/10/08 16:18:11 6 +++ trunk/src/devices/dev_asc.c 2007/10/08 16:21:17 34 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2005 Anders Gavare. All rights reserved. + * Copyright (C) 2003-2007 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -25,10 +25,9 @@ * SUCH DAMAGE. * * - * $Id: dev_asc.c,v 1.71 2005/05/15 01:55:50 debug Exp $ + * $Id: dev_asc.c,v 1.84 2006/12/31 21:35:26 debug Exp $ * - * 'asc' SCSI controller for some DECstation/DECsystem models, and - * for PICA-61. + * 'asc' SCSI controller for some DECstation/DECsystem models and PICA-61. * * Supposed to support SCSI-1 and SCSI-2. I've not yet found any docs * on NCR53C9X, so I'll try to implement this device from LSI53CF92A docs @@ -50,6 +49,10 @@ * TODO: This module needs a clean-up, and some testing to see that * it works will all OSes that might use it (NetBSD, OpenBSD, * Ultrix, Linux, Mach, OSF/1, Sprite, ...) + * + * Running Linux/DECstation 2.4.26 with no scsi disks attached causes + * a warning message to be printed by Linux. (Whether this is a bug, + * is is the way it works on real hardware, I don't know.) */ #include @@ -71,6 +74,8 @@ /* #define ASC_FULL_REGISTER_ACCESS_DEBUG */ /* static int quiet_mode = 0; */ +#define ASC_TICK_SHIFT 15 + extern int quiet_mode; @@ -90,12 +95,14 @@ /* The controller's SCSI id: */ #define ASC_SCSI_ID 7 +#define ASC_DMA_SIZE (128*1024) + struct asc_data { int mode; void *turbochannel; - int irq_nr; - int irq_caused_last_time; + struct interrupt irq; + int irq_asserted; /* Current state and transfer: */ int cur_state; @@ -118,9 +125,8 @@ /* Built-in DMA memory (for DECstation 5000/200): */ uint32_t dma_address_reg; - unsigned char dma_address_reg_memory[4096]; - /* NOTE: full page, for bintrans */ - unsigned char dma[128 * 1024]; + unsigned char *dma_address_reg_memory; + unsigned char *dma; void *dma_controller_data; size_t (*dma_controller)(void *dma_controller_data, @@ -146,18 +152,15 @@ int to_id, int dmaflag, int n_messagebytes); -/* - * dev_asc_tick(): - * - * This function is called "every now and then" from the CPU - * main loop. - */ -void dev_asc_tick(struct cpu *cpu, void *extra) +DEVICE_TICK(asc) { struct asc_data *d = extra; + int new_assert = d->reg_ro[NCR_STAT] & NCRSTAT_INT; + + if (new_assert && !d->irq_asserted) + INTERRUPT_ASSERT(d->irq); - if (d->reg_ro[NCR_STAT] & NCRSTAT_INT) - cpu_interrupt(cpu, d->irq_nr); + d->irq_asserted = new_assert; } @@ -306,8 +309,8 @@ fatal("no incoming DMA data?\n"); res = 0; } else { - int len = d->xferp->data_in_len; - int len2 = d->reg_wo[NCR_TCL] + + size_t len = d->xferp->data_in_len; + size_t len2 = d->reg_wo[NCR_TCL] + d->reg_wo[NCR_TCM] * 256; if (len2 == 0) len2 = 65536; @@ -319,14 +322,14 @@ /* TODO: check len2 in a similar way? */ if (len + (d->dma_address_reg & - ((sizeof(d->dma)-1))) > sizeof(d->dma)) - len = sizeof(d->dma) - + (ASC_DMA_SIZE-1)) > ASC_DMA_SIZE) + len = ASC_DMA_SIZE - (d->dma_address_reg & - ((sizeof(d->dma)-1))); + (ASC_DMA_SIZE-1)); if (len2 > len) { memset(d->dma + (d->dma_address_reg & - ((sizeof(d->dma)-1))), 0, len2); + (ASC_DMA_SIZE-1)), 0, len2); len2 = len; } @@ -352,7 +355,7 @@ len2, 1); else memcpy(d->dma + (d->dma_address_reg & - ((sizeof(d->dma)-1))), + (ASC_DMA_SIZE-1)), d->xferp->data_in, len2); if (d->xferp->data_in_len > len2) { @@ -439,7 +442,7 @@ else memcpy(d->xferp->data_out, d->dma + (d->dma_address_reg & - ((sizeof(d->dma)-1))), len2); + (ASC_DMA_SIZE-1)), len2); d->xferp->data_out_offset = len2; } else { /* Continuing a multi-transfer: */ @@ -453,7 +456,7 @@ memcpy(d->xferp->data_out + d->xferp->data_out_offset, d->dma + (d->dma_address_reg & - ((sizeof(d->dma)-1))), len2); + (ASC_DMA_SIZE-1)), len2); d->xferp->data_out_offset += len2; } @@ -705,7 +708,7 @@ for (i=0; idma_address_reg + i; - ch = d->dma[ofs & (sizeof(d->dma)-1)]; + ch = d->dma[ofs & (ASC_DMA_SIZE-1)]; d->xferp->cmd[i] = ch; if (!quiet_mode) debug("%02x ", ch); @@ -745,12 +748,7 @@ } -/* - * dev_asc_address_reg_access(): - */ -int dev_asc_address_reg_access(struct cpu *cpu, struct memory *mem, - uint64_t relative_addr, unsigned char *data, size_t len, - int writeflag, void *extra) +DEVICE_ACCESS(asc_address_reg) { struct asc_data *d = extra; @@ -767,12 +765,7 @@ } -/* - * dev_asc_dma_access(): - */ -int dev_asc_dma_access(struct cpu *cpu, struct memory *mem, - uint64_t relative_addr, unsigned char *data, size_t len, - int writeflag, void *extra) +DEVICE_ACCESS(asc_dma) { struct asc_data *d = extra; @@ -810,12 +803,7 @@ } -/* - * dev_asc_access(): - */ -int dev_asc_access(struct cpu *cpu, struct memory *mem, - uint64_t relative_addr, unsigned char *data, size_t len, - int writeflag, void *extra) +DEVICE_ACCESS(asc) { int regnr; struct asc_data *d = extra; @@ -823,8 +811,8 @@ int n_messagebytes = 0; uint64_t idata = 0, odata = 0; - - idata = memory_readmax64(cpu, data, len); + if (writeflag == MEM_WRITE) + idata = memory_readmax64(cpu, data, len); #if 0 /* Debug stuff useful when trying to make dev_asc compatible @@ -1211,7 +1199,8 @@ d->reg_ro[NCR_STAT] = PHASE_COMMAND; } - cpu_interrupt_ack(cpu, d->irq_nr); + INTERRUPT_DEASSERT(d->irq); + d->irq_asserted = 0; } if (regnr == NCR_CFG1) { @@ -1241,8 +1230,7 @@ * Register an 'asc' device. */ void dev_asc_init(struct machine *machine, struct memory *mem, - uint64_t baseaddr, int irq_nr, void *turbochannel, - int mode, + uint64_t baseaddr, char *irq_path, void *turbochannel, int mode, size_t (*dma_controller)(void *dma_controller_data, unsigned char *data, size_t len, int writeflag), void *dma_controller_data) @@ -1255,30 +1243,39 @@ exit(1); } memset(d, 0, sizeof(struct asc_data)); - d->irq_nr = irq_nr; + + INTERRUPT_CONNECT(irq_path, d->irq); d->turbochannel = turbochannel; d->mode = mode; d->reg_ro[NCR_CFG3] = NCRF9XCFG3_CDB; + d->dma_address_reg_memory = malloc(machine->arch_pagesize); + d->dma = malloc(ASC_DMA_SIZE); + if (d->dma == NULL || d->dma_address_reg_memory == NULL) { + fprintf(stderr, "out of memory\n"); + exit(1); + } + memset(d->dma_address_reg_memory, 0, machine->arch_pagesize); + memset(d->dma, 0, ASC_DMA_SIZE); + d->dma_controller = dma_controller; d->dma_controller_data = dma_controller_data; memory_device_register(mem, "asc", baseaddr, - mode == DEV_ASC_PICA? - DEV_ASC_PICA_LENGTH : DEV_ASC_DEC_LENGTH, - dev_asc_access, d, MEM_DEFAULT, NULL); + mode == DEV_ASC_PICA? DEV_ASC_PICA_LENGTH : DEV_ASC_DEC_LENGTH, + dev_asc_access, d, DM_DEFAULT, NULL); if (mode == DEV_ASC_DEC) { memory_device_register(mem, "asc_dma_address_reg", baseaddr + 0x40000, 4096, dev_asc_address_reg_access, d, - MEM_BINTRANS_OK | MEM_BINTRANS_WRITE_OK, - d->dma_address_reg_memory); + DM_DYNTRANS_OK | DM_DYNTRANS_WRITE_OK, + (unsigned char *)&d->dma_address_reg_memory[0]); memory_device_register(mem, "asc_dma", baseaddr + 0x80000, - 128*1024, dev_asc_dma_access, d, - MEM_BINTRANS_OK | MEM_BINTRANS_WRITE_OK, d->dma); + ASC_DMA_SIZE, dev_asc_dma_access, d, + DM_DYNTRANS_OK | DM_DYNTRANS_WRITE_OK, d->dma); } - machine_add_tickfunction(machine, dev_asc_tick, d, 15); + machine_add_tickfunction(machine, dev_asc_tick, d, ASC_TICK_SHIFT, 0.0); }