Merge pull request #5089 from 86Box/tc1995

Some changes on the PCSCSI code of the new year (January 1st, 2025)
This commit is contained in:
Miran Grča
2025-01-01 23:01:29 +01:00
committed by GitHub

View File

@@ -114,6 +114,7 @@
#define INTR_FC 0x08
#define INTR_BS 0x10
#define INTR_DC 0x20
#define INTR_ILL 0x40
#define INTR_RST 0x80
#define SEQ_0 0x0
@@ -174,12 +175,11 @@ typedef struct esp_t {
uint8_t bus;
uint8_t id, lun;
Fifo8 cmdfifo;
uint32_t do_cmd;
uint8_t cmdfifo_cdb_offset;
int data_ready;
int32_t xfer_counter;
int dma_enabled;
int32_t xfer_counter;
int dma_enabled;
uint32_t buffer_pos;
uint32_t dma_regs[8];
@@ -198,6 +198,7 @@ typedef struct esp_t {
struct {
uint8_t mode;
uint8_t status;
int interrupt;
int pos;
} dma_86c01;
@@ -239,7 +240,7 @@ static void esp_dma_ti_check(esp_t *dev);
static void esp_nodma_ti_dataout(esp_t *dev);
static void esp_pci_soft_reset(esp_t *dev);
static void esp_pci_hard_reset(esp_t *dev);
static void handle_ti(void *priv);
static void handle_ti(esp_t *dev);
static int
esp_cdb_length(uint8_t *buf)
@@ -253,7 +254,7 @@ esp_cdb_length(uint8_t *buf)
break;
case 1:
case 2:
case 6:
case 6: /*Vendor unique*/
cdb_len = 10;
break;
case 4:
@@ -292,9 +293,11 @@ esp_irq(esp_t *dev, int level)
if (dev->mca) {
if (level) {
picintlevel(1 << dev->irq, &dev->irq_state);
dev->dma_86c01.mode |= 0x40;
esp_log("Raising IRQ...\n");
} else {
picintclevel(1 << dev->irq, &dev->irq_state);
dev->dma_86c01.mode &= ~0x40;
esp_log("Lowering IRQ...\n");
}
} else {
@@ -307,8 +310,8 @@ esp_irq(esp_t *dev, int level)
* DMA_STAT_DONE and the ESP IRQ arriving which is visible to the
* guest that can cause confusion e.g. Linux
*/
if ((dev->dma_regs[DMA_CMD] & DMA_CMD_MASK) == 0x3 &&
dev->dma_regs[DMA_WBC] == 0)
if (((dev->dma_regs[DMA_CMD] & DMA_CMD_MASK) == 0x03) &&
(dev->dma_regs[DMA_WBC] == 0))
dev->dma_regs[DMA_STAT] |= DMA_STAT_DONE;
} else
dev->dma_regs[DMA_STAT] &= ~DMA_STAT_SCSIINT;
@@ -383,7 +386,7 @@ esp_get_tc(esp_t *dev)
{
uint32_t dmalen;
dmalen = dev->rregs[ESP_TCLO];
dmalen = dev->rregs[ESP_TCLO] & 0xff;
dmalen |= dev->rregs[ESP_TCMID] << 8;
dmalen |= dev->rregs[ESP_TCHI] << 16;
@@ -395,10 +398,11 @@ esp_set_tc(esp_t *dev, uint32_t dmalen)
{
uint32_t old_tc = esp_get_tc(dev);
dev->rregs[ESP_TCLO] = dmalen;
dev->rregs[ESP_TCLO] = dmalen & 0xff;
dev->rregs[ESP_TCMID] = dmalen >> 8;
dev->rregs[ESP_TCHI] = dmalen >> 16;
esp_log("OLDTC=%d, DMALEN=%d.\n", old_tc, dmalen);
if (old_tc && !dmalen)
dev->rregs[ESP_RSTAT] |= STAT_TC;
}
@@ -408,10 +412,11 @@ esp_get_stc(esp_t *dev)
{
uint32_t dmalen;
dmalen = dev->wregs[ESP_TCLO];
dmalen |= dev->wregs[ESP_TCMID] << 8;
dmalen |= dev->wregs[ESP_TCHI] << 16;
dmalen = dev->wregs[ESP_TCLO] & 0xff;
dmalen |= (dev->wregs[ESP_TCMID] << 8);
dmalen |= (dev->wregs[ESP_TCHI] << 16);
esp_log("STCW=%d.\n", dmalen);
return dmalen;
}
@@ -459,25 +464,25 @@ esp_transfer_data(esp_t *dev)
dev->rregs[ESP_RSEQ] = SEQ_CD;
break;
case CMD_SELATNS:
case (CMD_SELATNS | CMD_DMA):
/*
* Initial incoming data xfer is complete so raise command
* completion interrupt
*/
dev->rregs[ESP_RINTR] |= INTR_BS;
dev->rregs[ESP_RSEQ] = SEQ_MO;
break;
case CMD_SELATNS:
case (CMD_SELATNS | CMD_DMA):
/*
* Initial incoming data xfer is complete so raise command
* completion interrupt
*/
dev->rregs[ESP_RINTR] |= INTR_BS;
dev->rregs[ESP_RSEQ] = SEQ_MO;
break;
case CMD_TI:
case (CMD_TI | CMD_DMA):
/*
* Bus service interrupt raised because of initial change to
* DATA phase
*/
dev->rregs[ESP_CMD] = 0;
dev->rregs[ESP_RINTR] |= INTR_BS;
break;
case CMD_TI:
case (CMD_TI | CMD_DMA):
/*
* Bus service interrupt raised because of initial change to
* DATA phase
*/
dev->rregs[ESP_CMD] = 0;
dev->rregs[ESP_RINTR] |= INTR_BS;
break;
}
esp_raise_irq(dev);
@@ -621,16 +626,12 @@ esp_hard_reset(esp_t *dev)
{
memset(dev->rregs, 0, ESP_REGS);
memset(dev->wregs, 0, ESP_REGS);
dev->tchi_written = 0;
dev->ti_size = 0;
fifo8_reset(&dev->fifo);
fifo8_reset(&dev->cmdfifo);
dev->dma = 0;
dev->do_cmd = 0;
dev->rregs[ESP_CFG1] = dev->mca ? dev->HostID : 7;
esp_log("ESP Reset\n");
for (uint8_t i = 0; i < 16; i++)
scsi_device_reset(&scsi_devices[dev->bus][i]);
timer_stop(&dev->timer);
}
@@ -681,7 +682,7 @@ esp_do_dma(esp_t *dev)
len = esp_get_tc(dev);
switch (esp_get_phase(dev)) {
switch (esp_get_phase(dev)) {
case STAT_MO:
len = MIN(len, fifo8_num_free(&dev->cmdfifo));
if (dev->mca) {
@@ -787,7 +788,6 @@ esp_do_dma(esp_t *dev)
esp_pci_dma_memory_rw(dev, sd->sc->temp_buffer + dev->buffer_pos, len, WRITE_TO_DEVICE);
esp_set_tc(dev, esp_get_tc(dev) - len);
dev->buffer_pos += len;
dev->xfer_counter -= len;
dev->ti_size += len;
@@ -827,6 +827,7 @@ esp_do_dma(esp_t *dev)
/* Defer until data is available. */
return;
}
if (len > dev->xfer_counter)
len = dev->xfer_counter;
@@ -861,14 +862,6 @@ esp_do_dma(esp_t *dev)
break;
}
if ((dev->xfer_counter <= 0) && !dev->ti_size && esp_get_tc(dev)) {
/* If the guest underflows TC then terminate SCSI request */
esp_log("ESP SCSI Read finished (underflow).\n");
scsi_device_command_phase1(sd);
esp_command_complete(dev, sd->status);
return;
}
if ((dev->xfer_counter <= 0) && (fifo8_num_used(&dev->fifo) < 2)) {
/* Defer until the scsi layer has completed */
if (dev->ti_size <= 0) {
@@ -1241,10 +1234,8 @@ handle_pad(esp_t *dev)
}
static void
handle_ti(void *priv)
handle_ti(esp_t *dev)
{
esp_t *dev = (esp_t *) priv;
if (dev->dma) {
esp_log("ESP Handle TI, do data, minlen = %i\n", esp_get_tc(dev));
esp_do_dma(dev);
@@ -1329,8 +1320,6 @@ esp_callback(void *priv)
handle_pad(dev);
}
}
esp_log("ESP DMA activated = %d, CMD activated = %d, CMD = %02x\n", dev->dma_enabled, dev->do_cmd, (dev->rregs[ESP_CMD] & CMD_CMD));
}
static uint32_t
@@ -1353,13 +1342,15 @@ esp_reg_read(esp_t *dev, uint32_t saddr)
esp_lower_irq(dev);
esp_log("ESP RINTR read old val = %02x\n", ret);
break;
case ESP_TCHI:
/* Return the unique id if the value has never been written */
if (!dev->tchi_written && !dev->mca) {
esp_log("ESP TCHI read id 0x12\n");
ret = TCHI_AM53C974;
} else
ret = dev->rregs[saddr];
case ESP_TCHI: /* Return the unique id if the value has never been written */
if (dev->mca) {
ret = dev->rregs[ESP_TCHI];
} else {
if (dev->rregs[ESP_CFG2] & 0x40)
ret = TCHI_AM53C974;
else
ret = dev->rregs[ESP_TCHI];
}
break;
case ESP_RFLAGS:
ret = fifo8_num_used(&dev->fifo);
@@ -1376,14 +1367,11 @@ static void
esp_reg_write(esp_t *dev, uint32_t saddr, uint32_t val)
{
esp_log("Write reg %02x = %02x\n", saddr, val);
switch (saddr) {
case ESP_TCHI:
dev->tchi_written = 1;
fallthrough;
case ESP_TCLO:
case ESP_TCMID:
esp_log("Transfer count regs %02x = %i\n", saddr, val);
esp_log("ESP TCW reg%02x = %02x.\n", saddr, val);
dev->rregs[ESP_RSTAT] &= ~STAT_TC;
break;
case ESP_FIFO:
@@ -1393,14 +1381,18 @@ esp_reg_write(esp_t *dev, uint32_t saddr, uint32_t val)
esp_do_nodma(dev);
break;
case ESP_CMD:
dev->rregs[saddr] = val;
dev->rregs[ESP_CMD] = val;
if (val & CMD_DMA) {
dev->dma = 1;
/* Reload DMA counter. */
esp_set_tc(dev, esp_get_stc(dev));
if (!esp_get_stc(dev))
esp_set_tc(dev, 0x10000);
if (!esp_get_stc(dev)) {
if (dev->rregs[ESP_CFG2] & 0x40)
esp_set_tc(dev, 0x1000000);
else
esp_set_tc(dev, 0x10000);
}
} else {
dev->dma = 0;
esp_log("ESP Command not for DMA\n");
@@ -1481,6 +1473,8 @@ esp_reg_write(esp_t *dev, uint32_t saddr, uint32_t val)
}
break;
case ESP_WBUSID:
esp_log("ESP BUS ID=%d.\n", val & BUSID_DID);
break;
case ESP_WSEL:
case ESP_WSYNTP:
case ESP_WSYNO:
@@ -1505,6 +1499,7 @@ esp_reg_write(esp_t *dev, uint32_t saddr, uint32_t val)
static void
esp_pci_dma_memory_rw(esp_t *dev, uint8_t *buf, uint32_t len, int dir)
{
uint32_t sg_pos = 0;
uint32_t addr;
int expected_dir;
@@ -1513,31 +1508,58 @@ esp_pci_dma_memory_rw(esp_t *dev, uint8_t *buf, uint32_t len, int dir)
else
expected_dir = WRITE_TO_DEVICE;
esp_log("ESP DMA WBC = %d, addr = %06x, expected direction = %d, dir = %i\n", dev->dma_regs[DMA_WBC], dev->dma_regs[DMA_SPA], expected_dir, dir);
if (dir != expected_dir) {
esp_log("ESP unexpected direction\n");
return;
}
addr = dev->dma_regs[DMA_WAC];
if (dev->dma_regs[DMA_WBC] < len)
len = dev->dma_regs[DMA_WBC];
if (dev->dma_regs[DMA_CMD] & DMA_CMD_MDL) {
if (dev->dma_regs[DMA_STC]) {
if (dev->dma_regs[DMA_WBC] > len)
dev->dma_regs[DMA_WBC] = len;
if (expected_dir)
dma_bm_write(addr, buf, len, 4);
else
dma_bm_read(addr, buf, len, 4);
esp_log("WAC MDL=%08x, STC=%d, ID=%d.\n", dev->dma_regs[DMA_WAC] | (dev->dma_regs[DMA_WMAC] & 0xff000), dev->dma_regs[DMA_STC], dev->id);
for (uint32_t i = 0; i < len; i++) {
addr = dev->dma_regs[DMA_WAC];
esp_log("DMA: Address = %08X, Length = %08X (%02X %02X %02X %02X -> %02X %02X %02X %02X)\n", dev->dma_regs[DMA_SPA], len,
ram[dev->dma_regs[DMA_SPA]], ram[dev->dma_regs[DMA_SPA] + 1], ram[dev->dma_regs[DMA_SPA] + 2], ram[dev->dma_regs[DMA_SPA] + 3],
buf[0], buf[1], buf[2], buf[3]);
if (expected_dir)
dma_bm_write(addr | (dev->dma_regs[DMA_WMAC] & 0xff000), &buf[sg_pos], len, 4);
else
dma_bm_read(addr | (dev->dma_regs[DMA_WMAC] & 0xff000), &buf[sg_pos], len, 4);
/* update status registers */
dev->dma_regs[DMA_WBC] -= len;
dev->dma_regs[DMA_WAC] += len;
if (dev->dma_regs[DMA_WBC] == 0)
dev->dma_regs[DMA_STAT] |= DMA_STAT_DONE;
sg_pos++;
dev->dma_regs[DMA_WBC]--;
dev->dma_regs[DMA_WAC]++;
if (dev->dma_regs[DMA_WAC] & 0x1000) {
dev->dma_regs[DMA_WAC] = 0;
dev->dma_regs[DMA_WMAC] += 0x1000;
}
if (dev->dma_regs[DMA_WBC] <= 0) {
dev->dma_regs[DMA_WBC] = 0;
dev->dma_regs[DMA_STAT] |= DMA_STAT_DONE;
}
}
}
} else {
if (dev->dma_regs[DMA_WBC] < len)
len = dev->dma_regs[DMA_WBC];
addr = dev->dma_regs[DMA_WAC];
if (expected_dir)
dma_bm_write(addr, buf, len, 4);
else
dma_bm_read(addr, buf, len, 4);
/* update status registers */
dev->dma_regs[DMA_WBC] -= len;
dev->dma_regs[DMA_WAC] += len;
if (dev->dma_regs[DMA_WBC] == 0)
dev->dma_regs[DMA_STAT] |= DMA_STAT_DONE;
}
}
static uint32_t
@@ -1566,7 +1588,7 @@ esp_pci_dma_write(esp_t *dev, uint16_t saddr, uint32_t val)
switch (saddr) {
case DMA_CMD:
dev->dma_regs[saddr] = val;
dev->dma_regs[DMA_CMD] = val;
esp_log("ESP PCI DMA Write CMD = %02x\n", val & DMA_CMD_MASK);
switch (val & DMA_CMD_MASK) {
case 0: /*IDLE*/
@@ -1580,21 +1602,32 @@ esp_pci_dma_write(esp_t *dev, uint16_t saddr, uint32_t val)
scsi_device_command_stop(&scsi_devices[dev->bus][dev->id]);
break;
case 3: /*START*/
dev->dma_regs[DMA_WAC] = dev->dma_regs[DMA_SPA];
dev->dma_regs[DMA_WMAC] = dev->dma_regs[DMA_SMDLA] & 0xfffffffc;
if (!dev->dma_regs[DMA_STC])
dev->dma_regs[DMA_STC] = 0x1000000;
dev->dma_regs[DMA_WBC] = dev->dma_regs[DMA_STC];
dev->dma_regs[DMA_WAC] = dev->dma_regs[DMA_SPA];
dev->dma_regs[DMA_WMAC] = dev->dma_regs[DMA_SMDLA];
dev->dma_regs[DMA_STAT] &= ~(DMA_STAT_BCMBLT | DMA_STAT_SCSIINT | DMA_STAT_DONE | DMA_STAT_ABORT | DMA_STAT_ERROR | DMA_STAT_PWDN);
esp_dma_enable(dev, 1);
esp_log("PCI DMA enable\n");
esp_log("PCI DMA enable, MDL bit=%02x, SPA=%08x, SMDLA=%08x, STC=%d, ID=%d, SCSICMD=%02x.\n", val & DMA_CMD_MDL, dev->dma_regs[DMA_SPA], dev->dma_regs[DMA_SMDLA], dev->dma_regs[DMA_STC], dev->id, dev->cmdfifo.data[1]);
break;
default: /* can't happen */
abort();
break;
}
break;
case DMA_STC:
dev->dma_regs[DMA_STC] = val;
esp_log("DMASTC PCI write=%08x.\n", val);
break;
case DMA_SPA:
dev->dma_regs[DMA_SPA] = val;
esp_log("DMASPA PCI write=%08x.\n", val);
break;
case DMA_SMDLA:
dev->dma_regs[saddr] = val;
dev->dma_regs[DMA_SMDLA] = val;
esp_log("DMASMDLA PCI write=%08x.\n", val);
break;
case DMA_STAT:
if (dev->sbac & SBAC_STATUS) {
@@ -1629,7 +1662,7 @@ esp_pci_hard_reset(esp_t *dev)
dev->dma_regs[DMA_STAT] &= ~(DMA_STAT_BCMBLT | DMA_STAT_SCSIINT
| DMA_STAT_DONE | DMA_STAT_ABORT
| DMA_STAT_ERROR);
dev->dma_regs[DMA_WMAC] = 0xfffffffd;
dev->dma_regs[DMA_WMAC] = 0xfffffffc;
}
static uint32_t
@@ -1680,7 +1713,7 @@ esp_io_pci_write(esp_t *dev, uint32_t addr, uint32_t val, unsigned int size)
current = dev->wregs[addr >> 2];
} else if (addr < 0x60) {
current = dev->dma_regs[(addr - 0x40) >> 2];
} else if (addr < 0x74) {
} else if (addr == 0x70) {
current = dev->sbac;
}
@@ -2008,7 +2041,7 @@ esp_pci_read(UNUSED(int func), int addr, void *priv)
case 0x07:
return esp_pci_regs[0x07] | 0x02;
case 0x08:
return 0; /*Revision ID*/
return 0x10; /*Revision ID*/
case 0x09:
return 0; /*Programming interface*/
case 0x0A:
@@ -2018,7 +2051,7 @@ esp_pci_read(UNUSED(int func), int addr, void *priv)
case 0x0E:
return 0; /*Header type */
case 0x10:
return (esp_pci_bar[0].addr_regs[0] & 0x80) | 0x01; /*I/O space*/
return esp_pci_bar[0].addr_regs[0] | 0x01; /*I/O space*/
case 0x11:
return esp_pci_bar[0].addr_regs[1];
case 0x12:
@@ -2082,7 +2115,7 @@ esp_pci_write(UNUSED(int func), int addr, uint8_t val, void *priv)
switch (addr) {
case 0x04:
valxor = (val & 3) ^ esp_pci_regs[addr];
valxor = (val & 0x01) ^ esp_pci_regs[addr];
if (valxor & PCI_COMMAND_IO) {
esp_io_remove(dev, dev->PCIBase, 0x80);
if ((val & PCI_COMMAND_IO) && (dev->PCIBase != 0))
@@ -2215,6 +2248,8 @@ dc390_init(UNUSED(const device_t *info))
}
esp_pci_hard_reset(dev);
for (uint8_t i = 0; i < 16; i++)
scsi_device_reset(&scsi_devices[dev->bus][i]);
timer_add(&dev->timer, esp_callback, dev, 0);
@@ -2240,12 +2275,12 @@ ncr53c9x_in(uint16_t port, void *priv)
break;
case 0x0c:
if (dev->rregs[ESP_RSTAT] & STAT_INT)
if (dev->dma_86c01.mode & 0x40)
dev->dma_86c01.status |= 0x01;
else
dev->dma_86c01.status &= ~0x01;
if ((dev->dma_86c01.mode & 0x40) || dev->dma_enabled)
if (dev->dma_enabled)
dev->dma_86c01.status |= 0x02;
else
dev->dma_86c01.status &= ~0x02;
@@ -2258,7 +2293,7 @@ ncr53c9x_in(uint16_t port, void *priv)
}
}
esp_log("[%04X:%08X]: NCR53c9x DMA read port = %02x, ret = %02x.\n\n", CS, cpu_state.pc, port, ret);
esp_log("[%04X:%08X]: NCR53c9x DMA read port = %02x, ret = %02x, local = %d.\n\n", CS, cpu_state.pc, port, ret, dev->local);
return ret;
}
@@ -2282,7 +2317,7 @@ ncr53c9x_out(uint16_t port, uint16_t val, void *priv)
port &= 0x1f;
esp_log("[%04X:%08X]: NCR53c9x DMA write port = %02x, val = %02x\n", CS, cpu_state.pc, port, val);
esp_log("[%04X:%08X]: NCR53c9x DMA write port = %02x, val = %02x.\n\n", CS, cpu_state.pc, port, val);
if (port >= 0x10)
esp_reg_write(dev, port - 0x10, val);
@@ -2360,6 +2395,8 @@ ncr53c9x_mca_write(int port, uint8_t val, void *priv)
ncr53c9x_outb, ncr53c9x_outw, NULL, dev);
esp_hard_reset(dev);
for (uint8_t i = 0; i < 8; i++)
scsi_device_reset(&scsi_devices[dev->bus][i]);
}
/* Say hello. */
@@ -2377,7 +2414,7 @@ ncr53c9x_mca_feedb(void *priv)
}
static void *
ncr53c9x_mca_init(UNUSED(const device_t *info))
ncr53c9x_mca_init(const device_t *info)
{
esp_t *dev;
@@ -2387,6 +2424,7 @@ ncr53c9x_mca_init(UNUSED(const device_t *info))
dev->bus = scsi_get_bus();
dev->mca = 1;
dev->local = info->local;
fifo8_create(&dev->fifo, ESP_FIFO_SZ);
fifo8_create(&dev->cmdfifo, ESP_CMDFIFO_SZ);
@@ -2396,6 +2434,8 @@ ncr53c9x_mca_init(UNUSED(const device_t *info))
mca_add(ncr53c9x_mca_read, ncr53c9x_mca_write, ncr53c9x_mca_feedb, NULL, dev);
esp_hard_reset(dev);
for (uint8_t i = 0; i < 8; i++)
scsi_device_reset(&scsi_devices[dev->bus][i]);
timer_add(&dev->timer, esp_callback, dev, 0);
@@ -2446,7 +2486,7 @@ const device_t dc390_pci_device = {
};
const device_t am53c974_pci_device = {
.name = "AMD 53c974 PCI",
.name = "AMD 53c974A PCI",
.internal_name = "am53c974",
.flags = DEVICE_PCI,
.local = 1,