Removed scsi/scsi_bus.c as it's no longer needed.
This commit is contained in:
@@ -1,353 +0,0 @@
|
||||
/*
|
||||
* 86Box A hypervisor and IBM PC system emulator that specializes in
|
||||
* running old operating systems and software designed for IBM
|
||||
* PC systems and compatibles from 1981 through fairly recent
|
||||
* system designs based on the PCI bus.
|
||||
*
|
||||
* This file is part of the 86Box distribution.
|
||||
*
|
||||
* The generic SCSI bus operations handler.
|
||||
*
|
||||
* Version: @(#)scsi_bus.c 1.0.7 2018/06/18
|
||||
*
|
||||
* NOTES: For now ported from PCem with some modifications
|
||||
* but at least it's a start.
|
||||
*
|
||||
* Authors: TheCollector1995, <mariogplayer@gmail.com>
|
||||
*/
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <wchar.h>
|
||||
#define HAVE_STDARG_H
|
||||
#include "../86box.h"
|
||||
#include "scsi.h"
|
||||
#include "scsi_device.h"
|
||||
|
||||
|
||||
#define STATE_IDLE 0
|
||||
#define STATE_COMMAND 1
|
||||
#define STATE_COMMANDWAIT 2
|
||||
#define STATE_DATAIN 3
|
||||
#define STATE_DATAOUT 4
|
||||
#define STATE_STATUS 5
|
||||
#define STATE_MESSAGEIN 6
|
||||
#define STATE_PHASESEL 7
|
||||
|
||||
#define SET_BUS_STATE(bus, state) bus->bus_out = (bus->bus_out & ~(SCSI_PHASE_MESSAGE_IN)) | (state & (SCSI_PHASE_MESSAGE_IN))
|
||||
|
||||
uint32_t SCSI_BufferLength;
|
||||
#ifdef ENABLE_SCSI_BUS_LOG
|
||||
int scsi_bus_do_log = ENABLE_SCSI_BUS_LOG;
|
||||
#endif
|
||||
|
||||
|
||||
static void
|
||||
scsi_bus_log(const char *fmt, ...)
|
||||
{
|
||||
#ifdef ENABLE_SCSI_BUS_LOG
|
||||
va_list ap;
|
||||
|
||||
if (scsi_bus_do_log) {
|
||||
va_start(ap, fmt);
|
||||
pclog_ex(fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/* get the length of a SCSI command based on its command byte type */
|
||||
static int get_cmd_len(int cbyte)
|
||||
{
|
||||
int len;
|
||||
int group;
|
||||
|
||||
group = (cbyte>>5) & 7;
|
||||
|
||||
if (group == 0) len = 6;
|
||||
if (group == 1 || group == 2) len = 10;
|
||||
if (group == 5) len = 12;
|
||||
|
||||
// scsi_bus_log("Command group %d, length %d\n", group, len);
|
||||
|
||||
return(len);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
get_dev_id(uint8_t data)
|
||||
{
|
||||
int c;
|
||||
|
||||
for (c = 0; c < SCSI_ID_MAX; c++) {
|
||||
if (data & (1 << c)) return(c);
|
||||
}
|
||||
|
||||
return(-1);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
scsi_bus_update(scsi_bus_t *bus, int bus_assert)
|
||||
{
|
||||
scsi_device_t *dev;
|
||||
|
||||
if (bus_assert & BUS_ARB)
|
||||
bus->state = STATE_IDLE;
|
||||
|
||||
switch (bus->state) {
|
||||
case STATE_IDLE:
|
||||
scsi_bus_log("State Idle\n");
|
||||
bus->clear_req = bus->change_state_delay = bus->new_req_delay = 0;
|
||||
if ((bus_assert & BUS_SEL) && !(bus_assert & BUS_BSY)) {
|
||||
uint8_t sel_data = BUS_GETDATA(bus_assert);
|
||||
|
||||
bus->dev_id = get_dev_id(sel_data);
|
||||
|
||||
if ((bus->dev_id != -1) && scsi_device_present(bus->dev_id)) {
|
||||
bus->bus_out |= BUS_BSY;
|
||||
bus->state = STATE_PHASESEL;
|
||||
}
|
||||
//scsi_bus_log("Device id %i\n", bus->dev_id);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case STATE_PHASESEL:
|
||||
scsi_bus_log("State Phase Sel\n");
|
||||
if (! (bus_assert & BUS_SEL)) {
|
||||
if (! (bus_assert & BUS_ATN)) {
|
||||
if ((bus->dev_id != -1) &&
|
||||
scsi_device_present(bus->dev_id)) {
|
||||
bus->state = STATE_COMMAND;
|
||||
bus->bus_out = BUS_BSY | BUS_REQ;
|
||||
bus->command_pos = 0;
|
||||
SET_BUS_STATE(bus, SCSI_PHASE_COMMAND);
|
||||
} else {
|
||||
bus->state = STATE_IDLE;
|
||||
bus->bus_out = 0;
|
||||
}
|
||||
} else
|
||||
fatal("dropped sel %x\n", bus_assert & BUS_ATN);
|
||||
}
|
||||
break;
|
||||
|
||||
case STATE_COMMAND:
|
||||
if ((bus_assert & BUS_ACK) && !(bus->bus_in & BUS_ACK)) {
|
||||
scsi_bus_log("State Command\n");
|
||||
bus->command[bus->command_pos++] = BUS_GETDATA(bus_assert);
|
||||
|
||||
bus->clear_req = 3;
|
||||
bus->new_state = bus->bus_out & SCSI_PHASE_MESSAGE_IN;
|
||||
bus->bus_out &= ~BUS_REQ;
|
||||
|
||||
if (get_cmd_len(bus->command[0]) == bus->command_pos) {
|
||||
bus->data_pos = 0;
|
||||
|
||||
dev = &SCSIDevices[bus->dev_id];
|
||||
|
||||
scsi_bus_log("Command 0x%02X\n", bus->command[0]);
|
||||
|
||||
dev->BufferLength = -1;
|
||||
|
||||
scsi_device_command_phase0(bus->dev_id, bus->command);
|
||||
|
||||
scsi_bus_log("(ID %02X): Command %02X: Buffer Length %i, SCSI Phase %02X\n", bus->dev_id, bus->command[0], dev->BufferLength, dev->Phase);
|
||||
|
||||
if ((dev->Phase == SCSI_PHASE_DATA_IN) ||
|
||||
(dev->Phase == SCSI_PHASE_DATA_OUT)) {
|
||||
scsi_bus_log("dev->CmdBuffer = %08X\n", dev->CmdBuffer);
|
||||
dev->CmdBuffer = (uint8_t *) malloc(dev->BufferLength);
|
||||
scsi_bus_log("dev->CmdBuffer = %08X\n", dev->CmdBuffer);
|
||||
}
|
||||
|
||||
if (dev->Phase == SCSI_PHASE_DATA_OUT) {
|
||||
/* Write direction commands have delayed execution - only execute them after the bus has gotten all the data from the host. */
|
||||
scsi_bus_log("Next state is data out\n");
|
||||
|
||||
bus->state = STATE_COMMANDWAIT;
|
||||
bus->clear_req = 0;
|
||||
} else {
|
||||
/* Other command - execute immediately. */
|
||||
bus->new_state = dev->Phase;
|
||||
if (dev->Phase == SCSI_PHASE_DATA_IN) {
|
||||
scsi_device_command_phase1(bus->dev_id);
|
||||
}
|
||||
|
||||
bus->change_state_delay = 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case STATE_COMMANDWAIT:
|
||||
bus->new_state = SCSI_PHASE_DATA_OUT;
|
||||
bus->change_state_delay = 4;
|
||||
bus->clear_req = 4;
|
||||
break;
|
||||
|
||||
case STATE_DATAIN:
|
||||
if ((bus_assert & BUS_ACK) && !(bus->bus_in & BUS_ACK)) {
|
||||
scsi_bus_log("State Data In\n");
|
||||
|
||||
/* This seems to be read, so we first execute the command, then we return the bytes to the host. */
|
||||
dev = &SCSIDevices[bus->dev_id];
|
||||
|
||||
if (bus->data_pos >= SCSIDevices[bus->dev_id].BufferLength) {
|
||||
free(dev->CmdBuffer);
|
||||
dev->CmdBuffer = NULL;
|
||||
bus->bus_out &= ~BUS_REQ;
|
||||
bus->new_state = SCSI_PHASE_STATUS;
|
||||
bus->change_state_delay = 4;
|
||||
bus->new_req_delay = 8;
|
||||
} else {
|
||||
uint8_t val = dev->CmdBuffer[bus->data_pos++];
|
||||
|
||||
bus->bus_out = (bus->bus_out & ~BUS_DATAMASK) | BUS_SETDATA(val) | BUS_DBP | BUS_REQ;
|
||||
bus->clear_req = 3;
|
||||
bus->bus_out &= ~BUS_REQ;
|
||||
bus->new_state = SCSI_PHASE_DATA_IN;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case STATE_DATAOUT:
|
||||
if ((bus_assert & BUS_ACK) && !(bus->bus_in & BUS_ACK)) {
|
||||
scsi_bus_log("State Data Out\n");
|
||||
dev = &SCSIDevices[bus->dev_id];
|
||||
|
||||
/* This is write, so first get the data from the host, then execute the last phase of the command. */
|
||||
dev->CmdBuffer[bus->data_pos++] = BUS_GETDATA(bus_assert);
|
||||
|
||||
if (bus->data_pos >= SCSIDevices[bus->dev_id].BufferLength) {
|
||||
/* scsi_bus_log("%04X bytes written (%02X %02X)\n", bus->data_pos, bus->command[0], bus->command[1]); */
|
||||
scsi_bus_log("Actually executing write command\n");
|
||||
scsi_device_command_phase1(bus->dev_id);
|
||||
free(dev->CmdBuffer);
|
||||
dev->CmdBuffer = NULL;
|
||||
bus->bus_out &= ~BUS_REQ;
|
||||
bus->new_state = SCSI_PHASE_STATUS;
|
||||
bus->change_state_delay = 4;
|
||||
bus->new_req_delay = 8;
|
||||
} else {
|
||||
bus->bus_out |= BUS_REQ;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case STATE_STATUS:
|
||||
scsi_bus_log("State Status\n");
|
||||
|
||||
if ((bus_assert & BUS_ACK) && !(bus->bus_in & BUS_ACK)) {
|
||||
/* scsi_bus_log("Preparing for message in\n"); */
|
||||
bus->bus_out &= ~BUS_REQ;
|
||||
bus->new_state = SCSI_PHASE_MESSAGE_IN;
|
||||
bus->change_state_delay = 4;
|
||||
bus->new_req_delay = 8;
|
||||
}
|
||||
break;
|
||||
|
||||
case STATE_MESSAGEIN:
|
||||
scsi_bus_log("State Message In\n");
|
||||
|
||||
if ((bus_assert & BUS_ACK) && !(bus->bus_in & BUS_ACK)) {
|
||||
bus->bus_out &= ~BUS_REQ;
|
||||
bus->new_state = BUS_IDLE;
|
||||
bus->change_state_delay = 4;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
bus->bus_in = bus_assert;
|
||||
|
||||
return(bus->bus_out | bus->bus_in);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
scsi_bus_read(scsi_bus_t *bus)
|
||||
{
|
||||
scsi_device_t *dev;
|
||||
|
||||
if (bus->clear_req) {
|
||||
bus->clear_req--;
|
||||
if (!bus->clear_req) {
|
||||
scsi_bus_log("Clear REQ\n");
|
||||
|
||||
SET_BUS_STATE(bus, bus->new_state);
|
||||
bus->bus_out |= BUS_REQ;
|
||||
}
|
||||
}
|
||||
|
||||
if (bus->change_state_delay) {
|
||||
bus->change_state_delay--;
|
||||
if (!bus->change_state_delay) {
|
||||
uint8_t val;
|
||||
|
||||
scsi_bus_log("Change state delay\n");
|
||||
|
||||
SET_BUS_STATE(bus, bus->new_state);
|
||||
|
||||
switch (bus->bus_out & SCSI_PHASE_MESSAGE_IN) {
|
||||
case SCSI_PHASE_DATA_IN:
|
||||
dev = &SCSIDevices[bus->dev_id];
|
||||
|
||||
scsi_bus_log("Phase data in\n");
|
||||
bus->state = STATE_DATAIN;
|
||||
val = dev->CmdBuffer[bus->data_pos++];
|
||||
bus->bus_out = (bus->bus_out & ~BUS_DATAMASK) | BUS_SETDATA(val) | BUS_DBP;
|
||||
break;
|
||||
|
||||
case SCSI_PHASE_DATA_OUT:
|
||||
scsi_bus_log("Phase data out\n");
|
||||
if (bus->new_state & BUS_IDLE) {
|
||||
bus->state = STATE_IDLE;
|
||||
bus->bus_out &= ~BUS_BSY;
|
||||
} else {
|
||||
bus->state = STATE_DATAOUT;
|
||||
}
|
||||
break;
|
||||
|
||||
case SCSI_PHASE_STATUS:
|
||||
dev = &SCSIDevices[bus->dev_id];
|
||||
|
||||
scsi_bus_log("Phase status\n");
|
||||
bus->state = STATE_STATUS;
|
||||
bus->bus_out |= BUS_REQ;
|
||||
bus->bus_out = (bus->bus_out & ~BUS_DATAMASK) | BUS_SETDATA(dev->Status) | BUS_DBP;
|
||||
/* scsi_bus_log("SCSI Status (command %02X): %02X (%08X)\n", bus->command[0], dev->Status, bus->bus_out); */
|
||||
break;
|
||||
|
||||
case SCSI_PHASE_MESSAGE_IN:
|
||||
scsi_bus_log("Phase message in\n");
|
||||
/* scsi_bus_log("Message in\n"); */
|
||||
bus->state = STATE_MESSAGEIN;
|
||||
bus->bus_out = (bus->bus_out & ~BUS_DATAMASK) | BUS_SETDATA(0) | BUS_DBP;
|
||||
break;
|
||||
|
||||
default:
|
||||
fatal("change_state_delay bad state %x\n", bus->bus_out);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (bus->new_req_delay) {
|
||||
bus->new_req_delay--;
|
||||
if (!bus->new_req_delay) {
|
||||
bus->bus_out |= BUS_REQ;
|
||||
}
|
||||
}
|
||||
|
||||
return(bus->bus_out);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
scsi_bus_match(scsi_bus_t *bus, int bus_assert)
|
||||
{
|
||||
return((bus_assert & (BUS_CD | BUS_IO | BUS_MSG)) ==
|
||||
(bus->bus_out & (BUS_CD | BUS_IO | BUS_MSG)));
|
||||
}
|
@@ -8,7 +8,7 @@
|
||||
#
|
||||
# Makefile for Win32 (MinGW32) environment.
|
||||
#
|
||||
# Version: @(#)Makefile.mingw 1.0.125 2018/09/12
|
||||
# Version: @(#)Makefile.mingw 1.0.126 2018/09/15
|
||||
#
|
||||
# Authors: Miran Grca, <mgrca8@gmail.com>
|
||||
# Fred N. van Kempen, <decwiz@yahoo.com>
|
||||
@@ -487,8 +487,7 @@ ifeq ($(USB), y)
|
||||
USBOBJ := usb.o
|
||||
endif
|
||||
|
||||
SCSIOBJ := scsi.o \
|
||||
scsi_bus.o scsi_device.o \
|
||||
SCSIOBJ := scsi.o scsi_device.o \
|
||||
scsi_disk.o \
|
||||
scsi_x54x.o \
|
||||
scsi_aha154x.o scsi_buslogic.o \
|
||||
|
Reference in New Issue
Block a user