Split generic CD-ROM from SCSI-style CD-ROM;

Redid the way SCSI and ATAPI devices are handled;
Slight timings change in the NCR 5380;
Devices are now closed by device_close_all() in the reverse order of the one in which they were started;
Slight changes to some code in win/;
Added the WM_HARDRESET and WM_SHUTDOWN window messages for configuration manager purposes.
This commit is contained in:
OBattler
2018-10-10 22:33:24 +02:00
parent 173b1f7694
commit 6155802b59
36 changed files with 4557 additions and 4792 deletions

View File

@@ -8,7 +8,7 @@
*
* Handling of the SCSI controllers.
*
* Version: @(#)scsi.c 1.0.21 2018/10/02
* Version: @(#)scsi.c 1.0.22 2018/10/10
*
* Authors: Miran Grca, <mgrca8@gmail.com>
* Fred N. van Kempen, <decwiz@yahoo.com>
@@ -43,15 +43,9 @@
#endif
scsi_device_t SCSIDevices[SCSI_ID_MAX];
char scsi_fn[SCSI_NUM][512];
uint16_t scsi_disk_location[SCSI_NUM];
int scsi_card_current = 0;
int scsi_card_last = 0;
uint32_t SCSI_BufferLength;
typedef const struct {
const char *name;
@@ -83,26 +77,6 @@ static SCSI_CARD scsi_cards[] = {
};
#ifdef ENABLE_SCSI_LOG
int scsi_do_log = ENABLE_SCSI_LOG;
#endif
static void
scsi_log(const char *fmt, ...)
{
#ifdef ENABLE_SCSI_LOG
va_list ap;
if (scsi_do_log) {
va_start(ap, fmt);
pclog_ex(fmt, ap);
va_end(ap);
}
#endif
}
int scsi_card_available(int card)
{
if (scsi_cards[card].device)
@@ -159,25 +133,13 @@ void scsi_card_init(void)
if (!scsi_cards[scsi_card_current].device)
return;
scsi_log("Building SCSI hard disk map...\n");
build_scsi_disk_map();
scsi_log("Building SCSI CD-ROM map...\n");
build_scsi_cdrom_map();
scsi_log("Building SCSI ZIP map...\n");
build_scsi_zip_map();
for (i = 0; i < SCSI_ID_MAX; i++) {
if (scsi_devices[i].cmd_buffer)
free(scsi_devices[i].cmd_buffer);
scsi_devices[i].cmd_buffer = NULL;
for (i=0; i<SCSI_ID_MAX; i++) {
if (scsi_disks[i] != 0xff)
SCSIDevices[i].LunType = SCSI_DISK;
else if (scsi_cdrom_drives[i] != 0xff)
SCSIDevices[i].LunType = SCSI_CDROM;
else if (scsi_zip_drives[i] != 0xff)
SCSIDevices[i].LunType = SCSI_ZIP;
else
SCSIDevices[i].LunType = SCSI_NONE;
if (SCSIDevices[i].CmdBuffer)
free(SCSIDevices[i].CmdBuffer);
SCSIDevices[i].CmdBuffer = NULL;
memset(&scsi_devices[i], 0, sizeof(scsi_device_t));
scsi_devices[i].type = SCSI_NONE;
}
device_add(scsi_cards[scsi_card_current].device);

View File

@@ -11,7 +11,7 @@
* 1 - BT-545S ISA;
* 2 - BT-958D PCI
*
* Version: @(#)scsi_buslogic.c 1.0.39 2018/06/11
* Version: @(#)scsi_buslogic.c 1.0.40 2018/10/09
*
* Authors: TheCollector1995, <mariogplayer@gmail.com>
* Miran Grca, <mgrca8@gmail.com>
@@ -556,6 +556,7 @@ BuslogicSCSIBIOSDMATransfer(ESCMD *ESCSICmd, uint8_t TargetID, int dir)
int DataLength = ESCSICmd->DataLength;
uint32_t Address;
uint32_t TransferLength;
scsi_device_t *dev = &scsi_devices[TargetID];
if (ESCSICmd->DataDirection == 0x03) {
/* Non-data command. */
@@ -567,16 +568,16 @@ BuslogicSCSIBIOSDMATransfer(ESCMD *ESCSICmd, uint8_t TargetID, int dir)
/* If the control byte is 0x00, it means that the transfer direction is set up by the SCSI command without
checking its length, so do this procedure for both read/write commands. */
if ((DataLength > 0) && (SCSIDevices[TargetID].BufferLength > 0)) {
if ((DataLength > 0) && (dev->buffer_length > 0)) {
Address = DataPointer;
TransferLength = MIN(DataLength, SCSIDevices[TargetID].BufferLength);
TransferLength = MIN(DataLength, dev->buffer_length);
if (dir && ((ESCSICmd->DataDirection == CCB_DATA_XFER_OUT) || (ESCSICmd->DataDirection == 0x00))) {
buslogic_log("BusLogic BIOS DMA: Reading %i bytes from %08X\n", TransferLength, Address);
DMAPageRead(Address, (uint8_t *)SCSIDevices[TargetID].CmdBuffer, TransferLength);
DMAPageRead(Address, (uint8_t *)dev->cmd_buffer, TransferLength);
} else if (!dir && ((ESCSICmd->DataDirection == CCB_DATA_XFER_IN) || (ESCSICmd->DataDirection == 0x00))) {
buslogic_log("BusLogic BIOS DMA: Writing %i bytes at %08X\n", TransferLength, Address);
DMAPageWrite(Address, (uint8_t *)SCSIDevices[TargetID].CmdBuffer, TransferLength);
DMAPageWrite(Address, (uint8_t *)dev->cmd_buffer, TransferLength);
}
}
}
@@ -591,6 +592,7 @@ BuslogicSCSIBIOSRequestSetup(x54x_t *dev, uint8_t *CmdBuf, uint8_t *DataInBuf, u
int target_cdb_len = 12;
uint8_t target_id = 0;
int phase;
scsi_device_t *sd = &scsi_devices[ESCSICmd->TargetId];
DataInBuf[0] = DataInBuf[1] = 0;
@@ -602,9 +604,9 @@ BuslogicSCSIBIOSRequestSetup(x54x_t *dev, uint8_t *CmdBuf, uint8_t *DataInBuf, u
buslogic_log("Scanning SCSI Target ID %i\n", ESCSICmd->TargetId);
SCSIDevices[ESCSICmd->TargetId].Status = SCSI_STATUS_OK;
sd->status = SCSI_STATUS_OK;
if (!scsi_device_present(ESCSICmd->TargetId)) {
if (!scsi_device_present(sd)) {
buslogic_log("SCSI Target ID %i has no device attached\n", ESCSICmd->TargetId);
DataInBuf[2] = CCB_SELECTION_TIMEOUT;
DataInBuf[3] = SCSI_STATUS_OK;
@@ -623,7 +625,7 @@ BuslogicSCSIBIOSRequestSetup(x54x_t *dev, uint8_t *CmdBuf, uint8_t *DataInBuf, u
target_cdb_len = 12;
if (!scsi_device_valid(ESCSICmd->TargetId)) fatal("SCSI target on ID %02i has disappeared\n", ESCSICmd->TargetId);
if (!scsi_device_valid(sd)) fatal("SCSI target on ID %02i has disappeared\n", ESCSICmd->TargetId);
buslogic_log("SCSI target command being executed on: SCSI ID %i, SCSI LUN %i, Target %i\n", ESCSICmd->TargetId, ESCSICmd->LogicalUnit, target_id);
@@ -639,26 +641,26 @@ BuslogicSCSIBIOSRequestSetup(x54x_t *dev, uint8_t *CmdBuf, uint8_t *DataInBuf, u
memcpy(temp_cdb, ESCSICmd->CDB, target_cdb_len);
}
SCSIDevices[ESCSICmd->TargetId].BufferLength = ESCSICmd->DataLength;
scsi_device_command_phase0(ESCSICmd->TargetId, temp_cdb);
sd->buffer_length = ESCSICmd->DataLength;
scsi_device_command_phase0(sd, temp_cdb);
phase = SCSIDevices[ESCSICmd->TargetId].Phase;
phase = sd->phase;
if (phase != SCSI_PHASE_STATUS) {
if (phase == SCSI_PHASE_DATA_IN)
scsi_device_command_phase1(ESCSICmd->TargetId);
scsi_device_command_phase1(sd);
BuslogicSCSIBIOSDMATransfer(ESCSICmd, ESCSICmd->TargetId, (phase == SCSI_PHASE_DATA_OUT));
if (phase == SCSI_PHASE_DATA_OUT)
scsi_device_command_phase1(ESCSICmd->TargetId);
scsi_device_command_phase1(sd);
}
x54x_buf_free(ESCSICmd->TargetId);
buslogic_log("BIOS Request complete\n");
if (SCSIDevices[ESCSICmd->TargetId].Status == SCSI_STATUS_OK) {
if (sd->status == SCSI_STATUS_OK) {
DataInBuf[2] = CCB_COMPLETE;
DataInBuf[3] = SCSI_STATUS_OK;
} else if (SCSIDevices[ESCSICmd->TargetId].Status == SCSI_STATUS_CHECK_CONDITION) {
} else if (scsi_devices[ESCSICmd->TargetId].status == SCSI_STATUS_CHECK_CONDITION) {
DataInBuf[2] = CCB_COMPLETE;
DataInBuf[3] = SCSI_STATUS_CHECK_CONDITION;
}
@@ -697,15 +699,15 @@ buslogic_cmds(void *p)
case 0x23:
memset(dev->DataBuf, 0, 8);
for (i = 8; i < 15; i++) {
dev->DataBuf[i-8] = 0;
if (scsi_device_present(i) && (i != buslogic_get_host_id(dev)))
dev->DataBuf[i-8] |= 1;
dev->DataBuf[i - 8] = 0;
if (scsi_device_present(&scsi_devices[i]) && (i != buslogic_get_host_id(dev)))
dev->DataBuf[i - 8] |= 1;
}
dev->DataReplyLeft = 8;
break;
case 0x24:
for (i=0; i<15; i++) {
if (scsi_device_present(i) && (i != buslogic_get_host_id(dev)))
for (i = 0; i < 15; i++) {
if (scsi_device_present(&scsi_devices[i]) && (i != buslogic_get_host_id(dev)))
TargetsPresentMask |= (1 << i);
}
dev->DataBuf[0] = TargetsPresentMask & 0xFF;

3091
src/scsi/scsi_cdrom.c Normal file

File diff suppressed because it is too large Load Diff

75
src/scsi/scsi_cdrom.h Normal file
View File

@@ -0,0 +1,75 @@
/*
* 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.
*
* Implementation of the CD-ROM drive with SCSI(-like)
* commands, for both ATAPI and SCSI usage.
*
* Version: @(#)scsi_cdrom.h 1.0.0 2018/10/09
*
* Author: Miran Grca, <mgrca8@gmail.com>
*
* Copyright 2018 Miran Grca.
*/
#ifndef EMU_SCSI_CDROM_H
#define EMU_SCSI_CDROM_H
#define CDROM_TIME (5LL * 100LL * (1LL << TIMER_SHIFT))
#ifdef SCSI_DEVICE_H
typedef struct {
/* Common block. */
mode_sense_pages_t ms_pages_saved;
cdrom_drive_t *drv;
uint8_t *buffer,
atapi_cdb[16],
current_cdb[16],
sense[256];
uint8_t status, phase,
error, id,
features, pad0,
pad1, pad2;
uint16_t request_length, max_transfer_len;
int requested_blocks, packet_status,
total_length, do_page_save,
unit_attention;
uint32_t sector_pos, sector_len,
packet_len, pos;
int64_t callback;
int media_status, data_pos,
request_pos, total_read,
old_len;
uint8_t previous_command,
pad3, pad4, pad5;
} scsi_cdrom_t;
#endif
extern scsi_cdrom_t *scsi_cdrom[CDROM_NUM];
#define scsi_cdrom_sense_error dev->sense[0]
#define scsi_cdrom_sense_key dev->sense[2]
#define scsi_cdrom_asc dev->sense[12]
#define scsi_cdrom_ascq dev->sense[13]
#define scsi_cdrom_drive cdrom_drives[id].host_drive
extern void scsi_cdrom_reset(void *p);
#endif /*EMU_SCSI_CDROM_H*/

View File

@@ -8,7 +8,7 @@
*
* The generic SCSI device command handler.
*
* Version: @(#)scsi_device.c 1.0.17 2018/06/02
* Version: @(#)scsi_device.c 1.0.18 2018/10/10
*
* Authors: Miran Grca, <mgrca8@gmail.com>
* Fred N. van Kempen, <decwiz@yahoo.com>
@@ -25,325 +25,153 @@
#include "../disk/hdd.h"
#include "scsi.h"
#include "scsi_device.h"
#include "../cdrom/cdrom.h"
#include "../disk/zip.h"
#include "scsi_disk.h"
scsi_device_t scsi_devices[SCSI_ID_MAX];
uint8_t scsi_null_device_sense[18] = { 0x70,0,SENSE_ILLEGAL_REQUEST,0,0,0,0,0,0,0,0,0,ASC_INV_LUN,0,0,0,0,0 };
static uint8_t
scsi_device_target_command(int lun_type, uint8_t id, uint8_t *cdb)
scsi_device_target_command(scsi_device_t *dev, uint8_t *cdb)
{
switch(lun_type) {
case SCSI_DISK:
scsi_disk_command(scsi_disk[id], cdb);
return scsi_disk_err_stat_to_scsi(scsi_disk[id]);
case SCSI_CDROM:
cdrom_command(cdrom[id], cdb);
return cdrom_CDROM_PHASE_to_scsi(cdrom[id]);
case SCSI_ZIP:
zip_command(zip[id], cdb);
return zip_ZIP_PHASE_to_scsi(zip[id]);
default:
return SCSI_STATUS_CHECK_CONDITION;
}
if (dev->command && dev->err_stat_to_scsi) {
dev->command(dev->p, cdb);
return dev->err_stat_to_scsi(dev->p);
} else
return SCSI_STATUS_CHECK_CONDITION;
}
static void scsi_device_target_phase_callback(int lun_type, uint8_t id)
static void scsi_device_target_callback(scsi_device_t *dev)
{
switch(lun_type) {
case SCSI_DISK:
scsi_disk_callback(scsi_disk[id]);
break;
case SCSI_CDROM:
cdrom_phase_callback(cdrom[id]);
break;
case SCSI_ZIP:
zip_phase_callback(zip[id]);
break;
}
if (dev->callback)
dev->callback(dev->p);
return;
}
static int scsi_device_target_err_stat_to_scsi(int lun_type, uint8_t id)
static int scsi_device_target_err_stat_to_scsi(scsi_device_t *dev)
{
switch(lun_type) {
case SCSI_DISK:
return scsi_disk_err_stat_to_scsi(scsi_disk[id]);
case SCSI_CDROM:
return cdrom_CDROM_PHASE_to_scsi(cdrom[id]);
case SCSI_ZIP:
return zip_ZIP_PHASE_to_scsi(zip[id]);
default:
return SCSI_STATUS_CHECK_CONDITION;
}
if (dev->err_stat_to_scsi)
return dev->err_stat_to_scsi(dev->p);
else
return SCSI_STATUS_CHECK_CONDITION;
}
int64_t scsi_device_get_callback(uint8_t scsi_id)
int64_t scsi_device_get_callback(scsi_device_t *dev)
{
uint8_t lun_type = SCSIDevices[scsi_id].LunType;
scsi_device_data_t *sdd = (scsi_device_data_t *) dev->p;
uint8_t id = 0;
switch (lun_type)
{
case SCSI_DISK:
id = scsi_disks[scsi_id];
return scsi_disk[id]->callback;
break;
case SCSI_CDROM:
id = scsi_cdrom_drives[scsi_id];
return cdrom[id]->callback;
break;
case SCSI_ZIP:
id = scsi_zip_drives[scsi_id];
return zip[id]->callback;
break;
default:
return -1LL;
break;
}
if (sdd)
return sdd->callback;
else
return -1LL;
}
uint8_t *scsi_device_sense(uint8_t scsi_id)
uint8_t *scsi_device_sense(scsi_device_t *dev)
{
uint8_t lun_type = SCSIDevices[scsi_id].LunType;
scsi_device_data_t *sdd = (scsi_device_data_t *) dev->p;
uint8_t id = 0;
switch (lun_type)
{
case SCSI_DISK:
id = scsi_disks[scsi_id];
return scsi_disk[id]->sense;
break;
case SCSI_CDROM:
id = scsi_cdrom_drives[scsi_id];
return cdrom[id]->sense;
break;
case SCSI_ZIP:
id = scsi_zip_drives[scsi_id];
return zip[id]->sense;
break;
default:
return scsi_null_device_sense;
break;
}
if (sdd)
return sdd->sense;
else
return scsi_null_device_sense;
}
void scsi_device_request_sense(uint8_t scsi_id, uint8_t *buffer, uint8_t alloc_length)
void scsi_device_request_sense(scsi_device_t *dev, uint8_t *buffer, uint8_t alloc_length)
{
uint8_t lun_type = SCSIDevices[scsi_id].LunType;
uint8_t id = 0;
switch (lun_type)
{
case SCSI_DISK:
id = scsi_disks[scsi_id];
scsi_disk_request_sense_for_scsi(scsi_disk[id], buffer, alloc_length);
break;
case SCSI_CDROM:
id = scsi_cdrom_drives[scsi_id];
cdrom_request_sense_for_scsi(cdrom[id], buffer, alloc_length);
break;
case SCSI_ZIP:
id = scsi_zip_drives[scsi_id];
zip_request_sense_for_scsi(zip[id], buffer, alloc_length);
break;
default:
memcpy(buffer, scsi_null_device_sense, alloc_length);
break;
}
if (dev->request_sense)
dev->request_sense(dev, buffer, alloc_length);
else
memcpy(buffer, scsi_null_device_sense, alloc_length);
}
void scsi_device_reset(uint8_t scsi_id)
void scsi_device_reset(scsi_device_t *dev)
{
uint8_t lun_type = SCSIDevices[scsi_id].LunType;
uint8_t id = 0;
switch (lun_type)
{
case SCSI_DISK:
id = scsi_disks[scsi_id];
scsi_disk_reset(scsi_disk[id]);
break;
case SCSI_CDROM:
id = scsi_cdrom_drives[scsi_id];
cdrom_reset(cdrom[id]);
break;
case SCSI_ZIP:
id = scsi_zip_drives[scsi_id];
zip_reset(zip[id]);
break;
}
if (dev->reset)
dev->reset(dev->p);
}
void scsi_device_type_data(uint8_t scsi_id, uint8_t *type, uint8_t *rmb)
void scsi_device_type_data(scsi_device_t *dev, uint8_t *type, uint8_t *rmb)
{
uint8_t lun_type = SCSIDevices[scsi_id].LunType;
switch (lun_type)
{
case SCSI_DISK:
*type = *rmb = 0x00;
break;
case SCSI_CDROM:
*type = 0x05;
*rmb = 0x80;
break;
case SCSI_ZIP:
*type = 0x00;
*rmb = 0x80;
break;
default:
*type = *rmb = 0xff;
break;
}
*rmb = dev->type >> 8;
*type = dev->type & 0xff;
}
int scsi_device_read_capacity(uint8_t scsi_id, uint8_t *cdb, uint8_t *buffer, uint32_t *len)
int scsi_device_read_capacity(scsi_device_t *dev, uint8_t *cdb, uint8_t *buffer, uint32_t *len)
{
uint8_t lun_type = SCSIDevices[scsi_id].LunType;
uint8_t id = 0;
switch (lun_type)
{
case SCSI_DISK:
id = scsi_disks[scsi_id];
return scsi_disk_read_capacity(scsi_disk[id], cdb, buffer, len);
case SCSI_CDROM:
id = scsi_cdrom_drives[scsi_id];
return cdrom_read_capacity(cdrom[id], cdb, buffer, len);
case SCSI_ZIP:
id = scsi_zip_drives[scsi_id];
return zip_read_capacity(zip[id], cdb, buffer, len);
default:
return 0;
}
if (dev->read_capacity)
return dev->read_capacity(dev->p, cdb, buffer, len);
else
return 0;
}
int scsi_device_present(uint8_t scsi_id)
int scsi_device_present(scsi_device_t *dev)
{
uint8_t lun_type = SCSIDevices[scsi_id].LunType;
switch (lun_type)
{
case SCSI_NONE:
return 0;
default:
return 1;
}
if (dev->type == SCSI_NONE)
return 0;
else
return 1;
}
int scsi_device_valid(uint8_t scsi_id)
int scsi_device_valid(scsi_device_t *dev)
{
uint8_t lun_type = SCSIDevices[scsi_id].LunType;
uint8_t id = 0;
switch (lun_type)
{
case SCSI_DISK:
id = scsi_disks[scsi_id];
break;
case SCSI_CDROM:
id = scsi_cdrom_drives[scsi_id];
break;
case SCSI_ZIP:
id = scsi_zip_drives[scsi_id];
break;
default:
id = 0;
break;
}
return (id == 0xFF) ? 0 : 1;
if (dev->p)
return 0;
else
return 1;
}
int scsi_device_cdb_length(uint8_t scsi_id)
int scsi_device_cdb_length(scsi_device_t *dev)
{
/* Right now, it's 12 for all devices. */
return 12;
}
void scsi_device_command_phase0(uint8_t scsi_id, uint8_t *cdb)
void scsi_device_command_phase0(scsi_device_t *dev, uint8_t *cdb)
{
uint8_t id = 0;
uint8_t lun_type = SCSIDevices[scsi_id].LunType;
switch (lun_type) {
case SCSI_DISK:
id = scsi_disks[scsi_id];
break;
case SCSI_CDROM:
id = scsi_cdrom_drives[scsi_id];
break;
case SCSI_ZIP:
id = scsi_zip_drives[scsi_id];
break;
default:
id = 0;
SCSIDevices[scsi_id].Phase = SCSI_PHASE_STATUS;
SCSIDevices[scsi_id].Status = SCSI_STATUS_CHECK_CONDITION;
return;
if (!dev->p) {
dev->phase = SCSI_PHASE_STATUS;
dev->status = SCSI_STATUS_CHECK_CONDITION;
return;
}
/* Finally, execute the SCSI command immediately and get the transfer length. */
SCSIDevices[scsi_id].Phase = SCSI_PHASE_COMMAND;
SCSIDevices[scsi_id].Status = scsi_device_target_command(lun_type, id, cdb);
dev->phase = SCSI_PHASE_COMMAND;
dev->status = scsi_device_target_command(dev, cdb);
if (SCSIDevices[scsi_id].Phase == SCSI_PHASE_STATUS) {
if (dev->phase == SCSI_PHASE_STATUS) {
/* Command completed (either OK or error) - call the phase callback to complete the command. */
scsi_device_target_phase_callback(lun_type, id);
scsi_device_target_callback(dev);
}
/* If the phase is DATA IN or DATA OUT, finish this here. */
}
void scsi_device_command_phase1(uint8_t scsi_id)
void scsi_device_command_phase1(scsi_device_t *dev)
{
uint8_t id = 0;
uint8_t lun_type = SCSIDevices[scsi_id].LunType;
switch (lun_type) {
case SCSI_DISK:
id = scsi_disks[scsi_id];
break;
case SCSI_CDROM:
id = scsi_cdrom_drives[scsi_id];
break;
case SCSI_ZIP:
id = scsi_zip_drives[scsi_id];
break;
default:
id = 0;
return;
}
if (!dev->p)
return;
/* Call the second phase. */
scsi_device_target_phase_callback(lun_type, id);
SCSIDevices[scsi_id].Status = scsi_device_target_err_stat_to_scsi(lun_type, id);
scsi_device_target_callback(dev);
dev->status = scsi_device_target_err_stat_to_scsi(dev);
/* Command second phase complete - call the callback to complete the command. */
scsi_device_target_phase_callback(lun_type, id);
scsi_device_target_callback(dev);
}
int32_t *scsi_device_get_buf_len(uint8_t scsi_id)
int32_t *scsi_device_get_buf_len(scsi_device_t *dev)
{
return &SCSIDevices[scsi_id].BufferLength;
return &dev->buffer_length;
}

View File

@@ -8,7 +8,7 @@
*
* Definitions for the generic SCSI device command handler.
*
* Version: @(#)scsi_device.h 1.0.10 2018/10/07
* Version: @(#)scsi_device.h 1.0.11 2018/10/09
*
* Authors: Miran Grca, <mgrca8@gmail.com>
* Fred N. van Kempen, <decwiz@yahoo.com>
@@ -250,6 +250,15 @@
#define BUS_IDLE (1 << 31)
#define PHASE_IDLE 0x00
#define PHASE_COMMAND 0x01
#define PHASE_COMPLETE 0x02
#define PHASE_DATA_IN 0x03
#define PHASE_DATA_IN_DMA 0x04
#define PHASE_DATA_OUT 0x05
#define PHASE_DATA_OUT_DMA 0x06
#define PHASE_ERROR 0x80
#define SCSI_PHASE_DATA_OUT 0
#define SCSI_PHASE_DATA_IN BUS_IO
#define SCSI_PHASE_COMMAND BUS_CD
@@ -264,28 +273,38 @@
#define MODE_SELECT_PHASE_PAGE 4
/* This is probably no longer needed. */
#if 0
typedef struct
{
int state;
int new_state;
int clear_req;
uint32_t bus_in, bus_out;
int dev_id;
uint8_t command[20];
int command_pos;
uint8_t command[20];
int data_pos;
int change_state_delay;
int new_req_delay;
int state, new_state,
clear_req, dev_id,
command_pos, data_pos,
change_state_delay,
new_req_delay;
uint32_t bus_in, bus_out;
} scsi_bus_t;
#endif
typedef struct {
uint8_t *CmdBuffer;
int LunType;
int32_t BufferLength;
uint8_t Status;
uint8_t Phase;
uint8_t *cmd_buffer;
int32_t buffer_length;
uint8_t status, phase;
uint16_t type;
void *p;
void (*command)(void *p, uint8_t *cdb);
void (*callback)(void *p);
int (*err_stat_to_scsi)(void *p);
void (*request_sense)(void *p, uint8_t *buffer, uint8_t alloc_length);
void (*reset)(void *p);
int (*read_capacity)(void *p, uint8_t *cdb, uint8_t *buffer, uint32_t *len);
} scsi_device_t;
#pragma pack(push,1)
@@ -294,15 +313,43 @@ typedef struct {
} mode_sense_pages_t;
#pragma pack(pop)
enum {
SCSI_NONE = 0,
SCSI_DISK,
SCSI_CDROM,
SCSI_ZIP
};
/* This is so we can access the common elements to all SCSI device structs
without knowing the device type. */
typedef struct {
mode_sense_pages_t ms_pages_saved;
void *p;
extern scsi_device_t SCSIDevices[SCSI_ID_MAX];
uint8_t *temp_buffer,
pad[16], /* This is atapi_cdb in ATAPI-supporting devices,
and pad in SCSI-only devices. */
current_cdb[16],
sense[256];
uint8_t status, phase,
error, id,
features, pad0,
pad1, pad2;
uint16_t request_length, max_transfer_len;
int requested_blocks, packet_status,
total_length, do_page_save,
unit_attention;
uint32_t sector_pos, sector_len,
packet_len, pos;
int64_t callback;
} scsi_device_data_t;
/* These are based on the INQUIRY values. */
#define SCSI_NONE 0x0060
#define SCSI_FIXED_DISK 0x0000
#define SCSI_REMOVABLE_DISK 0x8000
#define SCSI_REMOVABLE_CDROM 0x8005
extern scsi_device_t scsi_devices[SCSI_ID_MAX];
extern int cdrom_add_error_and_subchannel(uint8_t *b, int real_sector_type);
@@ -312,20 +359,19 @@ extern int mode_select_init(uint8_t command, uint16_t pl_length, uint8_t do_save
extern int mode_select_terminate(int force);
extern int mode_select_write(uint8_t val);
extern uint8_t *scsi_device_sense(uint8_t id);
extern void scsi_device_type_data(uint8_t id, uint8_t *type, uint8_t *rmb);
extern int64_t scsi_device_get_callback(uint8_t scsi_id);
extern void scsi_device_request_sense(uint8_t scsi_id, uint8_t *buffer,
extern uint8_t *scsi_device_sense(scsi_device_t *dev);
extern void scsi_device_type_data(scsi_device_t *dev, uint8_t *type, uint8_t *rmb);
extern int64_t scsi_device_get_callback(scsi_device_t *dev);
extern void scsi_device_request_sense(scsi_device_t *dev, uint8_t *buffer,
uint8_t alloc_length);
extern void scsi_device_reset(uint8_t scsi_id);
extern int scsi_device_read_capacity(uint8_t id, uint8_t *cdb,
extern void scsi_device_reset(scsi_device_t *dev);
extern int scsi_device_read_capacity(scsi_device_t *dev, uint8_t *cdb,
uint8_t *buffer, uint32_t *len);
extern int scsi_device_present(uint8_t id);
extern int scsi_device_valid(uint8_t id);
extern int scsi_device_cdb_length(uint8_t id);
extern void scsi_device_command(uint8_t id, int cdb_len, uint8_t *cdb);
extern void scsi_device_command_phase0(uint8_t scsi_id, uint8_t *cdb);
extern void scsi_device_command_phase1(uint8_t scsi_id);
extern int32_t *scsi_device_get_buf_len(uint8_t scsi_id);
extern int scsi_device_present(scsi_device_t *dev);
extern int scsi_device_valid(scsi_device_t *dev);
extern int scsi_device_cdb_length(scsi_device_t *dev);
extern void scsi_device_command_phase0(scsi_device_t *dev, uint8_t *cdb);
extern void scsi_device_command_phase1(scsi_device_t *dev);
extern int32_t *scsi_device_get_buf_len(scsi_device_t *dev);
#endif /*SCSI_DEVICE_H*/

View File

@@ -30,7 +30,6 @@
#include "../plat.h"
#include "../ui.h"
#include "scsi_device.h"
#include "../cdrom/cdrom.h"
#include "scsi_disk.h"
@@ -54,12 +53,8 @@
#define scsi_disk_ascq dev->sense[13]
scsi_disk_t *scsi_disk[HDD_NUM];
uint8_t scsi_disks[16] = {
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};
scsi_disk_t *scsi_disk[HDD_NUM] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
/* Table of all SCSI commands and their flags, needed for the new disc change / not ready handler. */
@@ -145,6 +140,9 @@ static const mode_sense_pages_t scsi_disk_mode_sense_pages_changeable =
} };
static void scsi_disk_callback(void *p);
#ifdef ENABLE_SCSI_DISK_LOG
int scsi_disk_do_log = ENABLE_SCSI_DISK_LOG;
#endif
@@ -166,9 +164,11 @@ scsi_disk_log(const char *fmt, ...)
/* Translates ATAPI status (ERR_STAT flag) to SCSI status. */
int
scsi_disk_err_stat_to_scsi(scsi_disk_t *dev)
static int
scsi_disk_err_stat_to_scsi(void *p)
{
scsi_disk_t *dev = (scsi_disk_t *) p;
if (dev->status & ERR_STAT)
return SCSI_STATUS_CHECK_CONDITION;
else
@@ -176,48 +176,6 @@ scsi_disk_err_stat_to_scsi(scsi_disk_t *dev)
}
int
find_hdd_for_scsi_id(uint8_t scsi_id)
{
uint8_t i = 0;
for (i = 0; i < HDD_NUM; i++) {
if (wcslen(hdd[i].fn) == 0)
continue;
if ((hdd[i].spt == 0) || (hdd[i].hpc == 0) || (hdd[i].tracks == 0))
continue;
if ((hdd[i].bus == HDD_BUS_SCSI) && (hdd[i].scsi_id == scsi_id))
return i;
}
return 0xff;
}
void
scsi_loadhd(int scsi_id, int id)
{
if (! hdd_image_load(id))
scsi_disks[scsi_id] = 0xff;
}
void
build_scsi_disk_map(void)
{
uint8_t i = 0;
memset(scsi_disks, 0xff, 16);
for (i = 0; i < 16; i++) {
scsi_disks[i] = find_hdd_for_scsi_id(i);
if (scsi_disks[i] != 0xff) {
if (wcslen(hdd[scsi_disks[i]].fn) > 0)
scsi_loadhd(i, scsi_disks[i]);
}
}
}
void
scsi_disk_mode_sense_load(scsi_disk_t *dev)
{
@@ -256,9 +214,10 @@ scsi_disk_mode_sense_save(scsi_disk_t *dev)
}
int
scsi_disk_read_capacity(scsi_disk_t *dev, uint8_t *cdb, uint8_t *buffer, uint32_t *len)
static int
scsi_disk_read_capacity(void *p, uint8_t *cdb, uint8_t *buffer, uint32_t *len)
{
scsi_disk_t *dev = (scsi_disk_t *) p;
int size = 0;
size = hdd_image_get_last_sector(dev->id);
@@ -296,14 +255,14 @@ scsi_disk_mode_sense_read(scsi_disk_t *dev, uint8_t page_control, uint8_t page,
uint32_t
scsi_disk_mode_sense(scsi_disk_t *dev, uint8_t *buf, uint32_t pos, uint8_t type, uint8_t block_descriptor_len)
scsi_disk_mode_sense(scsi_disk_t *dev, uint8_t *buf, uint32_t pos, uint8_t page, uint8_t block_descriptor_len)
{
uint8_t msplen, page_control = (type >> 6) & 3;
uint8_t msplen, page_control = (page >> 6) & 3;
int i = 0, j = 0;
int size = 0;
type &= 0x3f;
page &= 0x3f;
size = hdd_image_get_last_sector(dev->id);
@@ -319,8 +278,8 @@ scsi_disk_mode_sense(scsi_disk_t *dev, uint8_t *buf, uint32_t pos, uint8_t type,
}
for (i = 0; i < 0x40; i++) {
if ((type == GPMODE_ALL_PAGES) || (type == i)) {
if (scsi_disk_mode_sense_page_flags & (1LL << dev->current_page_code)) {
if ((page == GPMODE_ALL_PAGES) || (page == i)) {
if (scsi_disk_mode_sense_page_flags & (1LL << (uint64_t) page)) {
buf[pos++] = scsi_disk_mode_sense_read(dev, page_control, i, 0);
msplen = scsi_disk_mode_sense_read(dev, page_control, i, 1);
buf[pos++] = msplen;
@@ -340,8 +299,8 @@ scsi_disk_command_common(scsi_disk_t *dev)
{
dev->status = BUSY_STAT;
dev->phase = 1;
if (dev->packet_status == CDROM_PHASE_COMPLETE) {
scsi_disk_callback(dev);
if (dev->packet_status == PHASE_COMPLETE) {
scsi_disk_callback((void *) dev);
dev->callback = 0LL;
} else
dev->callback = -1LL; /* Speed depends on SCSI controller */
@@ -351,7 +310,7 @@ scsi_disk_command_common(scsi_disk_t *dev)
static void
scsi_disk_command_complete(scsi_disk_t *dev)
{
dev->packet_status = CDROM_PHASE_COMPLETE;
dev->packet_status = PHASE_COMPLETE;
scsi_disk_command_common(dev);
}
@@ -359,7 +318,7 @@ scsi_disk_command_complete(scsi_disk_t *dev)
static void
scsi_disk_command_read_dma(scsi_disk_t *dev)
{
dev->packet_status = CDROM_PHASE_DATA_IN_DMA;
dev->packet_status = PHASE_DATA_IN_DMA;
scsi_disk_command_common(dev);
}
@@ -367,7 +326,7 @@ scsi_disk_command_read_dma(scsi_disk_t *dev)
static void
scsi_disk_command_write_dma(scsi_disk_t *dev)
{
dev->packet_status = CDROM_PHASE_DATA_OUT_DMA;
dev->packet_status = PHASE_DATA_OUT_DMA;
scsi_disk_command_common(dev);
}
@@ -407,7 +366,7 @@ scsi_disk_set_phase(scsi_disk_t *dev, uint8_t phase)
if (dev->drv->bus != HDD_BUS_SCSI)
return;
SCSIDevices[scsi_id].Phase = phase;
scsi_devices[scsi_id].phase = phase;
}
@@ -533,9 +492,11 @@ scsi_disk_rezero(scsi_disk_t *dev)
}
void
scsi_disk_reset(scsi_disk_t *dev)
static void
scsi_disk_reset(void *p)
{
scsi_disk_t *dev = (scsi_disk_t *) p;
scsi_disk_rezero(dev);
dev->status = 0;
dev->callback = 0;
@@ -568,9 +529,11 @@ scsi_disk_request_sense(scsi_disk_t *dev, uint8_t *buffer, uint8_t alloc_length,
}
void
scsi_disk_request_sense_for_scsi(scsi_disk_t *dev, uint8_t *buffer, uint8_t alloc_length)
static void
scsi_disk_request_sense_for_scsi(void *p, uint8_t *buffer, uint8_t alloc_length)
{
scsi_disk_t *dev = (scsi_disk_t *) p;
scsi_disk_request_sense(dev, buffer, alloc_length, 0);
}
@@ -588,9 +551,10 @@ scsi_disk_set_buf_len(scsi_disk_t *dev, int32_t *BufLen, int32_t *src_len)
}
void
scsi_disk_command(scsi_disk_t *dev, uint8_t *cdb)
static void
scsi_disk_command(void *p, uint8_t *cdb)
{
scsi_disk_t *dev = (scsi_disk_t *) p;
uint8_t *hdbufferb;
int32_t *BufLen;
int32_t len, max_len, alloc_length;
@@ -602,8 +566,8 @@ scsi_disk_command(scsi_disk_t *dev, uint8_t *cdb)
char device_identify_ex[15] = { '8', '6', 'B', '_', 'H', 'D', '0', '0', ' ', 'v', '1', '.', '0', '0', 0 };
int block_desc = 0;
hdbufferb = SCSIDevices[dev->drv->scsi_id].CmdBuffer;
BufLen = &SCSIDevices[dev->drv->scsi_id].BufferLength;
hdbufferb = scsi_devices[dev->drv->scsi_id].cmd_buffer;
BufLen = &scsi_devices[dev->drv->scsi_id].buffer_length;
last_sector = hdd_image_get_last_sector(dev->id);
@@ -666,7 +630,7 @@ scsi_disk_command(scsi_disk_t *dev, uint8_t *cdb)
if (!len) {
scsi_disk_set_phase(dev, SCSI_PHASE_STATUS);
dev->packet_status = CDROM_PHASE_COMPLETE;
dev->packet_status = PHASE_COMPLETE;
dev->callback = 20 * SCSI_TIME;
break;
}
@@ -715,7 +679,7 @@ scsi_disk_command(scsi_disk_t *dev, uint8_t *cdb)
if ((!dev->sector_len) || (*BufLen == 0)) {
scsi_disk_set_phase(dev, SCSI_PHASE_STATUS);
scsi_disk_log("SCSI HD %i: All done - callback set\n", dev);
dev->packet_status = CDROM_PHASE_COMPLETE;
dev->packet_status = PHASE_COMPLETE;
dev->callback = 20 * SCSI_TIME;
break;
}
@@ -779,7 +743,7 @@ scsi_disk_command(scsi_disk_t *dev, uint8_t *cdb)
if ((!dev->sector_len) || (*BufLen == 0)) {
scsi_disk_set_phase(dev, SCSI_PHASE_STATUS);
scsi_disk_log("SCSI HD %i: All done - callback set\n", dev->id);
dev->packet_status = CDROM_PHASE_COMPLETE;
dev->packet_status = PHASE_COMPLETE;
dev->callback = 20 * SCSI_TIME;
break;
}
@@ -817,7 +781,7 @@ scsi_disk_command(scsi_disk_t *dev, uint8_t *cdb)
if ((!dev->sector_len) || (*BufLen == 0)) {
scsi_disk_set_phase(dev, SCSI_PHASE_STATUS);
scsi_disk_log("SCSI HD %i: All done - callback set\n", dev->id);
dev->packet_status = CDROM_PHASE_COMPLETE;
dev->packet_status = PHASE_COMPLETE;
dev->callback = 20 * SCSI_TIME;
break;
}
@@ -847,8 +811,6 @@ scsi_disk_command(scsi_disk_t *dev, uint8_t *cdb)
else
len = (cdb[8] | (cdb[7] << 8));
dev->current_page_code = cdb[2] & 0x3F;
alloc_length = len;
dev->temp_buffer = (uint8_t *) malloc(65536);
@@ -909,7 +871,7 @@ scsi_disk_command(scsi_disk_t *dev, uint8_t *cdb)
if ((!max_len) || (*BufLen == 0)) {
scsi_disk_set_phase(dev, SCSI_PHASE_STATUS);
/* scsi_disk_log("SCSI HD %i: All done - callback set\n", dev->id); */
dev->packet_status = CDROM_PHASE_COMPLETE;
dev->packet_status = PHASE_COMPLETE;
dev->callback = 20 * SCSI_TIME;
break;
}
@@ -1055,8 +1017,8 @@ atapi_out:
static void
scsi_disk_phase_data_in(scsi_disk_t *dev)
{
uint8_t *hdbufferb = SCSIDevices[dev->drv->scsi_id].CmdBuffer;
int32_t *BufLen = &SCSIDevices[dev->drv->scsi_id].BufferLength;
uint8_t *hdbufferb = scsi_devices[dev->drv->scsi_id].cmd_buffer;
int32_t *BufLen = &scsi_devices[dev->drv->scsi_id].buffer_length;
if (!*BufLen) {
scsi_disk_log("scsi_disk_phase_data_in(): Buffer length is 0\n");
@@ -1108,9 +1070,9 @@ scsi_disk_phase_data_in(scsi_disk_t *dev)
static void
scsi_disk_phase_data_out(scsi_disk_t *dev)
{
uint8_t *hdbufferb = SCSIDevices[dev->drv->scsi_id].CmdBuffer;
uint8_t *hdbufferb = scsi_devices[dev->drv->scsi_id].cmd_buffer;
int i;
int32_t *BufLen = &SCSIDevices[dev->drv->scsi_id].BufferLength;
int32_t *BufLen = &scsi_devices[dev->drv->scsi_id].buffer_length;
uint32_t last_sector = hdd_image_get_last_sector(dev->id);
uint32_t c, h, s, last_to_write = 0;
uint16_t block_desc_len, pos;
@@ -1232,36 +1194,38 @@ scsi_disk_phase_data_out(scsi_disk_t *dev)
/* If the result is 1, issue an IRQ, otherwise not. */
void
scsi_disk_callback(scsi_disk_t *dev)
static void
scsi_disk_callback(void *p)
{
scsi_disk_t *dev = (scsi_disk_t *) p;
switch(dev->packet_status) {
case CDROM_PHASE_IDLE:
case PHASE_IDLE:
scsi_disk_log("SCSI HD %i: PHASE_IDLE\n", dev->id);
dev->phase = 1;
dev->status = READY_STAT | DRQ_STAT | (dev->status & ERR_STAT);
return;
case CDROM_PHASE_COMPLETE:
case PHASE_COMPLETE:
scsi_disk_log("SCSI HD %i: PHASE_COMPLETE\n", dev->id);
dev->status = READY_STAT;
dev->phase = 3;
dev->packet_status = 0xFF;
return;
case CDROM_PHASE_DATA_OUT_DMA:
case PHASE_DATA_OUT_DMA:
scsi_disk_log("SCSI HD %i: PHASE_DATA_OUT_DMA\n", dev->id);
scsi_disk_phase_data_out(dev);
dev->packet_status = CDROM_PHASE_COMPLETE;
dev->packet_status = PHASE_COMPLETE;
dev->status = READY_STAT;
dev->phase = 3;
return;
case CDROM_PHASE_DATA_IN_DMA:
case PHASE_DATA_IN_DMA:
scsi_disk_log("SCSI HD %i: PHASE_DATA_IN_DMA\n", dev->id);
scsi_disk_phase_data_in(dev);
dev->packet_status = CDROM_PHASE_COMPLETE;
dev->packet_status = PHASE_COMPLETE;
dev->status = READY_STAT;
dev->phase = 3;
return;
case CDROM_PHASE_ERROR:
case PHASE_ERROR:
scsi_disk_log("SCSI HD %i: PHASE_ERROR\n", dev->id);
dev->status = READY_STAT | ERR_STAT;
dev->phase = 3;
@@ -1283,20 +1247,47 @@ void
scsi_disk_hard_reset(void)
{
int c;
scsi_device_t *sd;
for (c = 0; c < HDD_NUM; c++) {
if (hdd[c].bus == HDD_BUS_SCSI) {
scsi_disk_log("SCSI disk hard_reset drive=%d\n", c);
/* Make sure to ignore any SCSI disk that has an out of range ID. */
if (hdd[c].scsi_id > SCSI_ID_MAX)
continue;
/* Make sure to ignore any SCSI disk whose image file name is empty. */
if (wcslen(hdd[c].fn) == 0)
continue;
/* Make sure to ignore any SCSI disk whose image fails to load. */
if (! hdd_image_load(c))
continue;
if (!scsi_disk[c]) {
scsi_disk[c] = (scsi_disk_t *) malloc(sizeof(scsi_disk_t));
memset(scsi_disk[c], 0, sizeof(scsi_disk_t));
}
/* SCSI disk, attach to the SCSI bus. */
sd = &scsi_devices[hdd[c].scsi_id];
sd->p = scsi_disk[c];
sd->command = scsi_disk_command;
sd->callback = scsi_disk_callback;
sd->err_stat_to_scsi = scsi_disk_err_stat_to_scsi;
sd->request_sense = scsi_disk_request_sense_for_scsi;
sd->reset = scsi_disk_reset;
sd->read_capacity = scsi_disk_read_capacity;
sd->type = SCSI_FIXED_DISK;
scsi_disk[c]->id = c;
scsi_disk[c]->drv = &hdd[c];
scsi_disk_mode_sense_load(scsi_disk[c]);
scsi_disk_log("SCSI disk %i attached to SCSI ID %i\n", c, hdd[c].scsi_id);
}
}
}

View File

@@ -6,7 +6,7 @@
*
* Emulation of SCSI fixed and removable disks.
*
* Version: @(#)scsi_disk.h 1.0.5 2018/06/02
* Version: @(#)scsi_disk.h 1.0.6 2018/10/10
*
* Author: Miran Grca, <mgrca8@gmail.com>
* Copyright 2017,2018 Miran Grca.
@@ -18,43 +18,33 @@ typedef struct {
hard_disk_t *drv;
/* Stuff for SCSI hard disks. */
uint8_t status, phase,
error, id,
uint8_t *temp_buffer,
pad[16], /* This is atapi_cdb in ATAPI-supporting devices,
and pad in SCSI-only devices. */
current_cdb[16],
sense[256];
uint16_t request_length;
uint8_t status, phase,
error, id,
pad0, pad1,
pad2, pad3;
int requested_blocks, block_total,
packet_status, callback,
block_descriptor_len,
total_length, do_page_save;
uint16_t request_length, pad4;
int requested_blocks, packet_status,
total_length, do_page_save,
unit_attention;
uint32_t sector_pos, sector_len,
packet_len;
packet_len, pos;
uint64_t current_page_code;
uint8_t *temp_buffer;
int64_t callback;
} scsi_disk_t;
extern scsi_disk_t *scsi_disk[HDD_NUM];
extern uint8_t scsi_disks[16];
extern void scsi_loadhd(int scsi_id, int id);
extern void scsi_disk_global_init(void);
extern void scsi_disk_hard_reset(void);
extern void scsi_disk_close(void);
extern int scsi_disk_read_capacity(scsi_disk_t *dev, uint8_t *cdb, uint8_t *buffer, uint32_t *len);
extern int scsi_disk_err_stat_to_scsi(scsi_disk_t *dev);
extern int scsi_disk_phase_to_scsi(scsi_disk_t *dev);
extern int find_hdd_for_scsi_id(uint8_t scsi_id);
extern void build_scsi_disk_map(void);
extern void scsi_disk_reset(scsi_disk_t *dev);
extern void scsi_disk_request_sense_for_scsi(scsi_disk_t *dev, uint8_t *buffer, uint8_t alloc_length);
extern void scsi_disk_command(scsi_disk_t *dev, uint8_t *cdb);
extern void scsi_disk_callback(scsi_disk_t *dev);

View File

@@ -9,7 +9,7 @@
* Implementation of the NCR 5380 series of SCSI Host Adapters
* made by NCR. These controllers were designed for the ISA bus.
*
* Version: @(#)scsi_ncr5380.c 1.0.20 2018/10/08
* Version: @(#)scsi_ncr5380.c 1.0.22 2018/10/09
*
* Authors: Sarah Walker, <http://pcem-emulator.co.uk/>
* TheCollector1995, <mariogplayer@gmail.com>
@@ -280,19 +280,19 @@ ncr_wait_process(ncr5380_t *ncr_dev)
if (ncr->wait_data) {
ncr->wait_data--;
if (!ncr->wait_data) {
dev = &SCSIDevices[ncr->target_id];
dev = &scsi_devices[ncr->target_id];
SET_BUS_STATE(ncr, ncr->new_phase);
if (ncr->new_phase == SCSI_PHASE_DATA_IN) {
ncr_log("Data In bus phase\n");
ncr->tx_data = dev->CmdBuffer[ncr->data_pos++];
ncr->tx_data = dev->cmd_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 (ncr->new_phase == SCSI_PHASE_STATUS) {
ncr_log("Status bus phase\n");
ncr->cur_bus |= BUS_REQ;
ncr->state = STATE_STATUS;
ncr->cur_bus = (ncr->cur_bus & ~BUS_DATAMASK) | BUS_SETDATA(dev->Status) | BUS_DBP;
ncr->cur_bus = (ncr->cur_bus & ~BUS_DATAMASK) | BUS_SETDATA(dev->status) | BUS_DBP;
} else if (ncr->new_phase == SCSI_PHASE_MESSAGE_IN) {
ncr_log("Message In bus phase\n");
ncr->state = STATE_MESSAGEIN;
@@ -799,7 +799,7 @@ scsiat_out(uint16_t port, uint8_t val, void *priv)
{
ncr5380_t *ncr_dev = (ncr5380_t *)priv;
ncr_t *ncr = &ncr_dev->ncr;
scsi_device_t *dev = &SCSIDevices[ncr->target_id];
scsi_device_t *dev = &scsi_devices[ncr->target_id];
ncr_log("SCSI AT write=0x%03x, val=%02x\n", port, val);
switch (port & 0x0f) {
@@ -852,7 +852,7 @@ scsiat_out(uint16_t port, uint8_t val, void *priv)
if (ncr->unk_08 & 0x01)
{
ncr_dev->block_count_loaded = 1;
ncr_dev->block_count = dev->BufferLength / 128;
ncr_dev->block_count = dev->buffer_length / 128;
}
break;
@@ -875,8 +875,8 @@ ncr_callback(void *priv)
{
ncr5380_t *ncr_dev = (ncr5380_t *)priv;
ncr_t *ncr = &ncr_dev->ncr;
scsi_device_t *dev = &SCSIDevices[ncr->target_id];
int c = 0;
scsi_device_t *dev = &scsi_devices[ncr->target_id];
int req_len, c = 0;
int64_t p;
uint8_t temp, data;
@@ -887,7 +887,7 @@ ncr_callback(void *priv)
if (((ncr->state == STATE_DATAIN) || (ncr->state == STATE_DATAOUT)) && (ncr->dma_mode != DMA_IDLE))
ncr_dev->timer_period = (int64_t) ncr_dev->period;
else
ncr_dev->timer_period += 10LL * TIMER_USEC;
ncr_dev->timer_period += 40LL * TIMER_USEC;
if (ncr->dma_mode == DMA_IDLE) {
ncr->bus_host = get_bus_host(ncr);
@@ -909,7 +909,7 @@ ncr_callback(void *priv)
ncr_log("Select - target ID = %i\n", ncr->target_id);
/*Once the device has been found and selected, mark it as busy*/
if ((ncr->target_id != -1) && scsi_device_present(ncr->target_id)) {
if ((ncr->target_id != -1) && scsi_device_present(&scsi_devices[ncr->target_id])) {
ncr->cur_bus |= BUS_BSY;
ncr_log("Device found at ID %i\n", ncr->target_id);
ncr_log("Current Bus BSY=%02x\n", ncr->cur_bus);
@@ -943,35 +943,36 @@ ncr_callback(void *priv)
/*Reset data position to default*/
ncr->data_pos = 0;
dev = &SCSIDevices[ncr->target_id];
dev = &scsi_devices[ncr->target_id];
ncr_log("SCSI Command 0x%02X for ID %d, status code=%02x\n", ncr->command[0], ncr->target_id, dev->Status);
ncr_log("SCSI Command 0x%02X for ID %d, status code=%02x\n", ncr->command[0], ncr->target_id, dev->status);
dev->BufferLength = -1;
dev->buffer_length = -1;
/*Now, execute the given SCSI command*/
scsi_device_command_phase0(ncr->target_id, ncr->command);
scsi_device_command_phase0(dev, ncr->command);
ncr_log("SCSI ID %i: Command %02X: Buffer Length %i, SCSI Phase %02X\n", ncr->target_id, ncr->command[0], dev->BufferLength, dev->Phase);
ncr_log("SCSI ID %i: Command %02X: Buffer Length %i, SCSI Phase %02X\n", ncr->target_id, ncr->command[0], dev->buffer_length, dev->phase);
if (dev->Status != SCSI_STATUS_OK) {
if (dev->status != SCSI_STATUS_OK) {
ncr->new_phase = SCSI_PHASE_STATUS;
ncr->wait_data = 4;
return;
}
/*If the SCSI phase is Data In or Data Out, allocate the SCSI buffer based on the transfer length of the command*/
if (dev->BufferLength && (dev->Phase == SCSI_PHASE_DATA_IN || dev->Phase == SCSI_PHASE_DATA_OUT)) {
dev->CmdBuffer = (uint8_t *) malloc(dev->BufferLength);
if (dev->buffer_length && (dev->phase == SCSI_PHASE_DATA_IN || dev->phase == SCSI_PHASE_DATA_OUT)) {
dev->cmd_buffer = (uint8_t *) malloc(dev->buffer_length);
p = scsi_device_get_callback(ncr->target_id);
p = scsi_device_get_callback(dev);
req_len = MIN(64, dev->buffer_length);
if (p <= 0LL)
ncr_dev->period = 0.2 * ((double) TIMER_USEC) * ((double) MIN(64, dev->BufferLength));
ncr_dev->period = 0.2 * ((double) TIMER_USEC) * ((double) req_len);
else
ncr_dev->period = (p / ((double) dev->BufferLength)) * ((double) MIN(64, dev->BufferLength));
ncr_dev->period = (p / ((double) dev->buffer_length)) * ((double) req_len);
}
if (dev->Phase == SCSI_PHASE_DATA_OUT) {
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. */
ncr_log("Next state is data out\n");
ncr->new_phase = SCSI_PHASE_DATA_OUT;
@@ -979,23 +980,23 @@ ncr_callback(void *priv)
ncr->clear_req = 4;
} else {
/* Other command - execute immediately. */
ncr->new_phase = dev->Phase;
ncr->new_phase = dev->phase;
if (ncr->new_phase == SCSI_PHASE_DATA_IN)
scsi_device_command_phase1(ncr->target_id);
scsi_device_command_phase1(dev);
ncr->wait_data = 4;
}
}
}
} else if (ncr->state == STATE_DATAIN) {
dev = &SCSIDevices[ncr->target_id];
dev = &scsi_devices[ncr->target_id];
ncr_log("Data In ACK=%02x\n", ncr->bus_host & BUS_ACK);
if (ncr->bus_host & BUS_ACK) {
if (ncr->data_pos >= dev->BufferLength) {
if (dev->CmdBuffer != NULL) {
free(dev->CmdBuffer);
dev->CmdBuffer = NULL;
if (ncr->data_pos >= dev->buffer_length) {
if (dev->cmd_buffer != NULL) {
free(dev->cmd_buffer);
dev->cmd_buffer = NULL;
}
ncr->cur_bus &= ~BUS_REQ;
@@ -1003,7 +1004,7 @@ ncr_callback(void *priv)
ncr->wait_data = 4;
ncr->wait_complete = 8;
} else {
ncr->tx_data = dev->CmdBuffer[ncr->data_pos++];
ncr->tx_data = dev->cmd_buffer[ncr->data_pos++];
ncr->cur_bus = (ncr->cur_bus & ~BUS_DATAMASK) | BUS_SETDATA(ncr->tx_data) | BUS_DBP | BUS_REQ;
ncr->clear_req = 3;
ncr->cur_bus &= ~BUS_REQ;
@@ -1011,18 +1012,18 @@ ncr_callback(void *priv)
}
}
} else if (ncr->state == STATE_DATAOUT) {
dev = &SCSIDevices[ncr->target_id];
dev = &scsi_devices[ncr->target_id];
ncr_log("Data Out ACK=%02x\n", ncr->bus_host & BUS_ACK);
if (ncr->bus_host & BUS_ACK) {
dev->CmdBuffer[ncr->data_pos++] = BUS_GETDATA(ncr->bus_host);
dev->cmd_buffer[ncr->data_pos++] = BUS_GETDATA(ncr->bus_host);
if (ncr->data_pos >= dev->BufferLength) {
scsi_device_command_phase1(ncr->target_id);
if (ncr->data_pos >= dev->buffer_length) {
scsi_device_command_phase1(dev);
if (dev->CmdBuffer != NULL) {
free(dev->CmdBuffer);
dev->CmdBuffer = NULL;
if (dev->cmd_buffer != NULL) {
free(dev->cmd_buffer);
dev->cmd_buffer = NULL;
}
ncr->cur_bus &= ~BUS_REQ;
@@ -1073,10 +1074,10 @@ ncr_callback(void *priv)
temp = BUS_GETDATA(ncr->bus_host);
ncr->bus_host = get_bus_host(ncr);
if (ncr->data_pos >= dev->BufferLength) {
if (dev->CmdBuffer != NULL) {
free(dev->CmdBuffer);
dev->CmdBuffer = NULL;
if (ncr->data_pos >= dev->buffer_length) {
if (dev->cmd_buffer != NULL) {
free(dev->cmd_buffer);
dev->cmd_buffer = NULL;
}
ncr->cur_bus &= ~BUS_REQ;
@@ -1084,7 +1085,7 @@ ncr_callback(void *priv)
ncr->wait_data = 4;
ncr->wait_complete = 8;
} else {
ncr->tx_data = dev->CmdBuffer[ncr->data_pos++];
ncr->tx_data = dev->cmd_buffer[ncr->data_pos++];
ncr->cur_bus = (ncr->cur_bus & ~BUS_DATAMASK) | BUS_SETDATA(ncr->tx_data) | BUS_DBP | BUS_REQ;
ncr->clear_req = 3;
ncr->cur_bus &= ~BUS_REQ;
@@ -1139,14 +1140,14 @@ ncr_callback(void *priv)
ncr->bus_host = get_bus_host(ncr) & ~BUS_DATAMASK;
ncr->bus_host |= BUS_SETDATA(data);
dev->CmdBuffer[ncr->data_pos++] = BUS_GETDATA(ncr->bus_host);
dev->cmd_buffer[ncr->data_pos++] = BUS_GETDATA(ncr->bus_host);
if (ncr->data_pos >= dev->BufferLength) {
scsi_device_command_phase1(ncr->target_id);
if (ncr->data_pos >= dev->buffer_length) {
scsi_device_command_phase1(dev);
if (dev->CmdBuffer != NULL) {
free(dev->CmdBuffer);
dev->CmdBuffer = NULL;
if (dev->cmd_buffer != NULL) {
free(dev->cmd_buffer);
dev->cmd_buffer = NULL;
}
ncr->cur_bus &= ~BUS_REQ;
@@ -1196,10 +1197,10 @@ ncr_callback(void *priv)
temp = BUS_GETDATA(ncr->bus_host);
ncr->bus_host = get_bus_host(ncr);
if (ncr->data_pos >= dev->BufferLength) {
if (dev->CmdBuffer != NULL) {
free(dev->CmdBuffer);
dev->CmdBuffer = NULL;
if (ncr->data_pos >= dev->buffer_length) {
if (dev->cmd_buffer != NULL) {
free(dev->cmd_buffer);
dev->cmd_buffer = NULL;
}
ncr->cur_bus &= ~BUS_REQ;
@@ -1207,7 +1208,7 @@ ncr_callback(void *priv)
ncr->wait_data = 4;
ncr->wait_complete = 8;
} else {
ncr->tx_data = dev->CmdBuffer[ncr->data_pos++];
ncr->tx_data = dev->cmd_buffer[ncr->data_pos++];
ncr->cur_bus = (ncr->cur_bus & ~BUS_DATAMASK) | BUS_SETDATA(ncr->tx_data) | BUS_DBP | BUS_REQ;
ncr->clear_req = 3;
ncr->cur_bus &= ~BUS_REQ;
@@ -1248,14 +1249,14 @@ ncr_callback(void *priv)
ncr->bus_host = get_bus_host(ncr) & ~BUS_DATAMASK;
ncr->bus_host |= BUS_SETDATA(data);
dev->CmdBuffer[ncr->data_pos++] = BUS_GETDATA(ncr->bus_host);
dev->cmd_buffer[ncr->data_pos++] = BUS_GETDATA(ncr->bus_host);
if (ncr->data_pos >= dev->BufferLength) {
scsi_device_command_phase1(ncr->target_id);
if (ncr->data_pos >= dev->buffer_length) {
scsi_device_command_phase1(dev);
if (dev->CmdBuffer != NULL) {
free(dev->CmdBuffer);
dev->CmdBuffer = NULL;
if (dev->cmd_buffer != NULL) {
free(dev->cmd_buffer);
dev->cmd_buffer = NULL;
}
ncr->cur_bus &= ~BUS_REQ;

View File

@@ -10,7 +10,7 @@
* NCR and later Symbios and LSI. This controller was designed
* for the PCI bus.
*
* Version: @(#)scsi_ncr53c810.c 1.0.14 2018/05/28
* Version: @(#)scsi_ncr53c810.c 1.0.15 2018/10/09
*
* Authors: Paul Brook (QEMU)
* Artyom Tarasenko (QEMU)
@@ -391,8 +391,10 @@ ncr53c810_soft_reset(ncr53c810_t *dev)
dev->gpreg0 = 0;
dev->sstop = 1;
for (i = 0; i < 16; i++)
scsi_device_reset(i);
/* This is *NOT* a wide SCSI controller, so do not touch
SCSI devices with ID's >= 8. */
for (i = 0; i < 8; i++)
scsi_device_reset(&scsi_devices[i]);
}
@@ -595,11 +597,9 @@ ncr53c810_do_dma(ncr53c810_t *dev, int out, uint8_t id)
uint32_t addr, tdbc;
int count;
scsi_device_t *sd;
scsi_device_t *sd = &scsi_devices[id];
sd = &SCSIDevices[id];
if ((!scsi_device_present(id))) {
if ((!scsi_device_present(sd))) {
ncr53c810_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: Device not present when attempting to do DMA\n", id, dev->current_lun, dev->last_command);
return;
}
@@ -610,7 +610,7 @@ ncr53c810_do_dma(ncr53c810_t *dev, int out, uint8_t id)
return;
}
/* Make sure count is never bigger than BufferLength. */
/* Make sure count is never bigger than buffer_length. */
count = tdbc = dev->dbc;
if (count > dev->temp_buf_len)
count = dev->temp_buf_len;
@@ -622,13 +622,13 @@ ncr53c810_do_dma(ncr53c810_t *dev, int out, uint8_t id)
dev->dbc -= count;
if (out)
ncr53c810_read(dev, addr, sd->CmdBuffer+dev->buffer_pos, count);
ncr53c810_read(dev, addr, sd->cmd_buffer + dev->buffer_pos, count);
else {
if (!dev->buffer_pos) {
ncr53c810_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: SCSI Command Phase 1 on PHASE_DI\n", id, dev->current_lun, dev->last_command);
scsi_device_command_phase1(dev->current->tag);
scsi_device_command_phase1(&scsi_devices[dev->current->tag]);
}
ncr53c810_write(dev, addr, sd->CmdBuffer+dev->buffer_pos, count);
ncr53c810_write(dev, addr, sd->cmd_buffer + dev->buffer_pos, count);
}
dev->temp_buf_len -= count;
@@ -637,13 +637,13 @@ ncr53c810_do_dma(ncr53c810_t *dev, int out, uint8_t id)
if (dev->temp_buf_len <= 0) {
if (out) {
ncr53c810_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: SCSI Command Phase 1 on PHASE_DO\n", id, dev->current_lun, dev->last_command);
scsi_device_command_phase1(id);
scsi_device_command_phase1(&scsi_devices[id]);
}
if (sd->CmdBuffer != NULL) {
free(sd->CmdBuffer);
sd->CmdBuffer = NULL;
if (sd->cmd_buffer != NULL) {
free(sd->cmd_buffer);
sd->cmd_buffer = NULL;
}
ncr53c810_command_complete(dev, sd->Status);
ncr53c810_command_complete(dev, sd->status);
} else {
ncr53c810_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: Resume SCRIPTS\n", id, dev->current_lun, dev->last_command);
dev->sstop = 0;
@@ -683,8 +683,8 @@ ncr53c810_do_command(ncr53c810_t *dev, uint8_t id)
dev->sfbr = buf[0];
dev->command_complete = 0;
sd = &SCSIDevices[id];
if (!scsi_device_present(id)) {
sd = &scsi_devices[id];
if (!scsi_device_present(sd)) {
ncr53c810_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: Bad Selection\n", id, dev->current_lun, buf[0]);
ncr53c810_bad_selection(dev, id);
return 0;
@@ -693,46 +693,46 @@ ncr53c810_do_command(ncr53c810_t *dev, uint8_t id)
dev->current = (ncr53c810_request*)malloc(sizeof(ncr53c810_request));
dev->current->tag = id;
sd->BufferLength = -1;
sd->buffer_length = -1;
ncr53c810_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: DBC=%i\n", id, dev->current_lun, buf[0], dev->dbc);
dev->last_command = buf[0];
scsi_device_command_phase0(dev->current->tag, buf);
scsi_device_command_phase0(&scsi_devices[dev->current->tag], buf);
dev->hba_private = (void *)dev->current;
dev->waiting = 0;
dev->buffer_pos = 0;
dev->temp_buf_len = sd->BufferLength;
dev->temp_buf_len = sd->buffer_length;
if (sd->BufferLength > 0) {
sd->CmdBuffer = (uint8_t *)malloc(sd->BufferLength);
dev->current->dma_len = sd->BufferLength;
if (sd->buffer_length > 0) {
sd->cmd_buffer = (uint8_t *)malloc(sd->buffer_length);
dev->current->dma_len = sd->buffer_length;
}
if ((sd->Phase == SCSI_PHASE_DATA_IN) && (sd->BufferLength > 0)) {
if ((sd->phase == SCSI_PHASE_DATA_IN) && (sd->buffer_length > 0)) {
ncr53c810_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: PHASE_DI\n", id, dev->current_lun, buf[0]);
ncr53c810_set_phase(dev, PHASE_DI);
p = scsi_device_get_callback(dev->current->tag);
p = scsi_device_get_callback(&scsi_devices[dev->current->tag]);
if (p <= 0LL) {
period = ((double) sd->BufferLength) * 0.1 * ((double) TIMER_USEC); /* Fast SCSI: 10000000 bytes per second */
period = ((double) sd->buffer_length) * 0.1 * ((double) TIMER_USEC); /* Fast SCSI: 10000000 bytes per second */
dev->timer_period += (int64_t) period;
} else
dev->timer_period += p;
return 1;
} else if ((sd->Phase == SCSI_PHASE_DATA_OUT) && (sd->BufferLength > 0)) {
} else if ((sd->phase == SCSI_PHASE_DATA_OUT) && (sd->buffer_length > 0)) {
ncr53c810_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: PHASE_DO\n", id, buf[0]);
ncr53c810_set_phase(dev, PHASE_DO);
p = scsi_device_get_callback(dev->current->tag);
p = scsi_device_get_callback(&scsi_devices[dev->current->tag]);
if (p <= 0LL) {
period = ((double) sd->BufferLength) * 0.1 * ((double) TIMER_USEC); /* Fast SCSI: 10000000 bytes per second */
period = ((double) sd->buffer_length) * 0.1 * ((double) TIMER_USEC); /* Fast SCSI: 10000000 bytes per second */
dev->timer_period += (int64_t) period;
} else
dev->timer_period += p;
return 1;
} else {
ncr53c810_command_complete(dev, sd->Status);
ncr53c810_command_complete(dev, sd->status);
return 0;
}
}
@@ -832,7 +832,7 @@ ncr53c810_do_msgout(ncr53c810_t *dev, uint8_t id)
uint32_t current_tag;
scsi_device_t *sd;
sd = &SCSIDevices[id];
sd = &scsi_devices[id];
current_tag = id;
@@ -884,9 +884,9 @@ ncr53c810_do_msgout(ncr53c810_t *dev, uint8_t id)
case 0x0d:
/* The ABORT TAG message clears the current I/O process only. */
ncr53c810_log("MSG: ABORT TAG tag=0x%x\n", current_tag);
if (sd->CmdBuffer) {
free(sd->CmdBuffer);
sd->CmdBuffer = NULL;
if (sd->cmd_buffer) {
free(sd->cmd_buffer);
sd->cmd_buffer = NULL;
}
ncr53c810_disconnect(dev);
break;
@@ -907,9 +907,9 @@ ncr53c810_do_msgout(ncr53c810_t *dev, uint8_t id)
ncr53c810_log("MSG: BUS DEVICE RESET tag=0x%x\n", current_tag);
/* clear the current I/O process */
if (sd->CmdBuffer) {
free(sd->CmdBuffer);
sd->CmdBuffer = NULL;
if (sd->cmd_buffer) {
free(sd->cmd_buffer);
sd->cmd_buffer = NULL;
}
ncr53c810_disconnect(dev);
break;
@@ -1078,7 +1078,7 @@ again:
}
dev->sstat0 |= NCR_SSTAT0_WOA;
dev->scntl1 &= ~NCR_SCNTL1_IARB;
if (!scsi_device_present(id)) {
if (!scsi_device_present(&scsi_devices[id])) {
ncr53c810_bad_selection(dev, id);
break;
}

View File

@@ -11,7 +11,7 @@
* series of SCSI Host Adapters made by Mylex.
* These controllers were designed for various buses.
*
* Version: @(#)scsi_x54x.c 1.0.22 2018/10/02
* Version: @(#)scsi_x54x.c 1.0.23 2018/10/09
*
* Authors: TheCollector1995, <mariogplayer@gmail.com>
* Miran Grca, <mgrca8@gmail.com>
@@ -155,9 +155,8 @@ clear_irq(x54x_t *dev)
static void
target_check(uint8_t id)
{
if (! scsi_device_valid(id)) {
if (! scsi_device_valid(&scsi_devices[id]))
fatal("BIOS INT13 device on ID %02i has disappeared\n", id);
}
}
@@ -237,9 +236,10 @@ x54x_bios_command_08(uint8_t id, uint8_t *buffer)
uint8_t rcbuf[8] = { 0,0,0,0,0,0,0,0 };
uint32_t len = 0;
int i, ret, sc;
scsi_device_t *sd = &scsi_devices[id];
ret = scsi_device_read_capacity(id, cdb, rcbuf, &len);
sc = completion_code(scsi_device_sense(id));
ret = scsi_device_read_capacity(sd, cdb, rcbuf, &len);
sc = completion_code(scsi_device_sense(sd));
if (ret == 0) return(sc);
memset(buffer, 0x00, 6);
@@ -261,15 +261,16 @@ x54x_bios_command_15(uint8_t id, uint8_t *buffer)
uint8_t rcbuf[8] = { 0,0,0,0,0,0,0,0 };
uint32_t len = 0;
int i, ret, sc;
scsi_device_t *sd = &scsi_devices[id];
ret = scsi_device_read_capacity(id, cdb, rcbuf, &len);
sc = completion_code(scsi_device_sense(id));
ret = scsi_device_read_capacity(sd, cdb, rcbuf, &len);
sc = completion_code(scsi_device_sense(sd));
memset(buffer, 0x00, 6);
for (i=0; i<4; i++)
buffer[i] = (ret == 0) ? 0 : rcbuf[i];
scsi_device_type_data(id, &(buffer[4]), &(buffer[5]));
scsi_device_type_data(sd, &(buffer[4]), &(buffer[5]));
x54x_log("BIOS Command 0x15: %02X %02X %02X %02X %02X %02X\n",
buffer[0], buffer[1], buffer[2], buffer[3], buffer[4], buffer[5]);
@@ -308,15 +309,15 @@ x54x_bios_command(x54x_t *x54x, uint8_t max_id, BIOSCMD *cmd, int8_t islba)
}
/* Get pointer to selected device. */
dev = &SCSIDevices[cmd->id];
dev->BufferLength = 0;
dev = &scsi_devices[cmd->id];
dev->buffer_length = 0;
if (! scsi_device_present(cmd->id)) {
if (! scsi_device_present(dev)) {
x54x_log("BIOS Target ID %i has no device attached\n", cmd->id);
return(0x80);
}
if ((dev->LunType == SCSI_CDROM) && !x54x->cdrom_boot) {
if ((dev->type == SCSI_REMOVABLE_CDROM) && !x54x->cdrom_boot) {
x54x_log("BIOS Target ID %i is CD-ROM on unsupported BIOS\n", cmd->id);
return(0x80);
}
@@ -326,9 +327,9 @@ x54x_bios_command(x54x_t *x54x, uint8_t max_id, BIOSCMD *cmd, int8_t islba)
x54x_log("BIOS Data Buffer write: length %d, pointer 0x%04X\n",
sector_len, dma_address);
if (dev->CmdBuffer != NULL) {
free(dev->CmdBuffer);
dev->CmdBuffer = NULL;
if (dev->cmd_buffer != NULL) {
free(dev->cmd_buffer);
dev->cmd_buffer = NULL;
}
switch(cmd->command) {
@@ -343,20 +344,20 @@ x54x_bios_command(x54x_t *x54x, uint8_t max_id, BIOSCMD *cmd, int8_t islba)
* length for SCSI sense, and no command-specific
* indication is given.
*/
dev->BufferLength = 14;
dev->CmdBuffer = (uint8_t *)malloc(14);
memset(dev->CmdBuffer, 0x00, 14);
dev->buffer_length = 14;
dev->cmd_buffer = (uint8_t *)malloc(14);
memset(dev->cmd_buffer, 0x00, 14);
if (sector_len > 0) {
x54x_log("BIOS DMA: Reading 14 bytes at %08X\n",
dma_address);
DMAPageWrite(dma_address,
scsi_device_sense(cmd->id), 14);
scsi_device_sense(dev), 14);
}
if (dev->CmdBuffer != NULL) {
free(dev->CmdBuffer);
dev->CmdBuffer = NULL;
if (dev->cmd_buffer != NULL) {
free(dev->cmd_buffer);
dev->cmd_buffer = NULL;
}
return(0);
@@ -364,7 +365,7 @@ x54x_bios_command(x54x_t *x54x, uint8_t max_id, BIOSCMD *cmd, int8_t islba)
case 0x02: /* Read Desired Sectors to Memory */
target_check(cmd->id);
dev->BufferLength = -1;
dev->buffer_length = -1;
cdb[0] = GPCMD_READ_10;
cdb[1] = (cmd->lun & 7) << 5;
@@ -378,33 +379,33 @@ x54x_bios_command(x54x_t *x54x, uint8_t max_id, BIOSCMD *cmd, int8_t islba)
x54x_log("BIOS CMD(READ, %08lx, %d)\n", lba, cmd->secount);
#endif
scsi_device_command_phase0(cmd->id, cdb);
scsi_device_command_phase0(dev, cdb);
if (dev->Phase == SCSI_PHASE_STATUS)
if (dev->phase == SCSI_PHASE_STATUS)
goto skip_read_phase1;
dev->CmdBuffer = (uint8_t *)malloc(dev->BufferLength);
dev->cmd_buffer = (uint8_t *)malloc(dev->buffer_length);
scsi_device_command_phase1(cmd->id);
scsi_device_command_phase1(dev);
if (sector_len > 0) {
x54x_log("BIOS DMA: Reading %i bytes at %08X\n",
dev->BufferLength, dma_address);
dev->buffer_length, dma_address);
DMAPageWrite(dma_address,
dev->CmdBuffer, dev->BufferLength);
dev->cmd_buffer, dev->buffer_length);
}
skip_read_phase1:
if (dev->CmdBuffer != NULL) {
free(dev->CmdBuffer);
dev->CmdBuffer = NULL;
if (dev->cmd_buffer != NULL) {
free(dev->cmd_buffer);
dev->cmd_buffer = NULL;
}
return(completion_code(scsi_device_sense(cmd->id)));
return(completion_code(scsi_device_sense(dev)));
case 0x03: /* Write Desired Sectors from Memory */
target_check(cmd->id);
dev->BufferLength = -1;
dev->buffer_length = -1;
cdb[0] = GPCMD_WRITE_10;
cdb[1] = (cmd->lun & 7) << 5;
@@ -418,29 +419,29 @@ skip_read_phase1:
x54x_log("BIOS CMD(WRITE, %08lx, %d)\n", lba, cmd->secount);
#endif
scsi_device_command_phase0(cmd->id, cdb);
scsi_device_command_phase0(dev, cdb);
if (dev->Phase == SCSI_PHASE_STATUS)
if (dev->phase == SCSI_PHASE_STATUS)
goto skip_write_phase1;
dev->CmdBuffer = (uint8_t *)malloc(dev->BufferLength);
dev->cmd_buffer = (uint8_t *)malloc(dev->buffer_length);
if (sector_len > 0) {
x54x_log("BIOS DMA: Reading %i bytes at %08X\n",
dev->BufferLength, dma_address);
dev->buffer_length, dma_address);
DMAPageRead(dma_address,
dev->CmdBuffer, dev->BufferLength);
dev->cmd_buffer, dev->buffer_length);
}
scsi_device_command_phase1(cmd->id);
scsi_device_command_phase1(dev);
skip_write_phase1:
if (dev->CmdBuffer != NULL) {
free(dev->CmdBuffer);
dev->CmdBuffer = NULL;
if (dev->cmd_buffer != NULL) {
free(dev->cmd_buffer);
dev->cmd_buffer = NULL;
}
return(completion_code(scsi_device_sense(cmd->id)));
return(completion_code(scsi_device_sense(dev)));
case 0x04: /* Verify Desired Sectors */
target_check(cmd->id);
@@ -454,9 +455,9 @@ skip_write_phase1:
cdb[7] = 0;
cdb[8] = sector_len;
scsi_device_command_phase0(cmd->id, cdb);
scsi_device_command_phase0(dev, cdb);
return(completion_code(scsi_device_sense(cmd->id)));
return(completion_code(scsi_device_sense(dev)));
case 0x05: /* Format Track, invalid since SCSI has no tracks */
//FIXME: add a longer delay here --FvK
@@ -472,26 +473,26 @@ skip_write_phase1:
cdb[0] = GPCMD_FORMAT_UNIT;
cdb[1] = (cmd->lun & 7) << 5;
scsi_device_command_phase0(cmd->id, cdb);
scsi_device_command_phase0(dev, cdb);
return(completion_code(scsi_device_sense(cmd->id)));
return(completion_code(scsi_device_sense(dev)));
case 0x08: /* Read Drive Parameters */
target_check(cmd->id);
dev->BufferLength = 6;
dev->CmdBuffer = (uint8_t *)malloc(dev->BufferLength);
memset(dev->CmdBuffer, 0x00, dev->BufferLength);
dev->buffer_length = 6;
dev->cmd_buffer = (uint8_t *)malloc(dev->buffer_length);
memset(dev->cmd_buffer, 0x00, dev->buffer_length);
ret = x54x_bios_command_08(cmd->id, dev->CmdBuffer);
ret = x54x_bios_command_08(cmd->id, dev->cmd_buffer);
x54x_log("BIOS DMA: Reading 6 bytes at %08X\n", dma_address);
DMAPageWrite(dma_address,
dev->CmdBuffer, 4 /* dev->BufferLength */);
dev->cmd_buffer, 4 /* dev->buffer_length */);
if (dev->CmdBuffer != NULL) {
free(dev->CmdBuffer);
dev->CmdBuffer = NULL;
if (dev->cmd_buffer != NULL) {
free(dev->cmd_buffer);
dev->cmd_buffer = NULL;
}
return(ret);
@@ -510,9 +511,9 @@ skip_write_phase1:
cdb[4] = (lba >> 8) & 0xff;
cdb[5] = lba & 0xff;
scsi_device_command_phase0(cmd->id, cdb);
scsi_device_command_phase0(dev, cdb);
return((dev->Status == SCSI_STATUS_OK) ? 1 : 0);
return((dev->status == SCSI_STATUS_OK) ? 1 : 0);
case 0x0d: /* Alternate Disk Reset, in practice it's a nop */
//FIXME: add a longer delay here --FvK
@@ -524,9 +525,9 @@ skip_write_phase1:
cdb[0] = GPCMD_TEST_UNIT_READY;
cdb[1] = (cmd->lun & 7) << 5;
scsi_device_command_phase0(cmd->id, cdb);
scsi_device_command_phase0(dev, cdb);
return(completion_code(scsi_device_sense(cmd->id)));
return(completion_code(scsi_device_sense(dev)));
case 0x11: /* Recalibrate */
target_check(cmd->id);
@@ -534,9 +535,9 @@ skip_write_phase1:
cdb[0] = GPCMD_REZERO_UNIT;
cdb[1] = (cmd->lun & 7) << 5;
scsi_device_command_phase0(cmd->id, cdb);
scsi_device_command_phase0(dev, cdb);
return(completion_code(scsi_device_sense(cmd->id)));
return(completion_code(scsi_device_sense(dev)));
case 0x14: /* Controller Diagnostic */
//FIXME: add a longer delay here --FvK
@@ -545,19 +546,19 @@ skip_write_phase1:
case 0x15: /* Read DASD Type */
target_check(cmd->id);
dev->BufferLength = 6;
dev->CmdBuffer = (uint8_t *)malloc(dev->BufferLength);
memset(dev->CmdBuffer, 0x00, dev->BufferLength);
dev->buffer_length = 6;
dev->cmd_buffer = (uint8_t *)malloc(dev->buffer_length);
memset(dev->cmd_buffer, 0x00, dev->buffer_length);
ret = x54x_bios_command_15(cmd->id, dev->CmdBuffer);
ret = x54x_bios_command_15(cmd->id, dev->cmd_buffer);
x54x_log("BIOS DMA: Reading 6 bytes at %08X\n", dma_address);
DMAPageWrite(dma_address,
dev->CmdBuffer, 4 /* dev->BufferLength */);
dev->cmd_buffer, 4 /* dev->buffer_length */);
if (dev->CmdBuffer != NULL) {
free(dev->CmdBuffer);
dev->CmdBuffer = NULL;
if (dev->cmd_buffer != NULL) {
free(dev->cmd_buffer);
dev->cmd_buffer = NULL;
}
return(ret);
@@ -761,7 +762,7 @@ x54x_set_residue(Req_t *req, int32_t TransferLength)
{
uint32_t Residue = 0;
addr24 Residue24;
int32_t BufLen = SCSIDevices[req->TargetID].BufferLength;
int32_t BufLen = scsi_devices[req->TargetID].buffer_length;
if ((req->CmdBlock.common.Opcode == SCSI_INITIATOR_COMMAND_RES) ||
(req->CmdBlock.common.Opcode == SCATTER_GATHER_COMMAND_RES)) {
@@ -792,7 +793,7 @@ x54x_buf_dma_transfer(Req_t *req, int Is24bit, int TransferLength, int dir)
uint32_t DataPointer, DataLength;
uint32_t SGEntryLength = (Is24bit ? sizeof(SGE) : sizeof(SGE32));
uint32_t Address, i;
int32_t BufLen = SCSIDevices[req->TargetID].BufferLength;
int32_t BufLen = scsi_devices[req->TargetID].buffer_length;
uint8_t read_from_host = (dir && ((req->CmdBlock.common.ControlByte == CCB_DATA_XFER_OUT) || (req->CmdBlock.common.ControlByte == 0x00)));
uint8_t write_to_host = (!dir && ((req->CmdBlock.common.ControlByte == CCB_DATA_XFER_IN) || (req->CmdBlock.common.ControlByte == 0x00)));
int sg_pos = 0;
@@ -824,11 +825,11 @@ x54x_buf_dma_transfer(Req_t *req, int Is24bit, int TransferLength, int dir)
if (read_from_host && DataToTransfer) {
x54x_log("Reading S/G segment %i: length %i, pointer %08X\n", i, DataToTransfer, Address);
DMAPageRead(Address, &(SCSIDevices[req->TargetID].CmdBuffer[sg_pos]), DataToTransfer);
DMAPageRead(Address, &(scsi_devices[req->TargetID].cmd_buffer[sg_pos]), DataToTransfer);
}
else if (write_to_host && DataToTransfer) {
x54x_log("Writing S/G segment %i: length %i, pointer %08X\n", i, DataToTransfer, Address);
DMAPageWrite(Address, &(SCSIDevices[req->TargetID].CmdBuffer[sg_pos]), DataToTransfer);
DMAPageWrite(Address, &(scsi_devices[req->TargetID].cmd_buffer[sg_pos]), DataToTransfer);
}
else
x54x_log("No action on S/G segment %i: length %i, pointer %08X\n", i, DataToTransfer, Address);
@@ -848,9 +849,9 @@ x54x_buf_dma_transfer(Req_t *req, int Is24bit, int TransferLength, int dir)
if ((DataLength > 0) && (BufLen > 0) && (req->CmdBlock.common.ControlByte < 0x03)) {
if (read_from_host)
DMAPageRead(Address, SCSIDevices[req->TargetID].CmdBuffer, MIN(BufLen, (int) DataLength));
DMAPageRead(Address, scsi_devices[req->TargetID].cmd_buffer, MIN(BufLen, (int) DataLength));
else if (write_to_host)
DMAPageWrite(Address, SCSIDevices[req->TargetID].CmdBuffer, MIN(BufLen, (int) DataLength));
DMAPageWrite(Address, scsi_devices[req->TargetID].cmd_buffer, MIN(BufLen, (int) DataLength));
}
}
}
@@ -860,23 +861,23 @@ x54x_buf_dma_transfer(Req_t *req, int Is24bit, int TransferLength, int dir)
void
x54x_buf_alloc(uint8_t id, int length)
{
if (SCSIDevices[id].CmdBuffer != NULL) {
free(SCSIDevices[id].CmdBuffer);
SCSIDevices[id].CmdBuffer = NULL;
if (scsi_devices[id].cmd_buffer != NULL) {
free(scsi_devices[id].cmd_buffer);
scsi_devices[id].cmd_buffer = NULL;
}
x54x_log("Allocating data buffer (%i bytes)\n", length);
SCSIDevices[id].CmdBuffer = (uint8_t *) malloc(length);
memset(SCSIDevices[id].CmdBuffer, 0, length);
scsi_devices[id].cmd_buffer = (uint8_t *) malloc(length);
memset(scsi_devices[id].cmd_buffer, 0, length);
}
void
x54x_buf_free(uint8_t id)
{
if (SCSIDevices[id].CmdBuffer != NULL) {
free(SCSIDevices[id].CmdBuffer);
SCSIDevices[id].CmdBuffer = NULL;
if (scsi_devices[id].cmd_buffer != NULL) {
free(scsi_devices[id].cmd_buffer);
scsi_devices[id].cmd_buffer = NULL;
}
}
@@ -920,7 +921,7 @@ SenseBufferFree(Req_t *req, int Copy)
uint8_t temp_sense[256];
if (SenseLength && Copy) {
scsi_device_request_sense(req->TargetID, temp_sense, SenseLength);
scsi_device_request_sense(&scsi_devices[req->TargetID], temp_sense, SenseLength);
/*
* The sense address, in 32-bit mode, is located in the
@@ -945,24 +946,22 @@ static void
x54x_scsi_cmd(x54x_t *dev)
{
Req_t *req = &dev->Req;
uint8_t id, lun;
uint8_t id, lun, phase, bit24 = !!req->Is24bit;
uint8_t temp_cdb[12];
uint32_t i;
int target_cdb_len = 12;
int target_data_len;
uint8_t bit24 = !!req->Is24bit;
uint32_t i, SenseBufferAddress;
int target_data_len, target_cdb_len = 12;
int32_t *BufLen;
uint8_t phase;
uint32_t SenseBufferAddress;
int64_t p;
scsi_device_t *sd;
id = req->TargetID;
sd = &scsi_devices[id];
lun = req->LUN;
target_cdb_len = 12;
target_data_len = x54x_get_length(req, bit24);
if (!scsi_device_valid(id))
if (!scsi_device_valid(sd))
fatal("SCSI target on %02i has disappeared\n", id);
x54x_log("target_data_len = %i\n", target_data_len);
@@ -985,14 +984,14 @@ x54x_scsi_cmd(x54x_t *dev)
dev->Residue = 0;
BufLen = scsi_device_get_buf_len(id);
BufLen = scsi_device_get_buf_len(sd);
*BufLen = target_data_len;
x54x_log("Command buffer: %08X\n", SCSIDevices[id].CmdBuffer);
x54x_log("Command buffer: %08X\n", scsi_devices[id].cmd_buffer);
scsi_device_command_phase0(id, temp_cdb);
scsi_device_command_phase0(sd, temp_cdb);
phase = SCSIDevices[id].Phase;
phase = sd->phase;
x54x_log("Control byte: %02X\n", (req->CmdBlock.common.ControlByte == 0x03));
@@ -1001,14 +1000,14 @@ x54x_scsi_cmd(x54x_t *dev)
/* Request sense in non-data mode - sense goes to sense buffer. */
*BufLen = ConvertSenseLength(req->CmdBlock.common.RequestSenseLength);
x54x_buf_alloc(id, *BufLen);
scsi_device_command_phase1(id);
if ((SCSIDevices[id].Status != SCSI_STATUS_OK) && (*BufLen > 0)) {
scsi_device_command_phase1(sd);
if ((sd->status != SCSI_STATUS_OK) && (*BufLen > 0)) {
SenseBufferAddress = SenseBufferPointer(req);
DMAPageWrite(SenseBufferAddress, SCSIDevices[id].CmdBuffer, *BufLen);
DMAPageWrite(SenseBufferAddress, scsi_devices[id].cmd_buffer, *BufLen);
x54x_add_to_period(*BufLen);
}
} else {
p = scsi_device_get_callback(id);
p = scsi_device_get_callback(sd);
if (p <= 0LL)
x54x_add_to_period(*BufLen);
else
@@ -1016,14 +1015,14 @@ x54x_scsi_cmd(x54x_t *dev)
x54x_buf_alloc(id, MIN(target_data_len, *BufLen));
if (phase == SCSI_PHASE_DATA_OUT)
x54x_buf_dma_transfer(req, bit24, target_data_len, 1);
scsi_device_command_phase1(id);
scsi_device_command_phase1(sd);
if (phase == SCSI_PHASE_DATA_IN)
x54x_buf_dma_transfer(req, bit24, target_data_len, 0);
SenseBufferFree(req, (SCSIDevices[id].Status != SCSI_STATUS_OK));
SenseBufferFree(req, (sd->status != SCSI_STATUS_OK));
}
} else
SenseBufferFree(req, (SCSIDevices[id].Status != SCSI_STATUS_OK));
SenseBufferFree(req, (sd->status != SCSI_STATUS_OK));
x54x_set_residue(req, target_data_len);
@@ -1031,15 +1030,15 @@ x54x_scsi_cmd(x54x_t *dev)
x54x_log("Request complete\n");
if (SCSIDevices[id].Status == SCSI_STATUS_OK) {
if (sd->status == SCSI_STATUS_OK) {
x54x_mbi_setup(dev, req->CCBPointer, &req->CmdBlock,
CCB_COMPLETE, SCSI_STATUS_OK, MBI_SUCCESS);
} else if (SCSIDevices[id].Status == SCSI_STATUS_CHECK_CONDITION) {
} else if (sd->status == SCSI_STATUS_CHECK_CONDITION) {
x54x_mbi_setup(dev, req->CCBPointer, &req->CmdBlock,
CCB_COMPLETE, SCSI_STATUS_CHECK_CONDITION, MBI_ERROR);
}
x54x_log("SCSIDevices[%02i].Status = %02X\n", id, SCSIDevices[id].Status);
x54x_log("scsi_devices[%02i].Status = %02X\n", id, sd->status);
}
@@ -1058,6 +1057,7 @@ x54x_req_setup(x54x_t *dev, uint32_t CCBPointer, Mailbox32_t *Mailbox32)
{
Req_t *req = &dev->Req;
uint8_t id, lun;
scsi_device_t *sd;
/* Fetch data from the Command Control Block. */
DMAPageRead(CCBPointer, (uint8_t *)&req->CmdBlock, sizeof(CCB32));
@@ -1069,6 +1069,7 @@ x54x_req_setup(x54x_t *dev, uint32_t CCBPointer, Mailbox32_t *Mailbox32)
req->LUN = dev->Mbx24bit ? req->CmdBlock.old.Lun : req->CmdBlock.new.Lun;
id = req->TargetID;
sd = &scsi_devices[id];
lun = req->LUN;
if ((id > dev->max_id) || (lun > 7)) {
x54x_log("SCSI Target ID %i or LUN %i is not valid\n",id,lun);
@@ -1081,10 +1082,10 @@ x54x_req_setup(x54x_t *dev, uint32_t CCBPointer, Mailbox32_t *Mailbox32)
x54x_log("Scanning SCSI Target ID %i\n", id);
SCSIDevices[id].Status = SCSI_STATUS_OK;
sd->status = SCSI_STATUS_OK;
/* If there is no device at ID:0, timeout the selection - the LUN is then checked later. */
if (! scsi_device_present(id)) {
if (! scsi_device_present(sd)) {
x54x_log("SCSI Target ID %i and LUN %i have no device attached\n",id,lun);
x54x_mbi_setup(dev, CCBPointer, &req->CmdBlock,
CCB_SELECTION_TIMEOUT, SCSI_STATUS_OK, MBI_ERROR);
@@ -1106,7 +1107,7 @@ x54x_req_setup(x54x_t *dev, uint32_t CCBPointer, Mailbox32_t *Mailbox32)
}
if (req->CmdBlock.common.Opcode == 0x81) {
x54x_log("Bus reset opcode\n");
scsi_device_reset(id);
scsi_device_reset(sd);
x54x_mbi_setup(dev, req->CCBPointer, &req->CmdBlock,
CCB_COMPLETE, SCSI_STATUS_OK, MBI_SUCCESS);
x54x_log("%s: Callback: Send incoming mailbox\n", dev->name);
@@ -1443,7 +1444,7 @@ x54x_reset(x54x_t *dev)
/* Reset all devices on controller reset. */
for (i = 0; i < 16; i++)
scsi_device_reset(i);
scsi_device_reset(&scsi_devices[i]);
if (dev->ven_reset)
dev->ven_reset(dev);
@@ -1500,7 +1501,7 @@ x54x_out(uint16_t port, uint8_t val, void *priv)
if (val & CTRL_SCRST) {
/* Reset all devices on SCSI bus reset. */
for (i = 0; i < 16; i++)
scsi_device_reset(i);
scsi_device_reset(&scsi_devices[i]);
}
if (val & CTRL_IRST) {
@@ -1677,7 +1678,7 @@ x54x_out(uint16_t port, uint8_t val, void *priv)
if (i == host_id) continue;
/* TODO: Query device for LUN's. */
if (scsi_device_present(i))
if (scsi_device_present(&scsi_devices[i]))
dev->DataBuf[i] |= 1;
}
dev->DataReplyLeft = i;
@@ -1685,9 +1686,9 @@ x54x_out(uint16_t port, uint8_t val, void *priv)
case CMD_RETCONF: /* return Configuration */
if (dev->ven_get_dma)
dev->DataBuf[0] = (1<<dev->ven_get_dma(dev));
dev->DataBuf[0] = (1 << dev->ven_get_dma(dev));
else
dev->DataBuf[0] = (1<<dev->DmaChannel);
dev->DataBuf[0] = (1 << dev->DmaChannel);
if (dev->ven_get_irq)
irq = dev->ven_get_irq(dev);