NCR 5380-based changes of the day (January 12, 2025)
1. Sanity check for the SCSI temp_buffer if it's allocated or not. 2. Data reads and writes in non-DMA mode should be accessible only when DMA mode is Idle (as in, no DMA at all, whereas DMA mode will go to the SCSI controllers' callbacks).
This commit is contained in:
@@ -197,20 +197,29 @@ ncr5380_bus_read(ncr_t *ncr)
|
||||
phase = (ncr->cur_bus & SCSI_PHASE_MESSAGE_IN);
|
||||
|
||||
if (phase == SCSI_PHASE_DATA_IN) {
|
||||
ncr->tx_data = dev->sc->temp_buffer[ncr->data_pos++];
|
||||
ncr->state = STATE_DATAIN;
|
||||
ncr->cur_bus = (ncr->cur_bus & ~BUS_DATAMASK) | BUS_SETDATA(ncr->tx_data) | BUS_DBP;
|
||||
if (ncr->dma_mode == DMA_IDLE) {
|
||||
ncr5380_log("Phase Data In.\n");
|
||||
if ((dev->sc != NULL) && (dev->sc->temp_buffer != NULL))
|
||||
ncr->tx_data = dev->sc->temp_buffer[ncr->data_pos++];
|
||||
|
||||
ncr->state = STATE_DATAIN;
|
||||
ncr->cur_bus = (ncr->cur_bus & ~BUS_DATAMASK) | BUS_SETDATA(ncr->tx_data) | BUS_DBP;
|
||||
}
|
||||
} else if (phase == SCSI_PHASE_DATA_OUT) {
|
||||
if (ncr->new_phase & BUS_IDLE) {
|
||||
ncr->state = STATE_IDLE;
|
||||
ncr->cur_bus &= ~BUS_BSY;
|
||||
} else
|
||||
ncr->state = STATE_DATAOUT;
|
||||
} else {
|
||||
if (ncr->dma_mode == DMA_IDLE)
|
||||
ncr->state = STATE_DATAOUT;
|
||||
}
|
||||
} else if (phase == SCSI_PHASE_STATUS) {
|
||||
ncr5380_log("Phase Status.\n");
|
||||
ncr->cur_bus |= BUS_REQ;
|
||||
ncr->state = STATE_STATUS;
|
||||
ncr->cur_bus = (ncr->cur_bus & ~BUS_DATAMASK) | BUS_SETDATA(dev->status) | BUS_DBP;
|
||||
} else if (phase == SCSI_PHASE_MESSAGE_IN) {
|
||||
ncr5380_log("Phase Message In.\n");
|
||||
ncr->state = STATE_MESSAGEIN;
|
||||
ncr->cur_bus = (ncr->cur_bus & ~BUS_DATAMASK) | BUS_SETDATA(0) | BUS_DBP;
|
||||
} else if (phase == SCSI_PHASE_MESSAGE_OUT) {
|
||||
@@ -335,19 +344,22 @@ ncr5380_bus_update(ncr_t *ncr, int bus)
|
||||
if ((bus & BUS_ACK) && !(ncr->bus_in & BUS_ACK)) {
|
||||
if (ncr->data_pos >= dev->buffer_length) {
|
||||
ncr->cur_bus &= ~BUS_REQ;
|
||||
ncr5380_log("CMD Phase1 DataIn.\n");
|
||||
scsi_device_command_phase1(dev);
|
||||
ncr->new_phase = SCSI_PHASE_STATUS;
|
||||
ncr->wait_data = 4;
|
||||
ncr->wait_complete = 8;
|
||||
} else {
|
||||
ncr->tx_data = dev->sc->temp_buffer[ncr->data_pos++];
|
||||
if ((dev->sc != NULL) && (dev->sc->temp_buffer != NULL))
|
||||
ncr->tx_data = dev->sc->temp_buffer[ncr->data_pos++];
|
||||
|
||||
ncr->cur_bus = (ncr->cur_bus & ~BUS_DATAMASK) | BUS_SETDATA(ncr->tx_data) | BUS_DBP | BUS_REQ;
|
||||
if (ncr->dma_mode == DMA_IDLE) { /*If a data in command that is not read 6/10 has been issued*/
|
||||
ncr->data_wait |= 1;
|
||||
ncr5380_log("DMA mode idle in\n");
|
||||
ncr5380_log("DMA mode idle IN=%d.\n", ncr->data_pos);
|
||||
ncr->timer(ncr->priv, ncr->period);
|
||||
} else {
|
||||
ncr5380_log("DMA mode IN.\n");
|
||||
ncr5380_log("DMA mode IN=%d.\n", ncr->data_pos);
|
||||
ncr->clear_req = 3;
|
||||
}
|
||||
|
||||
@@ -359,7 +371,8 @@ ncr5380_bus_update(ncr_t *ncr, int bus)
|
||||
case STATE_DATAOUT:
|
||||
dev = &scsi_devices[ncr->bus][ncr->target_id];
|
||||
if ((bus & BUS_ACK) && !(ncr->bus_in & BUS_ACK)) {
|
||||
dev->sc->temp_buffer[ncr->data_pos++] = BUS_GETDATA(bus);
|
||||
if ((dev->sc != NULL) && (dev->sc->temp_buffer != NULL))
|
||||
dev->sc->temp_buffer[ncr->data_pos++] = BUS_GETDATA(bus);
|
||||
|
||||
if (ncr->data_pos >= dev->buffer_length) {
|
||||
ncr->cur_bus &= ~BUS_REQ;
|
||||
@@ -439,12 +452,12 @@ ncr5380_write(uint16_t port, uint8_t val, ncr_t *ncr)
|
||||
|
||||
switch (port & 7) {
|
||||
case 0: /* Output data register */
|
||||
ncr5380_log("Write: Output data register, val = %02x\n", val);
|
||||
ncr5380_log("[%04X:%08X]: Write: Output data register, val=%02x\n", CS, cpu_state.pc, val);
|
||||
ncr->output_data = val;
|
||||
break;
|
||||
|
||||
case 1: /* Initiator Command Register */
|
||||
ncr5380_log("Write: Initiator command register\n");
|
||||
ncr5380_log("[%04X:%08X]: Write: Initiator command register, val=%02x.\n", CS, cpu_state.pc, val);
|
||||
if ((val & 0x80) && !(ncr->icr & 0x80)) {
|
||||
ncr5380_log("Resetting the 5380\n");
|
||||
ncr5380_reset(ncr);
|
||||
@@ -465,7 +478,7 @@ ncr5380_write(uint16_t port, uint8_t val, ncr_t *ncr)
|
||||
break;
|
||||
|
||||
case 3: /* Target Command Register */
|
||||
ncr5380_log("Write: Target Command register\n");
|
||||
ncr5380_log("Write: Target Command register, val=%02x.\n", val);
|
||||
ncr->tcr = val;
|
||||
break;
|
||||
|
||||
@@ -482,7 +495,7 @@ ncr5380_write(uint16_t port, uint8_t val, ncr_t *ncr)
|
||||
break;
|
||||
|
||||
case 7: /* start DMA Initiator Receive */
|
||||
ncr5380_log("Write: start DMA initiator receive register, dma? = %02x\n", ncr->mode & MODE_DMA);
|
||||
ncr5380_log("[%04X:%08X]: Write: start DMA initiator receive register, dma? = %02x\n", CS, cpu_state.pc, ncr->mode & MODE_DMA);
|
||||
/*a Read 6/10 has occurred, start the timer when the block count is loaded*/
|
||||
ncr->dma_mode = DMA_INITIATOR_RECEIVE;
|
||||
if (ncr->dma_initiator_receive_ext)
|
||||
@@ -510,13 +523,13 @@ ncr5380_read(uint16_t port, ncr_t *ncr)
|
||||
ncr5380_log("Read: Current SCSI data register\n");
|
||||
if (ncr->icr & ICR_DBP) {
|
||||
/*Return the data from the output register if on data bus phase from ICR*/
|
||||
ncr5380_log("Data Bus Phase, ret = %02x\n", ncr->output_data);
|
||||
ret = ncr->output_data;
|
||||
ncr5380_log("[%04X:%08X]: Data Bus Phase, ret=%02x, clearreq=%d, waitdata=%x.\n", CS, cpu_state.pc, ret, ncr->clear_req, ncr->wait_data);
|
||||
} else {
|
||||
/*Return the data from the SCSI bus*/
|
||||
ncr5380_bus_read(ncr);
|
||||
ncr5380_log("NCR GetData=%02x\n", BUS_GETDATA(ncr->cur_bus));
|
||||
ret = BUS_GETDATA(ncr->cur_bus);
|
||||
ncr5380_log("[%04X:%08X]: NCR Get SCSI bus data=%02x.\n", CS, cpu_state.pc, ret);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -595,7 +608,9 @@ ncr5380_read(uint16_t port, ncr_t *ncr)
|
||||
break;
|
||||
|
||||
case 6:
|
||||
ret = ncr->tx_data;
|
||||
ncr5380_log("Read: Input Data.\n");
|
||||
ncr5380_bus_read(ncr);
|
||||
ret = BUS_GETDATA(ncr->cur_bus);
|
||||
break;
|
||||
|
||||
case 7: /* reset Parity/Interrupt */
|
||||
|
||||
@@ -148,6 +148,12 @@ ncr53c400_write(uint32_t addr, uint8_t val, void *priv)
|
||||
ncr400->busy = 1;
|
||||
if (!(ncr->mode & MODE_MONITOR_BUSY) && ((scsi_device_get_callback(dev) > 0.0)))
|
||||
timer_on_auto(&ncr400->timer, ncr->period / 250.0);
|
||||
else if ((ncr->mode & MODE_MONITOR_BUSY) && !ncr->wait_data) {
|
||||
if (scsi_device_get_callback(dev) > 0.0)
|
||||
timer_on_auto(&ncr400->timer, 100.0);
|
||||
else
|
||||
timer_on_auto(&ncr400->timer, 40.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -181,13 +187,14 @@ ncr53c400_write(uint32_t addr, uint8_t val, void *priv)
|
||||
if ((ncr->mode & MODE_DMA) && (dev->buffer_length > 0)) {
|
||||
memset(ncr400->buffer, 0, MIN(128, dev->buffer_length));
|
||||
if (ncr->mode & MODE_MONITOR_BUSY)
|
||||
timer_on_auto(&ncr400->timer, ncr->period);
|
||||
timer_on_auto(&ncr400->timer, (ncr->period / 4.0) * 3.0);
|
||||
else if (scsi_device_get_callback(dev) > 0.0)
|
||||
timer_on_auto(&ncr400->timer, 40.0);
|
||||
else
|
||||
timer_on_auto(&ncr400->timer, ncr->period);
|
||||
|
||||
ncr53c400_log("DMA timer on=%02x, callback=%lf, scsi buflen=%d, waitdata=%d, waitcomplete=%d, clearreq=%d, datawait=%d, enabled=%d.\n", ncr->mode & MODE_MONITOR_BUSY, scsi_device_get_callback(dev), dev->buffer_length, ncr->wait_complete, ncr->wait_data, ncr->wait_complete, ncr->clear_req, ncr->data_wait, timer_is_enabled(&ncr400->timer));
|
||||
ncr53c400_log("DMA timer on=%02x, callback=%lf, scsi buflen=%d, waitdata=%d, waitcomplete=%d, clearreq=%d, datawait=%d, enabled=%d.\n",
|
||||
ncr->mode & MODE_MONITOR_BUSY, scsi_device_get_callback(dev), dev->buffer_length, ncr->wait_data, ncr->wait_complete, ncr->clear_req, ncr->data_wait, timer_is_enabled(&ncr400->timer));
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -244,6 +251,12 @@ ncr53c400_read(uint32_t addr, void *priv)
|
||||
ncr53c400_log("Transfer busy read, status = %02x.\n", ncr400->status_ctrl);
|
||||
if (!(ncr->mode & MODE_MONITOR_BUSY) && (scsi_device_get_callback(dev) > 0.0))
|
||||
timer_on_auto(&ncr400->timer, ncr->period / 250.0);
|
||||
else if ((ncr->mode & MODE_MONITOR_BUSY) && !ncr->wait_data) {
|
||||
if (scsi_device_get_callback(dev) > 0.0)
|
||||
timer_on_auto(&ncr400->timer, 100.0);
|
||||
else
|
||||
timer_on_auto(&ncr400->timer, 40.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -397,16 +410,20 @@ t130b_in(uint16_t port, void *priv)
|
||||
}
|
||||
|
||||
static void
|
||||
ncr53c400_dma_mode_ext(void *priv, UNUSED(void *ext_priv))
|
||||
ncr53c400_dma_mode_ext(void *priv, void *ext_priv)
|
||||
{
|
||||
ncr_t *ncr = (ncr_t *) priv;
|
||||
ncr53c400_t *ncr400 = (ncr53c400_t *) ext_priv;
|
||||
ncr_t *ncr = (ncr_t *) priv;
|
||||
|
||||
/*When a pseudo-DMA transfer has completed (Send or Initiator Receive), mark it as complete and idle the status*/
|
||||
if (!(ncr->mode & MODE_DMA)) {
|
||||
ncr53c400_log("No DMA mode\n");
|
||||
ncr->tcr &= ~TCR_LAST_BYTE_SENT;
|
||||
ncr->isr &= ~STATUS_END_OF_DMA;
|
||||
ncr->dma_mode = DMA_IDLE;
|
||||
ncr53c400_log("BlockCountLoaded=%d.\n", ncr400->block_count_loaded);
|
||||
if (!ncr400->block_count_loaded) {
|
||||
if (!(ncr->mode & MODE_DMA)) {
|
||||
ncr53c400_log("No DMA mode\n");
|
||||
ncr->tcr &= ~TCR_LAST_BYTE_SENT;
|
||||
ncr->isr &= ~STATUS_END_OF_DMA;
|
||||
ncr->dma_mode = DMA_IDLE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -474,6 +491,7 @@ ncr53c400_callback(void *priv)
|
||||
ncr400->block_count = (ncr400->block_count - 1) & 0xff;
|
||||
ncr53c400_log("NCR 53c400 Remaining blocks to be written=%d\n", ncr400->block_count);
|
||||
if (!ncr400->block_count) {
|
||||
ncr->dma_mode = DMA_IDLE;
|
||||
ncr400->block_count_loaded = 0;
|
||||
ncr53c400_log("IO End of write transfer\n");
|
||||
ncr->tcr |= TCR_LAST_BYTE_SENT;
|
||||
@@ -527,6 +545,7 @@ ncr53c400_callback(void *priv)
|
||||
ncr400->block_count = (ncr400->block_count - 1) & 0xff;
|
||||
ncr53c400_log("NCR 53c400 Remaining blocks to be read=%d\n", ncr400->block_count);
|
||||
if (!ncr400->block_count) {
|
||||
ncr->dma_mode = DMA_IDLE;
|
||||
ncr400->block_count_loaded = 0;
|
||||
ncr53c400_log("IO End of read transfer\n");
|
||||
ncr->isr |= STATUS_END_OF_DMA;
|
||||
@@ -544,6 +563,7 @@ ncr53c400_callback(void *priv)
|
||||
break;
|
||||
}
|
||||
|
||||
ncr53c400_log("Bus Read.\n");
|
||||
ncr5380_bus_read(ncr);
|
||||
|
||||
if (!(ncr->cur_bus & BUS_BSY) && (ncr->mode & MODE_MONITOR_BUSY)) {
|
||||
|
||||
@@ -287,6 +287,7 @@ write_again:
|
||||
t128->block_count = (t128->block_count - 1) & 0xff;
|
||||
t128_log("T128 Remaining blocks to be written=%d\n", t128->block_count);
|
||||
if (!t128->block_count) {
|
||||
ncr->dma_mode = DMA_IDLE;
|
||||
t128->block_loaded = 0;
|
||||
t128_log("IO End of write transfer\n");
|
||||
ncr->tcr |= TCR_LAST_BYTE_SENT;
|
||||
@@ -343,6 +344,7 @@ read_again:
|
||||
t128_log("T128 Remaining blocks to be read=%d, status=%02x, len=%i, cdb[0] = %02x\n", t128->block_count, t128->status, dev->buffer_length, ncr->command[0]);
|
||||
if (!t128->block_count) {
|
||||
t128->block_loaded = 0;
|
||||
ncr->dma_mode = DMA_IDLE;
|
||||
t128_log("IO End of read transfer\n");
|
||||
ncr->isr |= STATUS_END_OF_DMA;
|
||||
timer_stop(&t128->timer);
|
||||
|
||||
Reference in New Issue
Block a user