/scsi.cpp
C++ | 5735 lines | 4966 code | 661 blank | 108 comment | 1757 complexity | 926e04a3dba70969a5bd22aed068e453 MD5 | raw file
Large files files are truncated, but you can click here to view the full file
- /*
- * UAE - The Un*x Amiga Emulator
- *
- * SCSI and SASI emulation (not uaescsi.device)
- *
- * Copyright 2007-2015 Toni Wilen
- *
- */
- #include "sysconfig.h"
- #include "sysdeps.h"
- #include "options.h"
- #include "filesys.h"
- #include "blkdev.h"
- #include "zfile.h"
- #include "debug.h"
- #include "memory.h"
- #include "scsi.h"
- #include "autoconf.h"
- #include "rommgr.h"
- #include "newcpu.h"
- #include "custom.h"
- #include "gayle.h"
- #include "cia.h"
- #include "devices.h"
- #include "flashrom.h"
- #include "gui.h"
- #define SCSI_EMU_DEBUG 0
- #define RAW_SCSI_DEBUG 0
- #define NCR5380_DEBUG 0
- #define NCR5380_DEBUG_IRQ 0
- #define NCR53400_DEBUG 0
- #define NCR5380_SUPRA 1
- #define NONCR_GOLEM 2
- #define NCR5380_STARDRIVE 3
- #define NONCR_KOMMOS 4
- #define NONCR_VECTOR 5
- #define NONCR_APOLLO 6
- #define NCR5380_PROTAR 7
- #define NCR5380_ADD500 8
- #define NCR5380_KRONOS 9
- #define NCR5380_ADSCSI 10
- #define NCR5380_ROCHARD 11
- #define NCR5380_CLTD 12
- #define NCR5380_PTNEXUS 13
- #define NCR5380_DATAFLYER 14
- #define NONCR_TECMAR 15
- #define NCR5380_XEBEC 16
- #define NONCR_MICROFORGE 17
- #define NONCR_PARADOX 18
- #define OMTI_HDA506 19
- #define OMTI_ALF1 20
- #define OMTI_PROMIGOS 21
- #define OMTI_SYSTEM2000 22
- #define OMTI_ADAPTER 23
- #define NCR5380_X86_RT1000 24
- #define NCR5380_PHOENIXBOARD 25
- #define NCR5380_TRUMPCARDPRO 26
- #define NCR5380_IVSVECTOR 27 // nearly identical to trumpcard pro
- #define NCR5380_SCRAM 28
- #define NCR5380_OSSI 29
- #define NCR5380_DATAFLYERPLUS 30
- #define NONCR_HARDFRAME 31
- #define NCR5380_MALIBU 32
- #define NCR5380_ADDHARD 33
- #define NONCR_INMATE 34
- #define NCR5380_EMPLANT 35
- #define OMTI_HD3000 36
- #define OMTI_WEDGE 37
- #define NCR5380_EVESHAMREF 38
- #define OMTI_PROFEX 39
- #define NCR5380_FASTTRAK 40
- #define NCR5380_12GAUGE 41
- #define NCR5380_OVERDRIVE 42
- #define NCR5380_TRUMPCARD 43
- #define OMTI_ALF2 44
- #define NCR5380_SYNTHESIS 45 // clone of ICD AdSCSI
- #define NCR5380_FIREBALL 46
- #define OMTI_HD20 47
- #define NCR_LAST 48
- extern int log_scsiemu;
- static const uae_s16 outcmd[] = { 0x04, 0x0a, 0x0c, 0x11, 0x2a, 0xaa, 0x15, 0x55, 0x0f, -1 };
- static const uae_s16 incmd[] = { 0x01, 0x03, 0x08, 0x0e, 0x12, 0x1a, 0x5a, 0x25, 0x28, 0x34, 0x37, 0x42, 0x43, 0xa8, 0x51, 0x52, 0xb9, 0xbd, 0xd8, 0xd9, 0xbe, -1 };
- static const uae_s16 nonecmd[] = { 0x00, 0x05, 0x06, 0x07, 0x09, 0x0b, 0x10, 0x16, 0x17, 0x19, 0x1b, 0x1d, 0x1e, 0x2b, 0x35, 0x45, 0x47, 0x48, 0x49, 0x4b, 0x4e, 0xa5, 0xa9, 0xba, 0xbc, 0xe0, 0xe3, 0xe4, -1 };
- static const uae_s16 safescsi[] = { 0x00, 0x01, 0x03, 0x08, 0x0e, 0x0f, 0x12, 0x1a, 0x1b, 0x25, 0x28, 0x35, 0x5a, -1 };
- static const uae_s16 scsicmdsizes[] = { 6, 10, 10, 12, 16, 12, 10, 6 };
- static void scsi_illegal_command(struct scsi_data *sd)
- {
- uae_u8 *s = sd->sense;
- memset (s, 0, sizeof (sd->sense));
- sd->status = SCSI_STATUS_CHECK_CONDITION;
- s[0] = 0x70;
- s[2] = 5; /* ILLEGAL REQUEST */
- s[12] = 0x24; /* ILLEGAL FIELD IN CDB */
- sd->sense_len = 0x12;
- }
- static void scsi_grow_buffer(struct scsi_data *sd, int newsize)
- {
- if (sd->buffer_size >= newsize)
- return;
- uae_u8 *oldbuf = sd->buffer;
- int oldsize = sd->buffer_size;
- sd->buffer_size = newsize + SCSI_DEFAULT_DATA_BUFFER_SIZE;
- write_log(_T("SCSI buffer %d -> %d\n"), oldsize, sd->buffer_size);
- sd->buffer = xmalloc(uae_u8, sd->buffer_size);
- memcpy(sd->buffer, oldbuf, oldsize);
- xfree(oldbuf);
- }
- static int scsi_data_dir(struct scsi_data *sd)
- {
- int i;
- uae_u8 cmd;
- cmd = sd->cmd[0];
- for (i = 0; outcmd[i] >= 0; i++) {
- if (cmd == outcmd[i]) {
- return 1;
- }
- }
- for (i = 0; incmd[i] >= 0; i++) {
- if (cmd == incmd[i]) {
- return -1;
- }
- }
- for (i = 0; nonecmd[i] >= 0; i++) {
- if (cmd == nonecmd[i]) {
- return 0;
- }
- }
- write_log (_T("SCSI command %02X, no direction specified!\n"), sd->cmd[0]);
- return 0;
- }
- bool scsi_emulate_analyze (struct scsi_data *sd)
- {
- int cmd_len, data_len, data_len2, tmp_len;
- data_len = sd->data_len;
- data_len2 = 0;
- cmd_len = scsicmdsizes[sd->cmd[0] >> 5];
- if (sd->hdhfd && sd->hdhfd->ansi_version < 2 && cmd_len > 10)
- goto nocmd;
- sd->cmd_len = cmd_len;
- switch (sd->cmd[0])
- {
- case 0x04: // FORMAT UNIT
- if (sd->device_type == UAEDEV_CD)
- goto nocmd;
- // FmtData set?
- if (sd->cmd[1] & 0x10) {
- int cl = (sd->cmd[1] & 8) != 0;
- int dlf = sd->cmd[1] & 7;
- data_len2 = 4;
- } else {
- sd->direction = 0;
- sd->data_len = 0;
- return true;
- }
- break;
- case 0x06: // FORMAT TRACK
- case 0x07: // FORMAT BAD TRACK
- if (sd->device_type == UAEDEV_CD)
- goto nocmd;
- sd->direction = 0;
- sd->data_len = 0;
- return true;
- case 0x0c: // INITIALIZE DRIVE CHARACTERICS (SASI)
- if (sd->hfd && sd->hfd->ci.unit_feature_level < HD_LEVEL_SASI)
- goto nocmd;
- data_len = 8;
- break;
- case 0x08: // READ(6)
- data_len2 = (sd->cmd[4] == 0 ? 256 : sd->cmd[4]) * sd->blocksize;
- scsi_grow_buffer(sd, data_len2);
- break;
- case 0x11: // ASSIGN ALTERNATE TRACK (SASI)
- if (sd->hfd && sd->hfd->ci.unit_feature_level < HD_LEVEL_SASI)
- goto nocmd;
- data_len = 4;
- break;
- case 0x28: // READ(10)
- data_len2 = ((sd->cmd[7] << 8) | (sd->cmd[8] << 0)) * (uae_s64)sd->blocksize;
- scsi_grow_buffer(sd, data_len2);
- break;
- case 0xa8: // READ(12)
- data_len2 = ((sd->cmd[6] << 24) | (sd->cmd[7] << 16) | (sd->cmd[8] << 8) | (sd->cmd[9] << 0)) * (uae_s64)sd->blocksize;
- scsi_grow_buffer(sd, data_len2);
- break;
- case 0x0f: // WRITE SECTOR BUFFER
- data_len = sd->blocksize;
- scsi_grow_buffer(sd, data_len);
- break;
- case 0x0a: // WRITE(6)
- if (sd->device_type == UAEDEV_CD)
- goto nocmd;
- data_len = (sd->cmd[4] == 0 ? 256 : sd->cmd[4]) * sd->blocksize;
- scsi_grow_buffer(sd, data_len);
- break;
- case 0x2a: // WRITE(10)
- if (sd->device_type == UAEDEV_CD)
- goto nocmd;
- data_len = ((sd->cmd[7] << 8) | (sd->cmd[8] << 0)) * (uae_s64)sd->blocksize;
- scsi_grow_buffer(sd, data_len);
- break;
- case 0xaa: // WRITE(12)
- if (sd->device_type == UAEDEV_CD)
- goto nocmd;
- data_len = ((sd->cmd[6] << 24) | (sd->cmd[7] << 16) | (sd->cmd[8] << 8) | (sd->cmd[9] << 0)) * (uae_s64)sd->blocksize;
- scsi_grow_buffer(sd, data_len);
- break;
- case 0xbe: // READ CD
- case 0xb9: // READ CD MSF
- case 0xd8: // READ CD-DA
- case 0xd9: // READ CD-DA MSF
- if (sd->device_type != UAEDEV_CD)
- goto nocmd;
- tmp_len = (sd->cmd[6] << 16) | (sd->cmd[7] << 8) | sd->cmd[8];
- // max block transfer size, it is usually smaller.
- tmp_len *= 2352 + 96;
- scsi_grow_buffer(sd, tmp_len);
- break;
- case 0x2f: // VERIFY
- if (sd->cmd[1] & 2) {
- sd->data_len = ((sd->cmd[7] << 8) | (sd->cmd[8] << 0)) * (uae_s64)sd->blocksize;
- scsi_grow_buffer(sd, sd->data_len);
- sd->direction = 1;
- } else {
- sd->data_len = 0;
- sd->direction = 0;
- }
- return true;
- }
- if (data_len < 0) {
- if (cmd_len == 6) {
- sd->data_len = sd->cmd[4];
- } else {
- sd->data_len = (sd->cmd[7] << 8) | sd->cmd[8];
- }
- } else {
- sd->data_len = data_len;
- }
- sd->direction = scsi_data_dir(sd);
- if (sd->direction > 0 && sd->data_len == 0) {
- sd->direction = 0;
- }
- return true;
- nocmd:
- sd->status = SCSI_STATUS_CHECK_CONDITION;
- sd->direction = 0;
- scsi_illegal_command(sd);
- return false;
- }
- void scsi_illegal_lun(struct scsi_data *sd)
- {
- uae_u8 *s = sd->sense;
- memset (s, 0, sizeof (sd->sense));
- sd->status = SCSI_STATUS_CHECK_CONDITION;
- s[0] = 0x70;
- s[2] = SCSI_SK_ILLEGAL_REQ;
- s[12] = SCSI_INVALID_LUN;
- sd->sense_len = 0x12;
- }
- void scsi_clear_sense(struct scsi_data *sd)
- {
- memset (sd->sense, 0, sizeof (sd->sense));
- memset (sd->reply, 0, sizeof (sd->reply));
- sd->sense[0] = 0x70;
- }
- static void showsense(struct scsi_data *sd)
- {
- if (log_scsiemu) {
- for (int i = 0; i < sd->sense_len; i++) {
- if (i > 0)
- write_log (_T("."));
- write_log (_T("%02X"), sd->buffer[i]);
- }
- write_log (_T("\n"));
- }
- }
- static void copysense(struct scsi_data *sd)
- {
- bool sasi = sd->hfd && (sd->hfd->ci.unit_feature_level >= HD_LEVEL_SASI && sd->hfd->ci.unit_feature_level <= HD_LEVEL_SASI_ENHANCED);
- int len = sd->cmd[4];
- if (len == 0 || sasi)
- len = 4;
- memset(sd->buffer, 0, len);
- int tlen = sd->sense_len > len ? len : sd->sense_len;
- memcpy(sd->buffer, sd->sense, tlen);
- if (!sasi && sd->sense_len == 0) {
- // at least 0x12 bytes if SCSI and no sense
- tlen = len > 0x12 ? 0x12 : len;
- sd->buffer[0] = 0x70;
- sd->sense_len = tlen;
- }
- if (log_scsiemu)
- write_log(_T("REQUEST SENSE %d (%d -> %d)\n"), sd->cmd[4], sd->sense_len, tlen);
- showsense (sd);
- sd->data_len = tlen;
- scsi_clear_sense(sd);
- }
- static void copyreply(struct scsi_data *sd)
- {
- if (sd->status == 0 && sd->reply_len > 0) {
- memset(sd->buffer, 0, 256);
- memcpy(sd->buffer, sd->reply, sd->reply_len);
- sd->data_len = sd->reply_len;
- }
- }
- static void scsi_set_unit_attention(struct scsi_data *sd, uae_u8 v1, uae_u8 v2)
- {
- sd->unit_attention = (v1 << 8) | v2;
- }
- static void scsi_emulate_reset_device(struct scsi_data *sd)
- {
- if (!sd)
- return;
- if (sd->device_type == UAEDEV_HDF && sd->nativescsiunit < 0) {
- scsi_clear_sense(sd);
- // SCSI bus reset occurred
- scsi_set_unit_attention(sd, 0x29, 0x02);
- }
- }
- static bool handle_ca(struct scsi_data *sd)
- {
- bool cc = sd->sense_len > 2 && sd->sense[2] >= 2;
- bool ua = sd->unit_attention != 0;
- uae_u8 cmd = sd->cmd[0];
- // INQUIRY
- if (cmd == 0x12) {
- if (ua && cc && sd->sense[2] == 6) {
- // INQUIRY clears UA only if previous
- // command was aborted due to UA
- sd->unit_attention = 0;
- }
- memset(sd->reply, 0, sizeof(sd->reply));
- return true;
- }
- // REQUEST SENSE
- if (cmd == 0x03) {
- if (ua) {
- uae_u8 *s = sd->sense;
- scsi_clear_sense(sd);
- s[0] = 0x70;
- s[2] = 6; /* UNIT ATTENTION */
- s[12] = (sd->unit_attention >> 8) & 0xff;
- s[13] = (sd->unit_attention >> 0) & 0xff;
- sd->sense_len = 0x12;
- }
- sd->unit_attention = 0;
- return true;
- }
- scsi_clear_sense(sd);
- if (ua) {
- uae_u8 *s = sd->sense;
- s[0] = 0x70;
- s[2] = 6; /* UNIT ATTENTION */
- s[12] = (sd->unit_attention >> 8) & 0xff;
- s[13] = (sd->unit_attention >> 0) & 0xff;
- sd->sense_len = 0x12;
- sd->unit_attention = 0;
- sd->status = 2;
- return false;
- }
- return true;
- }
- bool scsi_cmd_is_safe(uae_u8 cmd)
- {
- for (int i = 0; safescsi[i] >= 0; i++) {
- if (safescsi[i] == cmd) {
- return true;
- }
- }
- return false;
- }
- void scsi_emulate_cmd(struct scsi_data *sd)
- {
- sd->status = 0;
- if ((sd->message[0] & 0xc0) == 0x80 && (sd->message[0] & 0x1f)) {
- uae_u8 lun = sd->message[0] & 0x1f;
- if (lun > 7)
- lun = 7;
- sd->cmd[1] &= ~(7 << 5);
- sd->cmd[1] |= lun << 5;
- }
- #if SCSI_EMU_DEBUG
- write_log (_T("CMD=%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x (%d,%d)\n"),
- sd->cmd[0], sd->cmd[1], sd->cmd[2], sd->cmd[3], sd->cmd[4], sd->cmd[5], sd->cmd[6], sd->cmd[7], sd->cmd[8], sd->cmd[9],
- sd->device_type, sd->nativescsiunit);
- #endif
- if (sd->device_type == UAEDEV_CD && sd->cd_emu_unit >= 0) {
- uae_u32 ua = 0;
- ua = scsi_cd_emulate(sd->cd_emu_unit, NULL, 0, 0, 0, 0, 0, 0, 0, sd->atapi);
- if (ua)
- sd->unit_attention = ua;
- if (handle_ca(sd)) {
- if (sd->cmd[0] == 0x03) { /* REQUEST SENSE */
- scsi_cd_emulate(sd->cd_emu_unit, sd->cmd, 0, 0, 0, 0, 0, 0, 0, sd->atapi); /* ack request sense */
- copysense(sd);
- } else {
- sd->status = scsi_cd_emulate(sd->cd_emu_unit, sd->cmd, sd->cmd_len, sd->buffer, &sd->data_len, sd->reply, &sd->reply_len, sd->sense, &sd->sense_len, sd->atapi);
- copyreply(sd);
- }
- }
- gui_flicker_led(LED_CD, sd->uae_unitnum, 1);
- } else if (sd->device_type == UAEDEV_HDF && sd->nativescsiunit < 0) {
- uae_u32 ua = 0;
- ua = scsi_hd_emulate(sd->hfd, sd->hdhfd, NULL, 0, 0, 0, 0, 0, 0, 0);
- if (ua)
- sd->unit_attention = ua;
- if (handle_ca(sd)) {
- if (sd->cmd[0] == 0x03) { /* REQUEST SENSE */
- scsi_hd_emulate(sd->hfd, sd->hdhfd, sd->cmd, 0, 0, 0, 0, 0, sd->sense, &sd->sense_len);
- copysense(sd);
- } else {
- sd->status = scsi_hd_emulate(sd->hfd, sd->hdhfd,
- sd->cmd, sd->cmd_len, sd->buffer, &sd->data_len, sd->reply, &sd->reply_len, sd->sense, &sd->sense_len);
- copyreply(sd);
- }
- }
- } else if (sd->device_type == UAEDEV_TAPE && sd->nativescsiunit < 0) {
- uae_u32 ua = 0;
- ua = scsi_tape_emulate(sd->tape, NULL, 0, 0, 0, 0, 0, 0, 0);
- if (ua)
- sd->unit_attention = ua;
- if (handle_ca(sd)) {
- if (sd->cmd[0] == 0x03) { /* REQUEST SENSE */
- scsi_tape_emulate(sd->tape, sd->cmd, 0, 0, 0, sd->reply, &sd->reply_len, sd->sense, &sd->sense_len); /* get request sense extra bits */
- copysense(sd);
- } else {
- sd->status = scsi_tape_emulate(sd->tape,
- sd->cmd, sd->cmd_len, sd->buffer, &sd->data_len, sd->reply, &sd->reply_len, sd->sense, &sd->sense_len);
- copyreply(sd);
- }
- }
- } else if (sd->device_type == UAEDEV_DIR) {
- uae_u32 ua = 0;
- ua = scsi_hd_emulate(sd->hfd, sd->hdhfd, NULL, 0, 0, 0, 0, 0, 0, 0);
- if (ua)
- sd->unit_attention = ua;
- if (handle_ca(sd)) {
- if (scsi_cmd_is_safe(sd->cmd[0])) {
- if (sd->cmd[0] == 0x03) { /* REQUEST SENSE */
- scsi_hd_emulate(sd->hfd, sd->hdhfd, sd->cmd, 0, 0, 0, 0, 0, sd->sense, &sd->sense_len);
- copysense(sd);
- } else {
- sd->status = scsi_hd_emulate(sd->hfd, sd->hdhfd,
- sd->cmd, sd->cmd_len, sd->buffer, &sd->data_len, sd->reply, &sd->reply_len, sd->sense, &sd->sense_len);
- copyreply(sd);
- }
- } else {
- sd->sense[0] = 0x70;
- sd->sense[2] = 5; /* Illegal Request */
- sd->sense[12] = 0x20; /* Invalid/unsupported command code */
- sd->sense_len = 18;
- sd->status = 2;
- copyreply(sd);
- }
- }
- } else if (sd->nativescsiunit >= 0) {
- struct amigascsi as;
- memset(sd->sense, 0, 256);
- memset(&as, 0, sizeof as);
- memcpy (&as.cmd, sd->cmd, sd->cmd_len);
- as.flags = 2 | 1;
- if (sd->direction > 0)
- as.flags &= ~1;
- as.sense_len = 32;
- as.cmd_len = sd->cmd_len;
- as.data = sd->buffer;
- as.len = sd->direction < 0 ? DEVICE_SCSI_BUFSIZE : sd->data_len;
- sys_command_scsi_direct_native(sd->nativescsiunit, -1, &as);
- sd->status = as.status;
- sd->data_len = as.len;
- if (sd->status) {
- sd->direction = 0;
- sd->data_len = 0;
- memcpy(sd->sense, as.sensedata, as.sense_len);
- }
- }
- sd->offset = 0;
- }
- static void allocscsibuf(struct scsi_data *sd)
- {
- sd->buffer_size = SCSI_DEFAULT_DATA_BUFFER_SIZE;
- sd->buffer = xcalloc(uae_u8, sd->buffer_size);
- }
- struct scsi_data *scsi_alloc_generic(struct hardfiledata *hfd, int type, int uae_unitnum)
- {
- struct scsi_data *sd = xcalloc(struct scsi_data, 1);
- sd->hfd = hfd;
- sd->id = -1;
- sd->nativescsiunit = -1;
- sd->cd_emu_unit = -1;
- sd->blocksize = hfd->ci.blocksize;
- sd->device_type = type;
- sd->uae_unitnum = uae_unitnum;
- allocscsibuf(sd);
- return sd;
- }
- struct scsi_data *scsi_alloc_hd(int id, struct hd_hardfiledata *hfd, int uae_unitnum)
- {
- struct scsi_data *sd = xcalloc (struct scsi_data, 1);
- sd->hdhfd = hfd;
- sd->hfd = &hfd->hfd;
- sd->id = id;
- sd->nativescsiunit = -1;
- sd->cd_emu_unit = -1;
- sd->blocksize = hfd->hfd.virtual_rdb ? 512 : hfd->hfd.ci.blocksize;
- sd->device_type = UAEDEV_HDF;
- sd->uae_unitnum = uae_unitnum;
- allocscsibuf(sd);
- return sd;
- }
- struct scsi_data *scsi_alloc_cd(int id, int unitnum, bool atapi, int uae_unitnum)
- {
- struct scsi_data *sd;
- if (!sys_command_open (unitnum)) {
- write_log (_T("SCSI: CD EMU scsi unit %d failed to open\n"), unitnum);
- return NULL;
- }
- sd = xcalloc (struct scsi_data, 1);
- sd->id = id;
- sd->cd_emu_unit = unitnum;
- sd->nativescsiunit = -1;
- sd->atapi = atapi;
- sd->blocksize = 2048;
- sd->device_type = UAEDEV_CD;
- sd->uae_unitnum = uae_unitnum;
- allocscsibuf(sd);
- return sd;
- }
- struct scsi_data *scsi_alloc_tape(int id, const TCHAR *tape_directory, bool readonly, int uae_unitnum)
- {
- struct scsi_data_tape *tape;
- tape = tape_alloc (id, tape_directory, readonly);
- if (!tape)
- return NULL;
- struct scsi_data *sd = xcalloc (struct scsi_data, 1);
- sd->id = id;
- sd->nativescsiunit = -1;
- sd->cd_emu_unit = -1;
- sd->blocksize = tape->blocksize;
- sd->tape = tape;
- sd->device_type = UAEDEV_TAPE;
- sd->uae_unitnum = uae_unitnum;
- allocscsibuf(sd);
- return sd;
- }
- struct scsi_data *scsi_alloc_native(int id, int nativeunit)
- {
- struct scsi_data *sd;
- if (!sys_command_open (nativeunit)) {
- write_log (_T("SCSI: native scsi unit %d failed to open\n"), nativeunit);
- return NULL;
- }
- sd = xcalloc (struct scsi_data, 1);
- sd->id = id;
- sd->nativescsiunit = nativeunit;
- sd->cd_emu_unit = -1;
- sd->blocksize = 2048;
- sd->device_type = 0;
- allocscsibuf(sd);
- return sd;
- }
- void scsi_reset(void)
- {
- //device_func_init (DEVICE_TYPE_SCSI);
- }
- void scsi_free(struct scsi_data *sd)
- {
- if (!sd)
- return;
- if (sd->nativescsiunit >= 0) {
- sys_command_close (sd->nativescsiunit);
- sd->nativescsiunit = -1;
- }
- if (sd->cd_emu_unit >= 0) {
- sys_command_close (sd->cd_emu_unit);
- sd->cd_emu_unit = -1;
- }
- tape_free (sd->tape);
- xfree(sd->buffer);
- xfree(sd);
- }
- void scsi_start_transfer(struct scsi_data *sd)
- {
- sd->offset = 0;
- }
- int scsi_send_data(struct scsi_data *sd, uae_u8 b)
- {
- if (sd->offset < 0) {
- write_log(_T("SCSI data offset is negative!\n"));
- return 0;
- }
- if (sd->direction == 1) {
- if (sd->offset >= sd->buffer_size) {
- write_log (_T("SCSI data buffer overflow!\n"));
- return 0;
- }
- sd->buffer[sd->offset++] = b;
- } else if (sd->direction == 2) {
- if (sd->offset >= 16) {
- write_log (_T("SCSI command buffer overflow!\n"));
- return 0;
- }
- sd->cmd[sd->offset++] = b;
- if (sd->offset == sd->cmd_len)
- return 1;
- } else {
- write_log (_T("scsi_send_data() without direction! (%02X)\n"), sd->cmd[0]);
- return 0;
- }
- if (sd->offset == sd->data_len)
- return 1;
- return 0;
- }
- int scsi_receive_data(struct scsi_data *sd, uae_u8 *b, bool next)
- {
- if (!sd->data_len)
- return -1;
- *b = sd->buffer[sd->offset];
- if (next) {
- sd->offset++;
- if (sd->offset == sd->data_len)
- return 1; // requested length got
- }
- return 0;
- }
- void free_scsi (struct scsi_data *sd)
- {
- if (!sd)
- return;
- hdf_hd_close(sd->hdhfd);
- scsi_free (sd);
- }
- int add_scsi_hd (struct scsi_data **sd, int ch, struct hd_hardfiledata *hfd, struct uaedev_config_info *ci)
- {
- free_scsi (*sd);
- *sd = NULL;
- if (!hfd) {
- hfd = xcalloc (struct hd_hardfiledata, 1);
- memcpy (&hfd->hfd.ci, ci, sizeof (struct uaedev_config_info));
- }
- if (!hdf_hd_open (hfd))
- return 0;
- hfd->ansi_version = ci->unit_feature_level + 1;
- *sd = scsi_alloc_hd (ch, hfd, ci->uae_unitnum);
- return *sd ? 1 : 0;
- }
- int add_scsi_cd (struct scsi_data **sd, int ch, int unitnum)
- {
- device_func_init (0);
- free_scsi (*sd);
- *sd = scsi_alloc_cd (ch, unitnum, false, unitnum);
- return *sd ? 1 : 0;
- }
- int add_scsi_tape (struct scsi_data **sd, int ch, const TCHAR *tape_directory, bool readonly)
- {
- free_scsi (*sd);
- *sd = scsi_alloc_tape (ch, tape_directory, readonly, ch);
- return *sd ? 1 : 0;
- }
- int add_scsi_device(struct scsi_data **sd, int ch, struct uaedev_config_info *ci, struct romconfig *rc)
- {
- if (ci->type == UAEDEV_CD)
- return add_scsi_cd(sd, ch, ci->device_emu_unit);
- else if (ci->type == UAEDEV_TAPE)
- return add_scsi_tape(sd, ch, ci->rootdir, ci->readonly);
- else if (ci->type == UAEDEV_HDF)
- return add_scsi_hd(sd, ch, NULL, ci);
- return 0;
- }
- void scsi_freenative(struct scsi_data **sd, int max)
- {
- for (int i = 0; i < max; i++) {
- free_scsi (sd[i]);
- sd[i] = NULL;
- }
- }
- void scsi_addnative(struct scsi_data **sd)
- {
- int i, j;
- int devices[MAX_TOTAL_SCSI_DEVICES];
- int types[MAX_TOTAL_SCSI_DEVICES];
- struct device_info dis[MAX_TOTAL_SCSI_DEVICES];
- scsi_freenative (sd, MAX_TOTAL_SCSI_DEVICES);
- i = 0;
- while (i < MAX_TOTAL_SCSI_DEVICES) {
- types[i] = -1;
- devices[i] = -1;
- if (sys_command_open (i)) {
- if (sys_command_info (i, &dis[i], 0)) {
- devices[i] = i;
- types[i] = 100 - i;
- if (dis[i].type == INQ_ROMD)
- types[i] = 1000 - i;
- }
- sys_command_close (i);
- }
- i++;
- }
- i = 0;
- while (devices[i] >= 0) {
- j = i + 1;
- while (devices[j] >= 0) {
- if (types[i] > types[j]) {
- int tmp = types[i];
- types[i] = types[j];
- types[j] = tmp;
- }
- j++;
- }
- i++;
- }
- i = 0; j = 0;
- while (devices[i] >= 0 && j < 7) {
- if (sd[j] == NULL) {
- sd[j] = scsi_alloc_native(j, devices[i]);
- write_log (_T("SCSI: %d:'%s'\n"), j, dis[i].label);
- i++;
- }
- j++;
- }
- }
- // raw scsi
- #define SCSI_IO_BUSY 0x80
- #define SCSI_IO_ATN 0x40
- #define SCSI_IO_SEL 0x20
- #define SCSI_IO_REQ 0x10
- #define SCSI_IO_DIRECTION 0x01
- #define SCSI_IO_COMMAND 0x02
- #define SCSI_IO_MESSAGE 0x04
- #define SCSI_SIGNAL_PHASE_FREE -1
- #define SCSI_SIGNAL_PHASE_ARBIT -2
- #define SCSI_SIGNAL_PHASE_SELECT_1 -3
- #define SCSI_SIGNAL_PHASE_SELECT_2 -4
- #define SCSI_SIGNAL_PHASE_DATA_OUT 0
- #define SCSI_SIGNAL_PHASE_DATA_IN 1
- #define SCSI_SIGNAL_PHASE_COMMAND 2
- #define SCSI_SIGNAL_PHASE_STATUS 3
- #define SCSI_SIGNAL_PHASE_MESSAGE_OUT 6
- #define SCSI_SIGNAL_PHASE_MESSAGE_IN 7
- struct raw_scsi
- {
- int io;
- int bus_phase;
- bool atn;
- bool ack;
- bool wait_ack;
- uae_u8 data_write;
- uae_u8 status;
- bool databusoutput;
- int initiator_id, target_id;
- struct scsi_data *device[MAX_TOTAL_SCSI_DEVICES];
- struct scsi_data *target;
- int msglun;
- };
- struct soft_scsi
- {
- uae_u8 regs[32];
- uae_u16 regs_400[2];
- uae_u8 scratch_400[64];
- int c400_count;
- bool c400;
- bool dp8490v;
- uae_u8 aic_reg;
- struct raw_scsi rscsi;
- bool irq;
- bool intena;
- bool level6;
- bool enabled;
- bool delayed_irq;
- bool configured;
- uae_u8 acmemory[128];
- uaecptr baseaddress;
- uaecptr baseaddress2;
- uae_u8 *rom;
- int rom_size;
- int board_mask;
- int board_mask2;
- int board_size;
- addrbank *bank;
- int type;
- int subtype;
- int dma_direction;
- bool dma_active;
- bool dma_started;
- bool dma_controller;
- bool dma_drq;
- bool dma_autodack;
- uae_u32 dma_mask;
- struct romconfig *rc;
- struct soft_scsi **self_ptr;
- int dmac_direction;
- uaecptr dmac_address;
- int dmac_length;
- int dmac_active;
- int chip_state;
- // add500
- uae_u16 databuffer[2];
- bool databuffer_empty;
- // kronos/xebec
- uae_u8 *databufferptr;
- int databuffer_size;
- int db_read_index;
- int db_write_index;
- void *eeprom;
- // sasi
- bool active_select;
- bool wait_select;
- // 12 Gauge needs this (Driver has buggy BSY test)
- bool busy_delayed_hack;
- int busy_delayed_hack_cnt;
- };
- #define MAX_SOFT_SCSI_UNITS 10
- static struct soft_scsi *soft_scsi_devices[MAX_SOFT_SCSI_UNITS];
- static struct soft_scsi *soft_scsi_units[NCR_LAST * MAX_DUPLICATE_EXPANSION_BOARDS];
- bool parallel_port_scsi;
- static struct soft_scsi *parallel_port_scsi_data;
- static struct soft_scsi *x86_hd_data;
- static void soft_scsi_free_unit(struct soft_scsi *s)
- {
- if (!s)
- return;
- struct raw_scsi *rs = &s->rscsi;
- for (int j = 0; j < 8; j++) {
- free_scsi (rs->device[j]);
- rs->device[j] = NULL;
- }
- eeprom93xx_free(s->eeprom);
- xfree(s->databufferptr);
- xfree(s->rom);
- if (s->self_ptr)
- *s->self_ptr = NULL;
- xfree(s);
- }
- static void freescsi(struct soft_scsi **ncr)
- {
- if (!ncr)
- return;
- for (int i = 0; i < MAX_SOFT_SCSI_UNITS; i++) {
- if (soft_scsi_devices[i] == *ncr) {
- soft_scsi_devices[i] = NULL;
- }
- }
- if (*ncr) {
- soft_scsi_free_unit(*ncr);
- }
- *ncr = NULL;
- }
- static struct soft_scsi *allocscsi(struct soft_scsi **ncr, struct romconfig *rc, int ch)
- {
- struct soft_scsi *scsi;
- if (ch < 0) {
- freescsi(ncr);
- *ncr = NULL;
- }
- if ((*ncr) == NULL) {
- scsi = xcalloc(struct soft_scsi, 1);
- for (int i = 0; i < MAX_SOFT_SCSI_UNITS; i++) {
- if (soft_scsi_devices[i] == NULL) {
- soft_scsi_devices[i] = scsi;
- rc->unitdata = scsi;
- scsi->rc = rc;
- scsi->self_ptr = ncr;
- if (ncr)
- *ncr = scsi;
- return scsi;
- }
- }
- }
- return *ncr;
- }
- static struct soft_scsi *getscsiboard(uaecptr addr)
- {
- for (int i = 0; soft_scsi_devices[i]; i++) {
- struct soft_scsi *s = soft_scsi_devices[i];
- if (s->baseaddress2 && (addr & ~s->board_mask2) == s->baseaddress2)
- return s;
- if (!s->baseaddress && !s->configured)
- return s;
- if ((addr & ~s->board_mask) == s->baseaddress)
- return s;
- if (s->baseaddress == AUTOCONFIG_Z2 && addr < 65536)
- return s;
- }
- return NULL;
- }
- static void raw_scsi_reset(struct raw_scsi *rs)
- {
- rs->target = NULL;
- rs->io = 0;
- rs->bus_phase = SCSI_SIGNAL_PHASE_FREE;
- }
- extern addrbank soft_bank_generic;
- static void ew(struct soft_scsi *scsi, int addr, uae_u32 value)
- {
- addr &= 0xffff;
- if (addr == 00 || addr == 02 || addr == 0x40 || addr == 0x42) {
- scsi->acmemory[addr] = (value & 0xf0);
- scsi->acmemory[addr + 2] = (value & 0x0f) << 4;
- } else {
- scsi->acmemory[addr] = ~(value & 0xf0);
- scsi->acmemory[addr + 2] = ~((value & 0x0f) << 4);
- }
- }
- static struct soft_scsi *generic_soft_scsi_add(int ch, struct uaedev_config_info *ci, struct romconfig *rc, int type, int boardsize, int romsize, int romtype)
- {
- struct soft_scsi *ss = allocscsi(&soft_scsi_units[type * MAX_DUPLICATE_EXPANSION_BOARDS + ci->controller_type_unit], rc, ch);
- ss->type = type;
- ss->configured = 0;
- ss->bank = &soft_bank_generic;
- ss->subtype = rc->subtype;
- ss->intena = false;
- ss->dma_mask = 0xffffffff;
- if (boardsize > 0) {
- ss->board_size = boardsize;
- ss->board_mask = ss->board_size - 1;
- }
- if (!ss->board_mask && !ss->board_size) {
- ss->board_size = 0x10000;
- ss->board_mask = 0xffff;
- }
- ss->board_mask2 = ss->board_mask;
- if (romsize >= 0) {
- ss->rom_size = romsize;
- xfree(ss->rom);
- ss->rom = NULL;
- if (romsize > 0) {
- ss->rom = xcalloc(uae_u8, ss->rom_size);
- memset(ss->rom, 0xff, ss->rom_size);
- }
- }
- memset(ss->acmemory, 0xff, sizeof ss->acmemory);
- const struct expansionromtype *ert = get_device_expansion_rom(romtype);
- if (ert) {
- const uae_u8 *ac = NULL;
- if (ert->subtypes)
- ac = ert->subtypes[rc->subtype].autoconfig;
- else
- ac = ert->autoconfig;
- if (ac[0]) {
- for (int i = 0; i < 16; i++) {
- uae_u8 b = ac[i];
- ew(ss, i * 4, b);
- }
- }
- }
- raw_scsi_reset(&ss->rscsi);
- if (ch < 0)
- return ss;
- add_scsi_device(&ss->rscsi.device[ch], ch, ci, rc);
- return ss;
- }
- static void raw_scsi_busfree(struct raw_scsi *rs)
- {
- rs->target = NULL;
- rs->io = 0;
- rs->bus_phase = SCSI_SIGNAL_PHASE_FREE;
- }
- static void bus_free(struct raw_scsi *rs)
- {
- rs->bus_phase = SCSI_SIGNAL_PHASE_FREE;
- rs->io = 0;
- }
- static int getbit(uae_u8 v)
- {
- for (int i = 7; i >= 0; i--) {
- if ((1 << i) & v)
- return i;
- }
- return -1;
- }
- static int countbits(uae_u8 v)
- {
- int cnt = 0;
- for (int i = 7; i >= 0; i--) {
- if ((1 << i) & v)
- cnt++;
- }
- return cnt;
- }
- static void raw_scsi_reset_bus(struct soft_scsi *scsi)
- {
- struct raw_scsi *r = &scsi->rscsi;
- #if RAW_SCSI_DEBUG
- write_log(_T("SCSI BUS reset\n"));
- #endif
- raw_scsi_reset(r);
- for (int i = 0; i < 8; i++) {
- scsi_emulate_reset_device(r->device[i]);
- }
- }
- static void raw_scsi_set_databus(struct raw_scsi *rs, bool databusoutput)
- {
- rs->databusoutput = databusoutput;
- }
- static void raw_scsi_set_signal_phase(struct raw_scsi *rs, bool busy, bool select, bool atn)
- {
- switch (rs->bus_phase)
- {
- case SCSI_SIGNAL_PHASE_FREE:
- if (busy && !select && !rs->databusoutput) {
- if (countbits(rs->data_write) != 1) {
- #if RAW_SCSI_DEBUG
- write_log(_T("raw_scsi: invalid arbitration scsi id mask! (%02x) %08x\n"), rs->data_write, M68K_GETPC);
- #endif
- return;
- }
- rs->bus_phase = SCSI_SIGNAL_PHASE_ARBIT;
- rs->initiator_id = getbit(rs->data_write);
- #if RAW_SCSI_DEBUG
- write_log(_T("raw_scsi: arbitration initiator id %d (%02x) %08x\n"), rs->initiator_id, rs->data_write, M68K_GETPC);
- #endif
- } else if (!busy && select) {
- if (countbits(rs->data_write) > 2 || rs->data_write == 0) {
- #if RAW_SCSI_DEBUG
- write_log(_T("raw_scsi: invalid scsi id selected mask (%02x) %08x\n"), rs->data_write, M68K_GETPC);
- #endif
- return;
- }
- rs->initiator_id = -1;
- rs->bus_phase = SCSI_SIGNAL_PHASE_SELECT_1;
- #if RAW_SCSI_DEBUG
- write_log(_T("raw_scsi: selected scsi id mask (%02x) %08x\n"), rs->data_write, M68K_GETPC);
- #endif
- raw_scsi_set_signal_phase(rs, busy, select, atn);
- }
- break;
- case SCSI_SIGNAL_PHASE_ARBIT:
- rs->target_id = -1;
- rs->target = NULL;
- if (busy && select) {
- rs->bus_phase = SCSI_SIGNAL_PHASE_SELECT_1;
- }
- break;
- case SCSI_SIGNAL_PHASE_SELECT_1:
- rs->atn = atn;
- rs->msglun = -1;
- rs->target_id = -1;
- if (!busy) {
- for (int i = 0; i < 8; i++) {
- if (i == rs->initiator_id)
- continue;
- if ((rs->data_write & (1 << i)) && rs->device[i]) {
- rs->target_id = i;
- rs->target = rs->device[rs->target_id];
- #if RAW_SCSI_DEBUG
- write_log(_T("raw_scsi: selected id %d %08x\n"), rs->target_id, M68K_GETPC);
- #endif
- rs->io |= SCSI_IO_BUSY;
- }
- }
- #if RAW_SCSI_DEBUG
- if (rs->target_id < 0) {
- for (int i = 0; i < 8; i++) {
- if (i == rs->initiator_id)
- continue;
- if ((rs->data_write & (1 << i)) && !rs->device[i]) {
- write_log(_T("raw_scsi: selected non-existing id %d %08x\n"), i, M68K_GETPC);
- }
- }
- }
- #endif
- if (rs->target_id >= 0) {
- rs->bus_phase = SCSI_SIGNAL_PHASE_SELECT_2;
- } else {
- if (!select) {
- rs->bus_phase = SCSI_SIGNAL_PHASE_FREE;
- }
- }
- }
- break;
- case SCSI_SIGNAL_PHASE_SELECT_2:
- if (!select) {
- scsi_start_transfer(rs->target);
- rs->bus_phase = rs->atn ? SCSI_SIGNAL_PHASE_MESSAGE_OUT : SCSI_SIGNAL_PHASE_COMMAND;
- rs->io = SCSI_IO_BUSY | SCSI_IO_REQ;
- }
- break;
- }
- }
- static uae_u8 raw_scsi_get_signal_phase(struct raw_scsi *rs)
- {
- uae_u8 v = rs->io;
- if (rs->bus_phase >= 0)
- v |= rs->bus_phase;
- if (rs->ack)
- v &= ~SCSI_IO_REQ;
- return v;
- }
- static uae_u8 raw_scsi_get_data_2(struct raw_scsi *rs, bool next, bool nodebug)
- {
- struct scsi_data *sd = rs->target;
- uae_u8 v = 0;
- switch (rs->bus_phase)
- {
- case SCSI_SIGNAL_PHASE_FREE:
- v = 0;
- break;
- case SCSI_SIGNAL_PHASE_ARBIT:
- #if RAW_SCSI_DEBUG
- write_log(_T("raw_scsi: arbitration %08x\n"), M68K_GETPC);
- #endif
- v = rs->data_write;
- break;
- case SCSI_SIGNAL_PHASE_DATA_IN:
- #if RAW_SCSI_DEBUG > 2
- scsi_receive_data(sd, &v, false);
- write_log(_T("raw_scsi: read data byte %02x (%d/%d) %08x\n"), v, sd->offset, sd->data_len, M68K_GETPC);
- #endif
- if (scsi_receive_data(sd, &v, next)) {
- #if RAW_SCSI_DEBUG
- write_log(_T("raw_scsi: data in finished, %d bytes: status phase\n"), sd->offset);
- #endif
- rs->bus_phase = SCSI_SIGNAL_PHASE_STATUS;
- }
- break;
- case SCSI_SIGNAL_PHASE_STATUS:
- #if RAW_SCSI_DEBUG
- if (!nodebug || next)
- write_log(_T("raw_scsi: status byte read %02x. Next=%d PC=%08x\n"), sd->status, next, M68K_GETPC);
- #endif
- v = sd->status;
- if (next) {
- sd->status = 0;
- rs->bus_phase = SCSI_SIGNAL_PHASE_MESSAGE_IN;
- }
- break;
- case SCSI_SIGNAL_PHASE_MESSAGE_IN:
- #if RAW_SCSI_DEBUG
- if (!nodebug || next)
- write_log(_T("raw_scsi: message byte read %02x. Next=%d PC=%08x\n"), sd->status, next, M68K_GETPC);
- #endif
- v = sd->status;
- rs->status = v;
- if (next) {
- bus_free(rs);
- }
- break;
- default:
- #if RAW_SCSI_DEBUG
- write_log(_T("raw_scsi_get_data but bus phase is %d %08x!\n"), rs->bus_phase, M68K_GETPC);
- #endif
- break;
- }
- return v;
- }
- static uae_u8 raw_scsi_get_data(struct raw_scsi *rs, bool next)
- {
- return raw_scsi_get_data_2(rs, next, true);
- }
- static int getmsglen(uae_u8 *msgp, int len)
- {
- uae_u8 msg = msgp[0];
- if (msg == 0 || (msg >= 0x02 && msg <= 0x1f) ||msg >= 0x80)
- return 1;
- if (msg >= 0x20 && msg <= 0x2f)
- return 2;
- // extended message, at least 3 bytes
- if (len < 2)
- return 3;
- return msgp[1];
- }
- static void raw_scsi_write_data(struct raw_scsi *rs, uae_u8 data)
- {
- struct scsi_data *sd = rs->target;
- int len;
- switch (rs->bus_phase)
- {
- case SCSI_SIGNAL_PHASE_SELECT_1:
- case SCSI_SIGNAL_PHASE_FREE:
- break;
- case SCSI_SIGNAL_PHASE_COMMAND:
- sd->cmd[sd->offset++] = data;
- len = scsicmdsizes[sd->cmd[0] >> 5];
- #if RAW_SCSI_DEBUG > 1
- write_log(_T("raw_scsi: got command byte %02x (%d/%d) %08x\n"), data, sd->offset, len, M68K_GETPC);
- #endif
- if (sd->offset >= len) {
- if (rs->msglun >= 0) {
- sd->cmd[1] &= ~(0x80 | 0x40 | 0x20);
- sd->cmd[1] |= rs->msglun << 5;
- }
- scsi_emulate_analyze(rs->target);
- if (sd->direction > 0) {
- #if RAW_SCSI_DEBUG
- write_log(_T("raw_scsi: data out %d bytes required\n"), sd->data_len);
- #endif
- scsi_start_transfer(sd);
- rs->bus_phase = SCSI_SIGNAL_PHASE_DATA_OUT;
- } else if (sd->direction <= 0) {
- scsi_emulate_cmd(sd);
- scsi_start_transfer(sd);
- #if RAW_SCSI_DEBUG
- if (sd->status) {
- write_log(_T("raw_scsi: status = %d len = %d\n"), sd->status, sd->data_len);
- }
- #endif
- if (!sd->status && sd->data_len > 0) {
- #if RAW_SCSI_DEBUG
- write_log(_T("raw_scsi: data in %d bytes waiting\n"), sd->data_len);
- #endif
- rs->bus_phase = SCSI_SIGNAL_PHASE_DATA_IN;
- } else {
- #if RAW_SCSI_DEBUG
- write_log(_T("raw_scsi: no data, status = %d\n"), sd->status);
- #endif
- rs->bus_phase = SCSI_SIGNAL_PHASE_STATUS;
- }
- }
- }
- break;
- case SCSI_SIGNAL_PHASE_DATA_OUT:
- #if RAW_SCSI_DEBUG > 2
- write_log(_T("raw_scsi: write data byte %02x (%d/%d) %08x\n"), data, sd->offset, sd->data_len, M68K_GETPC);
- #endif
- if (scsi_send_data(sd, data)) {
- #if RAW_SCSI_DEBUG
- write_log(_T("raw_scsi: data out finished, %d bytes\n"), sd->data_len);
- #endif
- scsi_emulate_cmd(sd);
- rs->bus_phase = SCSI_SIGNAL_PHASE_STATUS;
- }
- break;
- case SCSI_SIGNAL_PHASE_MESSAGE_OUT:
- sd->msgout[sd->offset++] = data;
- len = getmsglen(sd->msgout, sd->offset);
- #if RAW_SCSI_DEBUG
- write_log(_T("raw_scsi_put_data got message %02x (%d/%d) %08x\n"), data, sd->offset, len, M68K_GETPC);
- #endif
- if (sd->offset >= len) {
- #if RAW_SCSI_DEBUG
- write_log(_T("raw_scsi_put_data got message %02x (%d bytes)\n"), sd->msgout[0], len);
- #endif
- if ((sd->msgout[0] & (0x80 | 0x20)) == 0x80)
- rs->msglun = sd->msgout[0] & 7;
- scsi_start_transfer(sd);
- rs->bus_phase = SCSI_SIGNAL_PHASE_COMMAND;
- }
- break;
- default:
- #if RAW_SCSI_DEBUG
- write_log(_T("raw_scsi_put_data but bus phase is %d!\n"), rs->bus_phase);
- #endif
- break;
- }
- }
- static void raw_scsi_put_data(struct raw_scsi *rs, uae_u8 data, bool databusoutput)
- {
- rs->data_write = data;
- if (!databusoutput)
- return;
- raw_scsi_write_data(rs, data);
- }
- static void raw_scsi_set_ack(struct raw_scsi *rs, bool ack)
- {
- if (rs->ack != ack) {
- rs->ack = ack;
- if (!ack)
- return;
- if (rs->bus_phase < 0)
- return;
- if (!(rs->bus_phase & SCSI_IO_DIRECTION)) {
- if (rs->databusoutput) {
- raw_scsi_write_data(rs, rs->data_write);
- }
- } else {
- raw_scsi_get_data_2(rs, true, false);
- }
- }
- }
- // APOLLO SOFTSCSI
- void apollo_scsi_bput(uaecptr addr, uae_u8 v, uae_u32 config)
- {
- struct soft_scsi *as = getscsiboard(addr);
- if (!as)
- return;
- int bank = addr & (0x800 | 0x400);
- struct raw_scsi *rs = &as->rscsi;
- addr &= 0x3fff;
- if (bank == 0) {
- raw_scsi_put_data(rs, v, true);
- } else if (bank == 0xc00 && !(addr & 1)) {
- as->irq = (v & 64) != 0;
- raw_scsi_set_signal_phase(rs,
- (v & 128) != 0,
- (v & 32) != 0,
- false);
- } else if (bank == 0x400 && (addr & 1)) {
- raw_scsi_put_data(rs, v, true);
- raw_scsi_set_signal_phase(rs, true, false, false);
- }
- //write_log(_T("apollo scsi put %04x = %02x\n"), addr, v);
- }
- uae_u8 apollo_scsi_bget(uaecptr addr, uae_u32 config)
- {
- struct soft_scsi *as = getscsiboard(addr);
- if (!as)
- return 0;
- int bank = addr & (0x800 | 0x400);
- struct raw_scsi *rs = &as->rscsi;
- uae_u8 v = 0xff;
- addr &= 0x3fff;
- if (bank == 0) {
- v = raw_scsi_get_data(rs, true);
- } else if (bank == 0x800 && (addr & 1)) {
- uae_u8 t = raw_scsi_get_signal_phase(rs);
- v = 0;
- if (config & 1) // scsi module installed
- v |= 1;
- if (t & SCSI_IO_BUSY)
- v |= 128;
- if (t & SCSI_IO_SEL)
- v |= 32;
- if (t & SCSI_IO_REQ)
- v |= 2;
- if (t & SCSI_IO_DIRECTION)
- v |= 8;
- if (t & SCSI_IO_COMMAND)
- v |= 16;
- if (t & SCSI_IO_MESSAGE)
- v |= 4;
- v ^= (1 | 2 | 4 | 8 | 16 | 32 | 128);
- //v |= apolloscsi.irq ? 64 : 0;
- }
- //write_log(_T("apollo scsi get %04x = %02x\n"), addr, v);
- return v;
- }
- void apollo_add_ide_unit(int ch, struct uaedev_config_info *ci, struct romconfig *rc);
- void apollo_add_scsi_unit(int ch, struct uaedev_config_info *ci, struct romconfig *rc)
- {
- if (ch < 0) {
- generic_soft_scsi_add(-1, ci, rc, NONCR_APOLLO, -1, -1, ROMTYPE_APOLLO);
- // make sure IDE side is also initialized
- struct uaedev_config_info ci2 = { 0 };
- apollo_add_ide_unit(-1, &ci2, rc);
- } else {
- if (ci->controller_type < HD_CONTROLLER_TYPE_SCSI_FIRST) {
- apollo_add_ide_unit(ch, ci, rc);
- } else {
- generic_soft_scsi_add(ch, ci, rc, NONCR_APOLLO, -1, -1, ROMTYPE_APOLLO);
- }
- }
- }
- uae_u8 ncr5380_bget(struct soft_scsi *scsi, int reg);
- void ncr5380_bput(struct soft_scsi *scsi, int reg, uae_u8 v);
- static void supra_do_dma(struct soft_scsi *ncr)
- {
- int len = ncr->dmac_length;
- for (int i = 0; i < len; i++) {
- if (ncr->dmac_direction < 0) {
- dma_put_byte(ncr->dmac_address & ncr->dma_mask, ncr5380_bget(ncr, 0));
- } else if (ncr->dmac_direction > 0) {
- ncr5380_bput(ncr, 0, dma_get_byte(ncr->dmac_address & ncr->dma_mask));
- }
- ncr->dmac_length--;
- ncr->dmac_address++;
- }
- }
- uae_u8 aic_bget_dma(struct soft_scsi *scsi, bool *phaseerr);
- void aic_bput_dma(struct soft_scsi *scsi, uae_u8 v, bool *phaseerr);
- static void hardframe_do_dma(struct soft_scsi *ncr)
- {
- int len = ncr->dmac_length;
- for (int i = 0; i < len; i++) {
- bool phaseerr;
- if (ncr->dmac_direction < 0) {
- uae_u8 v = aic_bget_dma(ncr, &phaseerr);
- if (phaseerr)
- break;
- dma_put_byte(ncr->dmac_address & ncr->dma_mask, v);
- } else if (ncr->dmac_direction > 0) {
- uae_u8 v = dma_get_byte(ncr->dmac_address & ncr->dma_mask);
- aic_bput_dma(ncr, v, &phaseerr);
- if (phaseerr)
- break;
- }
- ncr->dmac_length--;
- ncr->dmac_address++;
- }
- }
- static void xebec_do_dma(struct soft_scsi *ncr)
- {
- struct raw_scsi *rs = &ncr->rscsi;
- while (rs->bus_phase == SCSI_SIGNAL_PHASE_DATA_OUT || rs->bus_phase == SCSI_SIGNAL_PHASE_DATA_IN) {
- if (rs->bus_phase == SCSI_SIGNAL_PHASE_DATA_IN) {
- dma_put_byte(ncr->dmac_address & ncr->dma_mask, ncr5380_bget(ncr, 8));
- } else if (rs->bus_phase == SCSI_SIGNAL_PHASE_DATA_OUT) {
- ncr5380_bput(ncr, 8, dma_get_byte(ncr->dmac_address & ncr->dma_mask));
- }
- }
- }
- static void overdrive_do_dma(struct soft_scsi *ncr)
- {
- struct raw_scsi *rs = &ncr->rscsi;
- while ((rs->bus_phase == SCSI_SIGNAL_PHASE_DATA_OUT || rs->bus_phase == SCSI_SIGNAL_PHASE_DATA_IN) && ncr->dmac_length > 0) {
- if (rs->bus_phase == SCSI_SIGNAL_PHASE_DATA_IN) {
- dma_put_byte(ncr->dmac_address & ncr->dma_mask, ncr5380_bget(ncr, 8));
- ncr->dmac_address++;
- ncr->dmac_length--;
- } else if (rs->bus_phase == SCSI_SIGNAL_PHASE_DATA_OUT) {
- ncr5380_bput(ncr, 8, dma_get_byte(ncr->dmac_address & ncr->dma_mask));
- ncr->dmac_address++;
- ncr->dmac_length--;
- }
- }
- }
- static void fireball_do_dma(struct soft_scsi* ncr)
- {
- struct raw_scsi* rs = &ncr->rscsi;
- while (rs->bus_phase == SCSI_SIGNAL_PHASE_DATA_OUT || rs->bus_phase == SCSI_SIGNAL_PHASE_DATA_IN) {
- if (rs->bus_phase == SCSI_SIGNAL_PHASE_DATA_IN) {
- dma_put_byte(ncr->dmac_address & ncr->dma_mask, ncr5380_bget(ncr, 8));
- ncr->dmac_address++;
- } else if (rs->bus_phase == SCSI_SIGNAL_PHASE_DATA_OUT) {
- ncr5380_bput(ncr, 8, dma_get_byte(ncr->dmac_address & ncr->dma_mask));
- ncr->dmac_address++;
- }
- }
- }
- static void dma_check(struct soft_scsi *ncr)
- {
- if (ncr->dmac_active && ncr->dma_direction) {
- m68k_cancel_idle();
- if (ncr->type == NCR5380_SUPRA && ncr->subtype == 4) {
- if (ncr->dmac_direction != ncr->dma_direction) {
- write_log(_T("SUPRADMA: mismatched direction\n"));
- ncr->dmac_active = 0;
- return;
- }
- supra_do_dma(ncr);
- }
- if (ncr->type == NCR5380_XEBEC) {
-
- xebec_do_dma(ncr);
- }
- if (ncr->type == NONCR_HARDFRAME) {
- hardframe_do_dma(ncr);
- }
- if (ncr->type == NCR5380_OVERDRIVE) {
- overdrive_do_dma(ncr);
- }
- if (ncr->type == NCR5380_FIREBALL) {
- fireball_do_dma(ncr);
- }
- ncr->dmac_active = 0;
- }
- }
- void x86_doirq(uint8_t irqnum);
- static void ncr80_rethink(void)
- {
- for (int i = 0; soft_scsi_devices[i]; i++) {
- struct soft_scsi *s = soft_scsi_devices[i];
- if (s->irq && s->intena && (
- (s->c400 && (s->regs_400[0] & 0x10) && !s->c400_count) ||
- (s->dp8490v && (s->regs[18] & 0x20)) ||
- (!s->c400 && !s->dp8490v)))
- {
- if (soft_scsi_devices[i] == x86_hd_data) {
- ;// x86_doirq(5);
- } else {
- safe_interrupt_set(IRQ_SOURCE_SCSI, i, soft_scsi_devices[i]->level6);
- }
- }
- }
- }
- // AIC-6250
- static void aic_int(struct soft_scsi *scsi, uae_u8 mask)
- {
- scsi->regs[16 + 8] |= mask;
- if ((scsi->regs[16 + 8] & scsi->regs[3]) & 0x1f) {
- scsi->irq = true;
- devices_rethink_all(ncr80_rethink);
- } else {
- scsi->irq = false;
- }
- }
- static bool aic_phase_match(struct soft_scsi *scsi)
- {
- struct raw_scsi *r = &scsi->rscsi;
- uae_u8 phase = r->bus_phase;
- bool cd = (phase & SCSI_IO_COMMAND) != 0;
- bool io = (phase & SCSI_IO_DIRECTION) != 0;
- bool msg = (phase & SCSI_IO_MESSAGE) != 0;
- if (phase >= 0 &&
- ((scsi->regs[9] >> 5) & 1) == msg &&
- ((scsi->regs[9] >> 6) & 1) == io &&
- ((scsi->regs[9] >> 7) & 1) == cd) {
- return true;
- }
- return false;
- }
- static void aic_reg_inc(struct soft_scsi *scsi)
- {
- if (scsi->aic_reg >= 8)
- return;
- scsi->aic_reg++;
- }
- static uae_u8 aic_bget_reg(struct soft_scsi *scsi)
- {
- return scsi->aic_reg & 15;
- }
- static uae_u8 aic_bget_dma(struct soft_scsi *scsi, bool *phaseerr)
- {
- struct raw_scsi *r = &scsi->rscsi;
- if (!scsi->dma_direction)
- return 0;
- if (!aic_phase_match(scsi)) {
- if (phaseerr)
- *phaseerr = true;
- if (!scsi->dmac_active) {
- aic_int(scsi, 0x08); // COMMAND DONE
- }
- scsi->dma_direction = 0;
- return 0;
- }
- if (phaseerr)
- *phaseerr = false;
- return raw_scsi_get_data(r, true);
- }
- static uae_u8 aic_bget_data(struct soft_scsi *scsi)
- {
- struct raw_scsi *r = &scsi->rscsi;
- int reg = scsi->aic_reg;
- uae_u8 v = scsi->regs[reg];
- aic_reg_inc(scsi);
- switch (reg)
- {
- case 0:
- v = (scsi->dmac_length >> 0) & 0xff;
- break;
- case 1:
- v = (scsi->dmac_length >> 8) & 0xff;
- break;
- case 2:
- v = (scsi->dmac_length >> 16) & 0xff;
- break;
- case 6: // REVISION CONTROL
- v = 2;
- break;
- case 7: // STATUS 0
- {
- v = scsi->regs[reg + 16] & 2;
- if (r->bus_phase == SCSI_SIGNAL_PHASE_FREE)
- v |= 0x10; // BUS FREE
- if (raw_scsi_get_signal_phase(r) & SCSI_IO_REQ)
- v |= 0x04; // SCSI REQ ON
- if (scsi->dmac_length == 0)
- v |= 0x01; // DMA BYTE COUNT ZERO
- if ((raw_scsi_get_signal_phase(r) & SCSI_IO_REQ) && !aic_phase_match(scsi))
- v |= 0x20; // PHASE MISMATCH
- }
- break;
- case 8: // STATUS 1
- {
- v = scsi->regs[reg + 16] | 0x40;
- if (scsi->regs[8] & 2) { // SCSI RESET OUT
- v |= 0x20; // SCSI RESET IN
- } else {
- v &= ~0x20;
- }
- scsi->regs[reg + 16] = v;
- }
- break;
- case 9: // SCSI SIGNAL
- {
- uae_u8 t = raw_scsi_get_signal_phase(r);
- v = 0;
- if (t & SCSI_IO_BUSY)
- v |= 0x04;
- if (t & SCSI_IO_ATN)
- v |= 0x10;
- if (t & SCSI_IO_SEL)
- v |= 0x08;
- if (t & SCSI_IO_REQ)
- v |= 0x02;
- if (t & SCSI_IO_DIRECTION)
- v |= 0x40;
- if (t & SCSI_IO_COMMAND)
- v |= 0x80;
- if (t & SCSI_IO_MESSAGE)
- v |= 0x20;
- if (r->ack)
- v |= 0x01;
- }
- break;
- case 10: // SCSI ID DATA
- v = scsi->regs[16 + 10];
- break;
- case 13:
- {
- // SCSI ID (4 to 7 only)
- int vv = scsi->rc->device_id - 4;
- if (vv < 0)
- vv = 0;
- vv ^= 3;
- vv = (vv >> 1) | (vv << 1);
- v = (vv & 3) << 5;
- }
- break;
- }
- return v;
- }
- static void aic_bput_reg(struct soft_scsi *scsi, uae_u8 v)
- {
- scsi->aic_reg = v & 15;
- }
- static void aic_bput_dma(struct soft_scsi *scsi, uae_u8 v, bool *phaseerr)
- {
- struct raw_scsi *r = &scsi->rscsi;
- if (!scsi->dma_direction)
- return;
- if (!aic_phase_match(scsi)) {
- if (phaseerr)
- *phaseerr = true;
- if (!scsi->dmac_active) {
- aic_int(scsi, 0x08); // COMMAND DONE
- }
- scsi->dma_direction = 0;
- return;
- }
- if (phaseerr)
- *phaseerr = false;
- raw_scsi_put_data(r, v, true);
- }
- static void aic_bput_data(struct soft_scsi *scsi, uae_u8 v)
- {
- struct raw_scsi *r = &scsi->rscsi;
- int reg = scsi->aic_reg;
- aic_reg_inc(scsi);
- switch (reg)
- {
- case 0:
- scsi->dmac_length &= 0xffff00;
- scsi->dmac_length |= v << 0;
- break;
- case 1:
- scsi->dmac_length &= 0xff00ff;
- scsi->dmac_length |= v << 8;
- break;
- case 2:
- scsi->dmac_length &= 0x00ffff;
- scsi->dmac_length |= v << 16;
- break;
- case 3: // INT MSK
- // cleared interrupt mask clears request
- scsi->regs[16 + 8] &= v | ~0x1f;
- if (v & 0x40) { // ARB/SEL START
- raw_scsi_put_data(r, scsi->regs[10], false);
- raw_scsi_set_signal_phase(r, false, true, (v & 0x20) != 0);
- raw_scsi_set_signal_phase(r, true, false, false);
- aic_int(scsi, 0x08); // COMMAND DONE
- scsi->regs[11] = scsi->regs[10]; // SOURCE AND DESTINATION ID = DATA
- v &= ~0x40;
- }
- aic_int(scsi, 0);
- break;
- case 5:
- if (v & 1) { // DMA XFER EN
- scsi->dma_direction = (v & 2) ? 1 : -1;
- if (scsi->dmac_active) {
- dma_check(scsi);
- aic_int(scsi, 0x08); // COMMAND DONE
- scsi->dma_direction = 0;
- }
- } else {
- scsi->dma_direction = 0;
- }
- break;
- case 8: // CONTROL
- if (v & 2) { // SCSI RESET OUT
- raw_scsi_reset(r);
- }
- if (v & 0x80) { // AUTO SCSI PIO REQ
- if (aic_phase_match(scsi)) {
- int phase = r->bus_phase;
- bool io = (phase & SCSI_IO_DIRECTION) != 0;
- scsi->regs[16 + 7] &= ~0x02;
- if (!io) {
- raw_scsi_put_data(r, scsi->regs[10], true);
- } else {
- scsi->regs[16 + 10] = raw_scsi_get_data(r, true);
- }
- aic_int(scsi, 0x08); // COMMAND DONE
- if (phase != r->bus_phase)
- scsi->regs[16 + 7] |= 0x02; // SCSI PHASE CHG/ATN
- v &= ~0x80;
- } else {
- aic_int(scsi, 0x10); // ERROR
- }
- }
- break;
- case 9: // SCSI SIGNAL
- break;
- }
- scsi->regs[reg] = v;
- }
- // NCR 53C80/MISC SCSI-LIKE
- static void ncr5380_set_irq(struct soft_scsi *scsi)
- {
- if (scsi->irq)
- return;
- scsi->irq = true;
- devices_rethink_all(ncr80_rethink);
- if (scsi->delayed_irq)
- x_do_cycles(2 * CYCLE_UNIT);
- #if NCR5380_DEBUG_IRQ
- write_log(_T("IRQ\n"));
- #endif
- }
- static void ncr5380_databusoutput(struct soft_scsi *scsi)
- {
- bool databusoutput = (scsi->regs[1] & 1) != 0;
- struct raw_scsi *r = &scsi->rscsi;
- if (r->bus_phase >= 0 && (r->bus_phase & SCSI_IO_DIRECTION))
- databusoutput = false;
- raw_scsi_set_databus(r, databusoutput);
- }
- static void ncr5380_check(struct soft_scsi *scsi)
- {
- ncr5380_databusoutput(scsi);
- }
- static void ncr5380_check_phase(struct soft_scsi *scsi)
- {
- if (!(scsi->regs[2] & 2))
- return;
- if (scsi->regs[2] & 0x40)
- return;
- if (scsi->rscsi.bus_phase != (scsi->regs[3] & 7)) {
- if (scsi->dma_controller) {
- scsi->regs[5] |= 0x80; // end of dma
- scsi->regs[3] |= 0x80; // last byte sent
- }
- ncr5380_set_irq(scsi);
- }
- }
- static void ncr5380_reset(struct soft_scsi *scsi, bool busreset)
- {
- struct raw_scsi *r = &scsi->rscsi;
- if (scsi->dp8490v) {
- // DP8490V manual says all registers are reset but that can't work
- // with Fireball driver. It assumes IMR is not reset.
- memset(scsi->regs, 0, 16);
- } else {
- memset(scsi->regs, 0, sizeof scsi->regs);
- }
- if (busreset) {
- raw_scsi_reset_bus(scsi);
- scsi->regs[1] = 0x80;
- ncr5380_set_irq(scsi);
- }
- }
- uae_u8 ncr5380_bget(struct soft_scsi *scsi, int reg)
- {
- if (reg > 8)
- return 0;
- if (scsi->dp8490v) {
- if ((scsi->regs[1] & 0x40) && reg == 7) {
- reg = 17;
- }
- }
- uae_u8 v = scsi->regs[reg];
- struct raw_scsi *r = &scsi->rscsi;
- switch(reg)
- {
- case 1:
- break;
- case 4:
- {
- uae_u8 oldv = v;
- uae_u8 t = raw_scsi_get_signal_phase(r);
- v = 0;
- if (t & SCSI_IO_BUSY)
- v |= 1 << 6;
- if (t & SCSI_IO_REQ)
- v |= 1 << 5;
- if (t & SCSI_IO_SEL)
- v |= 1 << 1;
- if (r->bus_phase >= 0)
- v |= r->bus_phase << 2;
- if (scsi->regs[1] & 0x80)
- v |= 0x80;
- scsi->regs[reg] = v;
- if (scsi->busy_delayed_hack && !(v & (1 << 6)) && (oldv & (1 << 6))) {
- scsi->busy_delayed_hack_cnt = 2;
- }
- if (scsi->busy_delayed_hack_cnt > 0) {
- scsi->busy_delayed_hack_cnt--;
- v |= 1 << 6;
- }
- }
- break;
- case 5:
- {
- uae_u8 t = raw_scsi_get_signal_phase(r);
- v &= (0x80 | 0x40 | 0x20 | 0x04);
- if (t & SCSI_IO_ATN)
- v |= 1 << 1;
- if (r->bus_phase == (scsi->regs[3] & 7)) {
- v |= 1 << 3;
- }
- if (scsi->irq) {
- v |= 1 << 4;
- }
- if (scsi->dma_drq || (scsi->dma_active && !scsi->dma_controller && r->bus_phase == (scsi->regs[3] & 7))) {
- scsi->dma_drq = true;
- if (scsi->dma_autodack && r->bus_phase != (scsi->regs[3] & 7))
- scsi->dma_drq = false;
- if (scsi->dma_drq)
- v |= 1 << 6;
- }
- if (scsi->regs[2] & 4) {
- // monitor busy
- if (r->bus_phase == SCSI_SIGNAL_PHASE_FREE) {
- // any loss of busy = Busy error
- // not just "unexpected" loss of busy
- v |= 1 << 2;
- scsi->dmac_active = false;
- }
- }
- }
- break;
- case 0:
- v = raw_scsi_get_data(r, false);
- break;
- case 6:
- v = raw_scsi_get_data(r, scsi->dma_active);
- ncr5380_check_phase(scsi);
- break;
- case 7:
- scsi->irq = false;
- break;
- case 17: // DP8490V MODE_E
- {
- int efr = (scsi->regs[17] >> 1) & 3;
- if (efr == 3) {
- v = 0;
- uae_u8 t = raw_scsi_get_signal_phase(r);
- // End of DMA -> DMA Phase Mismatch
- if (scsi->regs[5] & 0x80) {
- v = 0x10;
- }
- // Any Phase Mismatch
- if (r->bus_phase == (scsi->regs[3] & 7)) {
- v |= 0x20;
- }
- scsi->regs[17] &= ~(3 << 1);
- }
- }
- break;
- case 8: // fake dma port
- v = raw_scsi_get_data(r, true);
- ncr5380_check_phase(scsi);
- break;
- }
- ncr5380_check(scsi);
- return v;
- }
- void ncr5380_bput(struct soft_scsi *scsi, int reg, uae_u8 v)
- {
- if (reg > 8)
- return;
- if (scsi->dp8490v) {
- if ((scsi->regs[1] & 0x40) && reg == 7) {
- reg = 17;
- }
- }
- bool dataoutput = (scsi->regs[1] & 1) != 0;
- struct raw_scsi *r = &scsi->rscsi;
- uae_u8 old = scsi->regs[reg];
- scsi->regs[reg] = v;
- switch(reg)
- {
- case 0:
- {
- r->data_write = v;
- // assert data bus can be only active if direction is out
- // and bus phase matches
- if (r->databusoutput) {
- if (((scsi->regs[2] & 2) && scsi->dma_active) || r->bus_phase < 0) {
- raw_scsi_write_data(r, v);
- ncr5380_check_phase(scsi);
- }
- }
- }
- break;
- case 1:
- {
- scsi->regs[reg] &= ~((1 << 5) | (1 << 6));
- scsi->regs[reg] |= old & ((1 << 5) | (1 << 6)); // AIP, LA
- if (!(v & 0x80)) {
- bool init = r->bus_phase < 0;
- ncr5380_databusoutput(scsi);
- if (init && !dataoutput && (v & 1) && (scsi->regs[2] & 1)) {
- r->bus_phase = SCSI_SIGNAL_PHASE_SELECT_1;
- }
- raw_scsi_set_signal_phase(r,
- (v & (1 << 3)) != 0,
- (v & (1 << 2)) != 0,
- (v & (1 << 1)) != 0);
- if (!(scsi->regs[2] & 2))
- raw_scsi_set_ack(r, (v & (1 << 4)) != 0);
- }
- if (v & 0x80) { // RST
- ncr5380_reset(scsi, true);
- }
- if (scsi->dp8490v) {
- scsi->regs[reg] &= ~0x40…
Large files files are truncated, but you can click here to view the full file