#include "compiler.h"
#if defined(SUPPORT_SCSI)
#include "dosio.h"
#include "cpucore.h"
#include "pccore.h"
#include "iocore.h"
#include "cbuscore.h"
#include "scsiio.h"
#include "scsiio.tbl"
#include "scsicmd.h"
#include "sxsi.h"
#if defined(_WIN32) && defined(TRACE)
extern void iptrace_out(void);
#define SCSICMD_ERR MessageBox(NULL, "SCSI error", "?", MB_OK); \
exit(1);
#else
#define SCSICMD_ERR
#endif
static const BYTE hdd_inquiry[0x20] = {
0x00,0x00,0x02,0x02,0x1c,0x00,0x00,0x18,
'N', 'E', 'C', 0x20,0x20,0x20,0x20,0x20,
'N', 'P', '2', '-', 'H', 'D', 'D', 0x20,
0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20};
static UINT scsicmd_datain(SXSIDEV sxsi, BYTE *cdb) {
UINT length;
switch(cdb[0]) {
case 0x12: // Inquiry
TRACEOUT(("Inquiry"));
// Logical unit number = cdb[1] >> 5;
// EVPD = cdb[1] & 1;
// Page code = cdb[2];
length = cdb[4];
if (length) {
CopyMemory(scsiio.data, hdd_inquiry, min(length, 0x20));
}
break;
default:
length = 0;
}
return(length);
}
// ----
REG8 scsicmd_negate(REG8 id) {
scsiio.phase = 0;
return(0x85); // disconnect
}
REG8 scsicmd_select(REG8 id) {
SXSIDEV sxsi;
TRACEOUT(("scsicmd_select"));
if (scsiio.reg[SCSICTR_TARGETLUN] & 7) {
TRACEOUT(("LUN = %d", scsiio.reg[SCSICTR_TARGETLUN] & 7));
return(0x42);
}
sxsi = sxsi_getptr((REG8)(0x20 + id));
if ((sxsi) && (sxsi->type)) {
scsiio.phase = SCSIPH_COMMAND;
return(0x8a); // Transfer Command要求
}
return(0x42); // Timeout
}
REG8 scsicmd_transfer(REG8 id, BYTE *cdb) {
SXSIDEV sxsi;
UINT leng;
if (scsiio.reg[SCSICTR_TARGETLUN] & 7) {
return(0x42);
}
sxsi = sxsi_getptr((REG8)(0x20 + id));
if ((sxsi == NULL) || (sxsi->type == 0)) {
return(0x42);
}
TRACEOUT(("sel ope code = %.2x", cdb[0]));
switch(cdb[0]) {
case 0x00: // Test Unit Ready
return(0x16); // Succeed
case 0x12: // Inquiry
leng = scsicmd_datain(sxsi, cdb);
#if 0
if (leng > scsiio.transfer) {
return(0x2b); // Abort
}
else if (leng < scsiio.transfer) {
return(0x20); // Pause
}
#endif
return(0x16); // Succeed
}
SCSICMD_ERR
return(0xff);
}
static REG8 scsicmd_cmd(REG8 id) {
SXSIDEV sxsi;
TRACEOUT(("scsicmd_cmd = %.2x", scsiio.cmd[0]));
if (scsiio.reg[SCSICTR_TARGETLUN] & 7) {
return(0x42);
}
sxsi = sxsi_getptr((REG8)(0x20 + id));
if ((sxsi == NULL) || (sxsi->type == 0)) {
return(0x42);
}
switch(scsiio.cmd[0]) {
case 0x00:
return(0x8b); // Transfer Status要求
case 0x12: // inquiry
scsicmd_datain(sxsi, scsiio.cmd);
scsiio.phase = SCSIPH_DATAIN;
return(0x89); // Transfer Data要求
}
SCSICMD_ERR
return(0xff);
}
BOOL scsicmd_send(void) {
switch(scsiio.phase) {
case SCSIPH_COMMAND:
scsiio.cmdpos = 0;
return(SUCCESS);
}
return(FAILURE);
}
// ---- BIOS から
static const UINT8 stat2ret[16] = {
0x40, 0x00, 0x10, 0x00,
0x20, 0x00, 0x10, 0x00,
0x30, 0x00, 0x10, 0x00,
0x20, 0x00, 0x10, 0x00};
static REG8 bios1bc_seltrans(REG8 id) {
BYTE cdb[16];
REG8 ret;
i286_memstr_read(CPU_DS, CPU_DX, cdb, 16);
scsiio.reg[SCSICTR_TARGETLUN] = cdb[0];
if ((cdb[1] & 0x0c) == 0x08) { // OUT
i286_memstr_read(CPU_ES, CPU_BX, scsiio.data, CPU_CX);
}
ret = scsicmd_transfer(id, cdb + 4);
if ((cdb[1] & 0x0c) == 0x04) { // IN
i286_memstr_write(CPU_ES, CPU_BX, scsiio.data, CPU_CX);
}
return(ret);
}
void scsicmd_bios(void) {
UINT8 flag;
UINT8 ret;
REG8 stat;
UINT cmd;
REG8 dstid;
TRACEOUT(("BIOS 1B-C* CPU_AH %.2x", CPU_AH));
if (CPU_AH & 0x80) { // エラーぽ
return;
}
flag = i286_membyte_read(CPU_SS, CPU_SP+4) & 0xbe;
ret = mem[0x0483];
cmd = CPU_AH & 0x1f;
dstid = CPU_AL & 7;
if (ret & 0x80) {
mem[0x0483] &= 0x7f;
}
else if (cmd < 0x18) {
switch(cmd) {
case 0x00: // reset
stat = 0x00;
break;
case 0x03: // Negate ACK
stat = scsicmd_negate(dstid);
break;
case 0x07: // Select Without AMN
stat = scsicmd_select(dstid);
break;
case 0x09: // Select Without AMN and Transfer
stat = bios1bc_seltrans(dstid);
break;
default:
TRACEOUT(("cmd = %.2x", CPU_AH));
SCSICMD_ERR
break;
}
ret = stat2ret[stat >> 4] + (stat & 0x0f);
TRACEOUT(("BIOS 1B-C* CPU_AH %.2x ret = %.2x", CPU_AH, ret));
mem[0x0483] = ret;
}
else {
if ((ret ^ cmd) & 0x0f) {
ret = cmd | 0x80;
}
else {
switch(cmd) {
case 0x19: // Data In
i286_memstr_write(CPU_ES, CPU_BX, scsiio.data, CPU_CX);
scsiio.phase = SCSIPH_STATUS;
stat = 0x8b;
break;
case 0x1a: // Transfer command
i286_memstr_read(CPU_ES, CPU_BX, scsiio.cmd, 12);
stat = scsicmd_cmd(dstid);
break;
case 0x1b: // Status In
scsiio.phase = SCSIPH_MSGIN;
stat = 0x8f;
break;
case 0x1f: // Message In
scsiio.phase = 0;
stat = 0x80;
break;
default:
TRACEOUT(("cmd = %.2x", CPU_AH));
SCSICMD_ERR
break;
}
ret = stat2ret[stat >> 4] + (stat & 0x0f);
}
TRACEOUT(("BIOS 1B-C* CPU_AH %.2x ret = %.2x", CPU_AH, ret));
mem[0x0483] = ret;
}
flag |= ret & Z_FLAG;
if (ret & 0x80) {
flag |= C_FLAG;
ret &= 0x7f;
}
CPU_AH = ret;
i286_membyte_write(CPU_SS, CPU_SP + 4, flag);
}
#endif
RetroPC.NET-CVS <cvs@retropc.net>