From c5da4c74e9076082a33ec7bebd86c501bd5d92af Mon Sep 17 00:00:00 2001 From: OBattler Date: Tue, 15 Aug 2017 19:49:25 +0200 Subject: [PATCH] Added BusLogic BT-542B BIOS support (patch from TheCollector1995); Brought the Adaptec AHA-1540B BIOS support to an essentially work state; Fixed some warnings in CPU/808x.c. --- src/CPU/808x.c | 27 +- src/cdrom.h | 1 + src/scsi.h | 17 + src/scsi_aha154x.c | 71 +-- src/scsi_buslogic.c | 1209 ++++++++++++++++++++++++++++++++++++++----- src/scsi_disk.c | 19 +- src/scsi_disk.h | 2 + 7 files changed, 1190 insertions(+), 156 deletions(-) diff --git a/src/CPU/808x.c b/src/CPU/808x.c index dcc95132f..6ff59cbd3 100644 --- a/src/CPU/808x.c +++ b/src/CPU/808x.c @@ -983,7 +983,7 @@ void execx86(int cycs) int8_t offset; int tempws; uint32_t templ; - int c; + unsigned int c; int tempi; int trap; @@ -2439,6 +2439,12 @@ void execx86(int cycs) switch (rmdat&0x38) { case 0x00: /*ROL b,CL*/ + temp2=(temp&0x80)?1:0; + if (!c) + { + cycles-=((cpu_mod==3)?8:28); + break; + } while (c>0) { temp2=(temp&0x80)?1:0; @@ -2454,6 +2460,12 @@ void execx86(int cycs) cycles-=((cpu_mod==3)?8:28); break; case 0x08: /*ROR b,CL*/ + temp2=temp&1; + if (!c) + { + cycles-=((cpu_mod==3)?8:28); + break; + } while (c>0) { temp2=temp&1; @@ -2564,6 +2576,12 @@ void execx86(int cycs) cycles-=((cpu_mod==3)?8:28); break; case 0x08: /*ROR w,CL*/ + tempw2=(tempw&1)?0x8000:0; + if (!c) + { + cycles-=((cpu_mod==3)?8:28); + break; + } while (c>0) { tempw2=(tempw&1)?0x8000:0; @@ -2596,6 +2614,13 @@ void execx86(int cycs) cycles-=((cpu_mod==3)?8:28); break; case 0x18: /*RCR w,CL*/ + templ=flags&C_FLAG; + tempw2=(templ&1)?0x8000:0; + if (!c) + { + cycles-=((cpu_mod==3)?8:28); + break; + } while (c>0) { templ=flags&C_FLAG; diff --git a/src/cdrom.h b/src/cdrom.h index 5b7cb1f8b..17f7f0570 100644 --- a/src/cdrom.h +++ b/src/cdrom.h @@ -233,6 +233,7 @@ void cdrom_update_cdb(uint8_t *cdb, int lba_pos, int number_of_blocks); void cdrom_insert(uint8_t id); int find_cdrom_for_scsi_id(uint8_t scsi_id, uint8_t scsi_lun); +int cdrom_read_capacity(uint8_t id, uint8_t *cdb, uint8_t *buffer, uint32_t *len); #define cdrom_sense_error cdrom[id].sense[0] #define cdrom_sense_key cdrom[id].sense[2] diff --git a/src/scsi.h b/src/scsi.h index 68200572b..96d0dc8c7 100644 --- a/src/scsi.h +++ b/src/scsi.h @@ -289,6 +289,23 @@ typedef struct { #define ADDR_TO_U32(x) (((x).hi<<16)|((x).mid<<8)|((x).lo&0xFF)) #define U32_TO_ADDR(a,x) do {(a).hi=(x)>>16;(a).mid=(x)>>8;(a).lo=(x)&0xFF;}while(0) +#pragma pack(push,1) +typedef struct +{ + uint8_t command; + unsigned char id:3; + unsigned char reserved:2; + unsigned char lun:3; + uint16_t cylinder; + uint8_t head; + uint8_t sector; + uint8_t secount; + addr24 dma_address; +} BIOSCMD; +#pragma pack(pop) + +uint8_t HACommand03Handler(uint8_t last_id, BIOSCMD *BiosCmd); + /* * diff --git a/src/scsi_aha154x.c b/src/scsi_aha154x.c index 1111f86a3..cbb5554b5 100644 --- a/src/scsi_aha154x.c +++ b/src/scsi_aha154x.c @@ -12,7 +12,7 @@ * * NOTE: THIS IS CURRENTLY A MESS, but will be cleaned up as I go. * - * Version: @(#)scsi_aha154x.c 1.0.7 2017/06/14 + * Version: @(#)scsi_aha154x.c 1.0.8 2017/08/15 * * Authors: Fred N. van Kempen, * Original Buslogic version by SA1988 and Miran Grca. @@ -182,6 +182,7 @@ static uint16_t aha_ports[] = { 0x0130, 0x0134, 0x0000, 0x0000 }; +#define WALTJE 1 #ifdef WALTJE int aha_do_log = 1; @@ -310,7 +311,8 @@ aha154x_bios(uint16_t ioaddr, uint32_t memaddr, aha_info *aha, int irq, int dma, /* bios_path = ROMFILE; */ if (chip == CHIP_AHA154XB) { - bios_path = L"roms/scsi/adaptec/aha1540b310.bin"; + /* bios_path = L"roms/scsi/adaptec/aha1540b310.bin"; */ + bios_path = L"roms/scsi/adaptec/B_AC00.BIN"; } else { @@ -545,7 +547,7 @@ aha154x_memory(uint8_t cmd) } -#define AHA_RESET_DURATION_NS UINT64_C(50000000) +#define AHA_RESET_DURATION_NS UINT64_C(25000000) /* @@ -1338,6 +1340,7 @@ aha_read(uint16_t port, void *priv) switch (port & 3) { case 0: + default: ret = dev->Status; break; @@ -1386,14 +1389,18 @@ aha_write(uint16_t port, uint8_t val, void *priv) aha_t *dev = (aha_t *)priv; uint8_t Offset; MailboxInit_t *MailboxInit; + BIOSCMD *BiosCmd; ReplyInquireSetupInformation *ReplyISI; + uint16_t cyl = 0; + uint8_t temp = 0; pclog("AHA154X: Write Port 0x%02X, Value %02X\n", port, val); switch (port & 3) { case 0: if ((val & CTRL_HRST) || (val & CTRL_SRST)) { - uint8_t Reset = !(val & CTRL_HRST); + uint8_t Reset = (val & CTRL_HRST); + pclog("Reset completed = %x\n", Reset); aha_reset_ctrl(dev, Reset); break; } @@ -1466,10 +1473,7 @@ aha_write(uint16_t port, uint8_t val, void *priv) break; case 0x29: - if (dev->chip != CHIP_AHA154XB) - { - dev->CmdParamLeft = 2; - } + dev->CmdParamLeft = 2; break; case 0x91: @@ -1511,7 +1515,16 @@ aha_0x01: break; case 0x03: - dev->DataBuf[0] = 0x00; + BiosCmd = (BIOSCMD *)dev->CmdBuf; + + cyl = ((BiosCmd->cylinder & 0xff) << 8) | ((BiosCmd->cylinder >> 8) & 0xff); + BiosCmd->cylinder = cyl; + temp = BiosCmd->id; + BiosCmd->id = BiosCmd->lun; + BiosCmd->lun = temp; + pclog("C: %04X, H: %02X, S: %02X\n", BiosCmd->cylinder, BiosCmd->head, BiosCmd->sector); + dev->DataBuf[0] = HACommand03Handler(7, BiosCmd); + pclog("BIOS Completion/Status Code %x\n", dev->DataBuf[0]); dev->DataReplyLeft = 1; break; @@ -1683,32 +1696,17 @@ aha_0x01: break; case 0x28: - if (dev->chip == CHIP_AHA154XB) - { - dev->DataReplyLeft = 0; - dev->Status |= STAT_INVCMD; - } - else - { - dev->DataBuf[0] = 0x08; - dev->DataBuf[1] = dev->Lock; - dev->DataReplyLeft = 2; - } + dev->DataBuf[0] = 0x08; + dev->DataBuf[1] = dev->Lock; + dev->DataReplyLeft = 2; break; case 0x29: dev->DataReplyLeft = 0; - if (dev->chip == CHIP_AHA154XB) - { - dev->Status |= STAT_INVCMD; - } - else - { - if (dev->CmdBuf[1] == dev->Lock) { - if (dev->CmdBuf[0] & 1) { - dev->Lock = 1; - } else { - dev->Lock = 0; - } + if (dev->CmdBuf[1] == dev->Lock) { + if (dev->CmdBuf[0] & 1) { + dev->Lock = 1; + } else { + dev->Lock = 0; } } break; @@ -2316,7 +2314,14 @@ aha_init(int chip, int has_bios) if (bios) { /* Perform AHA-154xNN-specific initialization. */ - aha154x_bios(dev->Base, bios_addr, &dev->aha, dev->Irq, dev->DmaChannel, chip); + if (chip == CHIP_AHA154XB) + { + rom_init(&dev->bios, L"roms/scsi/adaptec/B_AC00.BIN", 0xd8000, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL); + } + else + { + aha154x_bios(dev->Base, bios_addr, &dev->aha, dev->Irq, dev->DmaChannel, chip); + } } return(dev); diff --git a/src/scsi_buslogic.c b/src/scsi_buslogic.c index 94348fe76..25ad0e928 100644 --- a/src/scsi_buslogic.c +++ b/src/scsi_buslogic.c @@ -10,7 +10,7 @@ * 0 - BT-542B ISA; * 1 - BT-958 PCI (but BT-542B ISA on non-PCI machines) * - * Version: @(#)scsi_buslogic.c 1.0.4 2017/06/14 + * Version: @(#)scsi_buslogic.c 1.0.5 2017/08/15 * * Authors: TheCollector1995, * Miran Grca, @@ -39,7 +39,7 @@ #include "scsi_buslogic.h" -#define BUSLOGIC_RESET_DURATION_NS UINT64_C(50000000) +#define BUSLOGIC_RESET_DURATION_NS UINT64_C(250000) /* @@ -437,6 +437,29 @@ typedef union { } CCBU; #pragma pack(pop) +#pragma pack(push,1) +typedef struct +{ + /** Data length. */ + uint32_t DataLength; + /** Data pointer. */ + uint32_t DataPointer; + /** The device the request is sent to. */ + uint8_t TargetId; + /** The LUN in the device. */ + uint8_t LogicalUnit; + /** Reserved */ + unsigned char Reserved1 : 3; + /** Data direction for the request. */ + unsigned char DataDirection : 2; + /** Reserved */ + unsigned char Reserved2 : 3; + /** Length of the SCSI CDB. */ + uint8_t CDBLength; + /** The SCSI CDB. (A CDB can be 12 bytes long.) */ + uint8_t CDB[12]; +} ESCMD; +#pragma pack(pop) #pragma pack(push,1) typedef struct { @@ -465,10 +488,10 @@ typedef struct { uint8_t Geometry; uint8_t Control; uint8_t Command; - uint8_t CmdBuf[53]; + uint8_t CmdBuf[128]; uint8_t CmdParam; uint8_t CmdParamLeft; - uint8_t DataBuf[64]; + uint8_t DataBuf[128]; uint16_t DataReply; uint16_t DataReplyLeft; uint32_t MailboxCount; @@ -490,6 +513,7 @@ typedef struct { mem_mapping_t mmio_mapping; int chip; int Card; + int has_bios; } Buslogic_t; #pragma pack(pop) @@ -505,10 +529,9 @@ enum { CHIP_BUSLOGIC_PCI }; - +/* #define ENABLE_BUSLOGIC_LOG 0 */ int buslogic_do_log = 0; - static void BuslogicLog(const char *format, ...) { @@ -525,6 +548,18 @@ BuslogicLog(const char *format, ...) } #define pclog BuslogicLog +static void +SpecificLog(const char *format, ...) +{ +#ifdef ENABLE_BUSLOGIC_LOG + va_list ap; + + va_start(ap, format); + vprintf(format, ap); + va_end(ap); + fflush(stdout); +#endif +} static void BuslogicInterrupt(Buslogic_t *bl, int set) @@ -545,10 +580,12 @@ BuslogicInterrupt(Buslogic_t *bl, int set) if (set) { picint(1 << bl->Irq); + //pclog("Interrupt Set\n"); } else { picintc(1 << bl->Irq); + //pclog("Interrupt Cleared\n"); } } } @@ -557,13 +594,13 @@ BuslogicInterrupt(Buslogic_t *bl, int set) static void BuslogicClearInterrupt(Buslogic_t *bl) { - pclog("Buslogic: Lowering Interrupt 0x%02X\n", bl->Interrupt); + //pclog("Buslogic: Lowering Interrupt 0x%02X\n", bl->Interrupt); bl->Interrupt = 0; - pclog("Lowering IRQ %i\n", bl->Irq); + //pclog("Lowering IRQ %i\n", bl->Irq); BuslogicInterrupt(bl, 0); if (bl->PendingInterrupt) { bl->Interrupt = bl->PendingInterrupt; - pclog("Buslogic: Raising Interrupt 0x%02X (Pending)\n", bl->Interrupt); + //pclog("Buslogic: Raising Interrupt 0x%02X (Pending)\n", bl->Interrupt); if (bl->MailboxOutInterrupts || !(bl->Interrupt & INTR_MBOA)) { if (bl->IrqEnabled) BuslogicInterrupt(bl, 1); } @@ -571,39 +608,14 @@ BuslogicClearInterrupt(Buslogic_t *bl) } } - -static void -BuslogicLocalRAM(Buslogic_t *bl) -{ - /* - * These values are mostly from what I think is right - * looking at the dmesg output from a Linux guest inside - * a VMware server VM. - * - * So they don't have to be right :) - */ - memset(bl->LocalRAM.u8View, 0, sizeof(HALocalRAM)); - bl->LocalRAM.structured.autoSCSIData.fLevelSensitiveInterrupt = 1; - bl->LocalRAM.structured.autoSCSIData.fParityCheckingEnabled = 1; - bl->LocalRAM.structured.autoSCSIData.fExtendedTranslation = 1; /* Same as in geometry register. */ - bl->LocalRAM.structured.autoSCSIData.u16DeviceEnabledMask = UINT16_MAX; /* All enabled. Maybe mask out non present devices? */ - bl->LocalRAM.structured.autoSCSIData.u16WidePermittedMask = UINT16_MAX; - bl->LocalRAM.structured.autoSCSIData.u16FastPermittedMask = UINT16_MAX; - bl->LocalRAM.structured.autoSCSIData.u16SynchronousPermittedMask = UINT16_MAX; - bl->LocalRAM.structured.autoSCSIData.u16DisconnectPermittedMask = UINT16_MAX; - bl->LocalRAM.structured.autoSCSIData.fStrictRoundRobinMode = bl->StrictRoundRobinMode; - bl->LocalRAM.structured.autoSCSIData.u16UltraPermittedMask = UINT16_MAX; - /** @todo calculate checksum? */ -} - - static void BuslogicReset(Buslogic_t *bl) { + //pclog("BuslogicReset()\n"); BuslogicCallback = 0; BuslogicResetCallback = 0; + bl->Geometry = 0x80; bl->Status = STAT_IDLE | STAT_INIT; - bl->Geometry = 0x80; bl->Command = 0xFF; bl->CmdParam = 0; bl->CmdParamLeft = 0; @@ -617,15 +629,14 @@ BuslogicReset(Buslogic_t *bl) bl->Lock = 0; BuslogicInOperation = 0; - BuslogicClearInterrupt(bl); - - BuslogicLocalRAM(bl); + BuslogicClearInterrupt(bl); } static void BuslogicResetControl(Buslogic_t *bl, uint8_t Reset) { + //pclog("BuslogicResetControl()\n"); BuslogicReset(bl); if (Reset) { bl->Status |= STAT_STST; @@ -638,9 +649,10 @@ BuslogicResetControl(Buslogic_t *bl, uint8_t Reset) static void BuslogicCommandComplete(Buslogic_t *bl) { - bl->DataReply = 0; - bl->Status |= STAT_IDLE; - + pclog("BuslogicCommandComplete()\n"); + bl->DataReply = 0; + bl->Status |= STAT_IDLE; + if (bl->Command != 0x02) { bl->Status &= ~STAT_DFULL; bl->Interrupt = (INTR_ANY | INTR_HACC); @@ -650,7 +662,7 @@ BuslogicCommandComplete(Buslogic_t *bl) } bl->Command = 0xFF; - bl->CmdParam = 0; + bl->CmdParam = 0; } @@ -984,6 +996,889 @@ BuslogicDataBufferFree(Req_t *req) } } +static uint8_t +BuslogicConvertSenseLength(uint8_t RequestSenseLength) +{ + pclog("Unconverted Request Sense length %i\n", RequestSenseLength); + + if (RequestSenseLength == 0) + RequestSenseLength = 14; + else if (RequestSenseLength == 1) + RequestSenseLength = 0; + + pclog("Request Sense length %i\n", RequestSenseLength); + + return(RequestSenseLength); +} + + +static void +BuslogicSCSIBIOSDataBufferAllocate(ESCMD *ESCSICmd, uint8_t TargetID, uint8_t LUN) +{ + uint32_t DataPointer, DataLength; + + DataPointer = ESCSICmd->DataPointer; + DataLength = ESCSICmd->DataLength; + + SpecificLog("BIOS Data Buffer write: length %d, pointer 0x%04X\n", + DataLength, DataPointer); + + if (SCSIDevices[TargetID][LUN].CmdBuffer != NULL) + { + free(SCSIDevices[TargetID][LUN].CmdBuffer); + SCSIDevices[TargetID][LUN].CmdBuffer = NULL; + } + + if ((ESCSICmd->DataDirection != 0x03) && DataLength) + { + uint32_t Address = DataPointer; + + SCSIDevices[TargetID][LUN].InitLength = DataLength; + + SCSIDevices[TargetID][LUN].CmdBuffer = (uint8_t *) malloc(DataLength); + memset(SCSIDevices[TargetID][LUN].CmdBuffer, 0, DataLength); + + if (DataLength > 0) { + DMAPageRead(Address, + (char *)SCSIDevices[TargetID][LUN].CmdBuffer, + SCSIDevices[TargetID][LUN].InitLength); + } + } +} + +static void +BuslogicSCSIBIOSDataBufferFree(ESCMD *ESCSICmd, uint8_t TargetID, uint8_t LUN) +{ + uint32_t DataPointer = 0; + uint32_t DataLength = 0; + uint32_t Address; + uint32_t Residual; + + DataPointer = ESCSICmd->DataPointer; + DataLength = ESCSICmd->DataLength; + + if ((DataLength != 0) && (ESCSICmd->CDB[0] == GPCMD_TEST_UNIT_READY)) { + SpecificLog("Data length not 0 with TEST UNIT READY: %i (%i)\n", + DataLength, SCSIDevices[TargetID][LUN].InitLength); + } + + if (ESCSICmd->CDB[0] == GPCMD_TEST_UNIT_READY) { + DataLength = 0; + } + + SpecificLog("BIOS Data Buffer read: length %d, pointer 0x%04X\n", + DataLength, DataPointer); + + /* 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) && + ((ESCSICmd->DataDirection == CCB_DATA_XFER_IN) || + (ESCSICmd->DataDirection == 0x00))) + { + Address = DataPointer; + + SpecificLog("BusLogic BIOS DMA: Writing %i bytes at %08X\n", DataLength, Address); + DMAPageWrite(Address, (char *)SCSIDevices[TargetID][LUN].CmdBuffer, DataLength); + } + + /* Should be 0 when scatter/gather? */ + if (DataLength >= SCSIDevices[TargetID][LUN].InitLength) { + Residual = DataLength; + Residual -= SCSIDevices[TargetID][LUN].InitLength; + } else { + Residual = 0; + } + + ESCSICmd->DataLength = Residual; + SpecificLog("BIOS Residual data length for reading: %d\n", + ESCSICmd->DataLength); + + if (SCSIDevices[TargetID][LUN].CmdBuffer != NULL) + { + free(SCSIDevices[TargetID][LUN].CmdBuffer); + SCSIDevices[TargetID][LUN].CmdBuffer = NULL; + } +} + +static void +BuslogicSCSIBIOSRequestSetup(Buslogic_t *bl, uint8_t *CmdBuf, uint8_t *DataInBuf, uint8_t DataReply) +{ + ESCMD *ESCSICmd = (ESCMD *)CmdBuf; + uint8_t hdc_id, hd_phase; + uint8_t cdrom_id, cdrom_phase; + uint32_t i; + uint8_t temp_cdb[12]; + uint8_t last_id = (bl->chip >= CHIP_BUSLOGIC_ISA) ? 15 : 7; + + DataInBuf[0] = DataInBuf[1] = 0; + + if ((ESCSICmd->TargetId > last_id) || (ESCSICmd->LogicalUnit > 7)) { + DataInBuf[2] = CCB_INVALID_CCB; + DataInBuf[3] = SCSI_STATUS_OK; + return; + } + + SpecificLog("Scanning SCSI Target ID %i\n", ESCSICmd->TargetId); + + SCSIStatus = SCSI_STATUS_OK; + SCSIDevices[ESCSICmd->TargetId][ESCSICmd->LogicalUnit].InitLength = 0; + + BuslogicSCSIBIOSDataBufferAllocate(ESCSICmd, ESCSICmd->TargetId, ESCSICmd->LogicalUnit); + + if (SCSIDevices[ESCSICmd->TargetId][ESCSICmd->LogicalUnit].LunType == SCSI_NONE) { + SpecificLog("SCSI Target ID %i and LUN %i have no device attached\n",ESCSICmd->TargetId,ESCSICmd->LogicalUnit); + BuslogicSCSIBIOSDataBufferFree(ESCSICmd, ESCSICmd->TargetId, ESCSICmd->LogicalUnit); + //BuslogicSCSIBIOSSenseBufferFree(ESCSICmd, Id, Lun, 0, 0); + DataInBuf[2] = CCB_SELECTION_TIMEOUT; + DataInBuf[3] = SCSI_STATUS_OK; + } else { + SpecificLog("SCSI Target ID %i and LUN %i detected and working\n", ESCSICmd->TargetId, ESCSICmd->LogicalUnit); + + SpecificLog("Transfer Control %02X\n", ESCSICmd->DataDirection); + SpecificLog("CDB Length %i\n", ESCSICmd->CDBLength); + if (ESCSICmd->DataDirection > 0x03) { + SpecificLog("Invalid control byte: %02X\n", + ESCSICmd->DataDirection); + } + } + + if (SCSIDevices[ESCSICmd->TargetId][ESCSICmd->LogicalUnit].LunType == SCSI_DISK) + { + hdc_id = scsi_hard_disks[ESCSICmd->TargetId][ESCSICmd->LogicalUnit]; + + if (hdc_id == 0xff) fatal("SCSI hard disk on %02i:%02i has disappeared\n", ESCSICmd->TargetId, ESCSICmd->LogicalUnit); + + SpecificLog("SCSI HD command being executed on: SCSI ID %i, SCSI LUN %i, HD %i\n", + ESCSICmd->TargetId, ESCSICmd->LogicalUnit, hdc_id); + + SpecificLog("SCSI Cdb[0]=0x%02X\n", ESCSICmd->CDB[0]); + for (i = 1; i < ESCSICmd->CDBLength; i++) { + SpecificLog("SCSI Cdb[%i]=%i\n", i, ESCSICmd->CDB[i]); + } + + memset(temp_cdb, 0, 12); + if (ESCSICmd->CDBLength <= 12) { + memcpy(temp_cdb, ESCSICmd->CDB, + ESCSICmd->CDBLength); + } else { + memcpy(temp_cdb, ESCSICmd->CDB, 12); + } + + /* + * Since that field in the HDC struct is never used when + * the bus type is SCSI, let's use it for this scope. + */ + shdc[hdc_id].request_length = temp_cdb[1]; + + if (ESCSICmd->CDBLength != 12) { + /* + * Make sure the LUN field of the temporary CDB is always 0, + * otherwise Daemon Tools drives will misbehave when a command + * is passed through to them. + */ + temp_cdb[1] &= 0x1f; + } + + /* Finally, execute the SCSI command immediately and get the transfer length. */ + SCSIPhase = SCSI_PHASE_COMMAND; + scsi_hd_command(hdc_id, temp_cdb); + SCSIStatus = scsi_hd_err_stat_to_scsi(hdc_id); + if (SCSIStatus == SCSI_STATUS_OK) { + hd_phase = scsi_hd_phase_to_scsi(hdc_id); + if (hd_phase == 2) { + /* Command completed - call the phase callback to complete the command. */ + scsi_hd_callback(hdc_id); + } else { + /* Command first phase complete - call the callback to execute the second phase. */ + scsi_hd_callback(hdc_id); + SCSIStatus = scsi_hd_err_stat_to_scsi(hdc_id); + /* Command second phase complete - call the callback to complete the command. */ + scsi_hd_callback(hdc_id); + } + } else { + /* Error (Check Condition) - call the phase callback to complete the command. */ + scsi_hd_callback(hdc_id); + } + + pclog("SCSI Status: %s, Sense: %02X, ASC: %02X, ASCQ: %02X\n", (SCSIStatus == SCSI_STATUS_OK) ? "OK" : "CHECK CONDITION", shdc[hdc_id].sense[2], shdc[hdc_id].sense[12], shdc[hdc_id].sense[13]); + + BuslogicSCSIBIOSDataBufferFree(ESCSICmd, ESCSICmd->TargetId, ESCSICmd->LogicalUnit); + //BuslogicSCSIBIOSSenseBufferFree(ESCSICmd, Id, Lun, (SCSIStatus != SCSI_STATUS_OK), 1); + + pclog("BIOS Request complete\n"); + + if (SCSIStatus == SCSI_STATUS_OK) { + DataInBuf[2] = CCB_COMPLETE; + DataInBuf[3] = SCSI_STATUS_OK; + } else if (SCSIStatus == SCSI_STATUS_CHECK_CONDITION) { + DataInBuf[2] = CCB_COMPLETE; + DataInBuf[3] = SCSI_STATUS_CHECK_CONDITION; + } + } + else if (SCSIDevices[ESCSICmd->TargetId][ESCSICmd->LogicalUnit].LunType == SCSI_CDROM) + { + cdrom_id = scsi_cdrom_drives[ESCSICmd->TargetId][ESCSICmd->LogicalUnit]; + + if (cdrom_id == 0xff) fatal("SCSI CD-ROM on %02i:%02i has disappeared\n", ESCSICmd->TargetId, ESCSICmd->LogicalUnit); + + pclog("CD-ROM command being executed on: SCSI ID %i, SCSI LUN %i, CD-ROM %i\n", + ESCSICmd->TargetId, ESCSICmd->LogicalUnit, cdrom_id); + + pclog("SCSI Cdb[0]=0x%02X\n", ESCSICmd->CDB[0]); + for (i = 1; i < ESCSICmd->CDBLength; i++) { + pclog("SCSI Cdb[%i]=%i\n", i, ESCSICmd->CDB[i]); + } + + memset(temp_cdb, 0, cdrom[cdrom_id].cdb_len); + if (ESCSICmd->CDBLength <= cdrom[cdrom_id].cdb_len) { + memcpy(temp_cdb, ESCSICmd->CDB, + ESCSICmd->CDBLength); + } else { + memcpy(temp_cdb, ESCSICmd->CDB, cdrom[cdrom_id].cdb_len); + } + + /* + * Since that field in the CDROM struct is never used when + * the bus type is SCSI, let's use it for this scope. + */ + cdrom[cdrom_id].request_length = temp_cdb[1]; + + if (ESCSICmd->CDBLength != 12) { + /* + * Make sure the LUN field of the temporary CDB is always 0, + * otherwise Daemon Tools drives will misbehave when a command + * is passed through to them. + */ + temp_cdb[1] &= 0x1f; + } + + /* Finally, execute the SCSI command immediately and get the transfer length. */ + SCSIPhase = SCSI_PHASE_COMMAND; + cdrom_command(cdrom_id, temp_cdb); + SCSIStatus = cdrom_CDROM_PHASE_to_scsi(cdrom_id); + if (SCSIStatus == SCSI_STATUS_OK) { + cdrom_phase = cdrom_atapi_phase_to_scsi(cdrom_id); + if (cdrom_phase == 2) { + /* Command completed - call the phase callback to complete the command. */ + cdrom_phase_callback(cdrom_id); + } else { + /* Command first phase complete - call the callback to execute the second phase. */ + cdrom_phase_callback(cdrom_id); + SCSIStatus = cdrom_CDROM_PHASE_to_scsi(cdrom_id); + /* Command second phase complete - call the callback to complete the command. */ + cdrom_phase_callback(cdrom_id); + } + } else { + /* Error (Check Condition) - call the phase callback to complete the command. */ + cdrom_phase_callback(cdrom_id); + } + + pclog("SCSI Status: %s, Sense: %02X, ASC: %02X, ASCQ: %02X\n", (SCSIStatus == SCSI_STATUS_OK) ? "OK" : "CHECK CONDITION", cdrom[cdrom_id].sense[2], cdrom[cdrom_id].sense[12], cdrom[cdrom_id].sense[13]); + + BuslogicSCSIBIOSDataBufferFree(ESCSICmd, ESCSICmd->TargetId, ESCSICmd->LogicalUnit); + + pclog("Request complete\n"); + + if (SCSIStatus == SCSI_STATUS_OK) { + DataInBuf[2] = CCB_COMPLETE; + DataInBuf[3] = SCSI_STATUS_OK; + } else if (SCSIStatus == SCSI_STATUS_CHECK_CONDITION) { + DataInBuf[2] = CCB_COMPLETE; + DataInBuf[3] = SCSI_STATUS_CHECK_CONDITION; + } + } + + //BuslogicInOperation = (SCSIDevices[Id][Lun].LunType == SCSI_DISK) ? 0x13 : 3; + pclog("SCSI (%i:%i) -> %i\n", ESCSICmd->TargetId, ESCSICmd->LogicalUnit, SCSIDevices[ESCSICmd->TargetId][ESCSICmd->LogicalUnit].LunType); + + bl->DataReplyLeft = DataReply; +} + +static uint8_t BuslogicCompletionCode(uint8_t *sense) +{ + switch (sense[12]) + { + case 0x00: + return 0x00; + case 0x20: + return 0x01; + case 0x12: + case 0x21: + return 0x02; + case 0x27: + return 0x03; + case 0x14: case 0x16: + return 0x04; + case 0x10: case 0x11: + return 0x10; + case 0x17: case 0x18: + return 0x11; + case 0x01: case 0x03: case 0x05: case 0x06: case 0x07: case 0x08: case 0x09: + case 0x1B: case 0x1C: case 0x1D: + case 0x40: case 0x41: case 0x42: case 0x43: case 0x44: case 0x45: case 0x46: + case 0x47: case 0x48: case 0x49: + return 0x20; + case 0x15: + case 0x02: + return 0x40; + case 0x04: + case 0x28: case 0x29: case 0x2A: + return 0xAA; + default: + return 0xFF; + } +} + +uint8_t BuslogicBIOSCommand08(uint8_t id, uint8_t *buffer, int lun_type) +{ + uint32_t len = 0; + uint8_t cdb[12] = { GPCMD_READ_CDROM_CAPACITY, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + uint8_t rcbuf[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; + int ret = 0; + int i = 0; + uint8_t sc = 0; + + if (lun_type == SCSI_CDROM) + { + ret = cdrom_read_capacity(id, cdb, rcbuf, &len); + sc = BuslogicCompletionCode(cdrom[id].sense); + } + else + { + ret = scsi_hd_read_capacity(id, cdb, rcbuf, &len); + sc = BuslogicCompletionCode(shdc[id].sense); + } + + if (ret == 0) + { + return sc; + } + + memset(buffer, 0, 6); + + for (i = 0; i < 4; i++) + { + buffer[i] = rcbuf[i]; + } + + for (i = 4; i < 6; i++) + { + buffer[i] = rcbuf[(i + 2) ^ 1]; + } + + SpecificLog("BIOS Command 0x08: %02X %02X %02X %02X %02X %02X\n", buffer[0], buffer[1], buffer[2], buffer[3], buffer[4], buffer[5]); + + return 0; +} + +int BuslogicBIOSCommand15(uint8_t id, uint8_t *buffer, int lun_type) +{ + uint32_t len = 0; + uint8_t cdb[12] = { GPCMD_READ_CDROM_CAPACITY, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + uint8_t rcbuf[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; + int ret = 0; + int i = 0; + uint8_t sc = 0; + + if (lun_type == SCSI_CDROM) + { + ret = cdrom_read_capacity(id, cdb, rcbuf, &len); + sc = BuslogicCompletionCode(cdrom[id].sense); + } + else + { + ret = scsi_hd_read_capacity(id, cdb, rcbuf, &len); + sc = BuslogicCompletionCode(shdc[id].sense); + } + + memset(buffer, 0, 6); + + for (i = 0; i < 4; i++) + { + buffer[i] = (ret == 0) ? 0 : rcbuf[i]; + } + + buffer[4] = (lun_type == SCSI_CDROM) ? 5 : 0; + if (lun_type == SCSI_CDROM) + { + buffer[5] = 0x80; + } + else + { + buffer[5] = (hdc[id].bus == HDD_BUS_SCSI_REMOVABLE) ? 0x80 : 0x00; + } + + SpecificLog("BIOS Command 0x15: %02X %02X %02X %02X %02X %02X\n", buffer[0], buffer[1], buffer[2], buffer[3], buffer[4], buffer[5]); + + return sc; +} + +static void BuslogicSCSICDROMPhaseHandler(uint8_t id) +{ + int phase = 0; + + SCSIStatus = cdrom_CDROM_PHASE_to_scsi(id); + if (SCSIStatus == SCSI_STATUS_OK) + { + phase = cdrom_atapi_phase_to_scsi(id); + if (phase == 2) + { + /* Command completed - call the phase callback to complete the command. */ + cdrom_phase_callback(id); + } + else + { + /* Command first phase complete - call the callback to execute the second phase. */ + cdrom_phase_callback(id); + SCSIStatus = cdrom_CDROM_PHASE_to_scsi(id); + /* Command second phase complete - call the callback to complete the command. */ + cdrom_phase_callback(id); + } + } + else + { + /* Error (Check Condition) - call the phase callback to complete the command. */ + cdrom_phase_callback(id); + } +} + +static void BuslogicSCSIDiskPhaseHandler(uint8_t hdc_id) +{ + int phase = 0; + + SCSIStatus = scsi_hd_err_stat_to_scsi(hdc_id); + if (SCSIStatus == SCSI_STATUS_OK) + { + phase = scsi_hd_phase_to_scsi(hdc_id); + if (phase == 2) + { + /* Command completed - call the phase callback to complete the command. */ + scsi_hd_callback(hdc_id); + } + else + { + /* Command first phase complete - call the callback to execute the second phase. */ + scsi_hd_callback(hdc_id); + SCSIStatus = scsi_hd_err_stat_to_scsi(hdc_id); + /* Command second phase complete - call the callback to complete the command. */ + scsi_hd_callback(hdc_id); + } + } + else + { + /* Error (Check Condition) - call the phase callback to complete the command. */ + scsi_hd_callback(hdc_id); + } +} + +static void BuslogicIDCheck(int lun_type, uint8_t cdrom_id, uint8_t hdc_id, BIOSCMD *BiosCmd) +{ + if (lun_type == SCSI_CDROM) + { + if (cdrom_id == 0xff) + { + fatal("BIOS INT13 CD-ROM on %02i:%02i has disappeared\n", BiosCmd->id, BiosCmd->lun); + } + } + else + { + if (hdc_id == 0xff) + { + fatal("BIOS INT13 hard disk on %02i:%02i has disappeared\n", BiosCmd->id, BiosCmd->lun); + } + } +} + +/* This returns the completion code. */ +uint8_t HACommand03Handler(uint8_t last_id, BIOSCMD *BiosCmd) +{ + uint32_t dma_address; + uint8_t cdrom_id, hdc_id; + int lba = (BiosCmd->cylinder << 9) + (BiosCmd->head << 5) + BiosCmd->sector; + int sector_len = BiosCmd->secount; + int block_shift = 9; + int lun_type = SCSI_NONE; + uint8_t ret = 0; + uint8_t cdb[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + + SpecificLog("BIOS Command = 0x%02X\n", BiosCmd->command); + + if ((BiosCmd->id > last_id) || (BiosCmd->lun > 7)) { + return 0x80; + } + + lun_type = SCSIDevices[BiosCmd->id][BiosCmd->lun].LunType; + + cdrom_id = scsi_cdrom_drives[BiosCmd->id][BiosCmd->lun]; + hdc_id = scsi_hard_disks[BiosCmd->id][BiosCmd->lun]; + + SCSIDevices[BiosCmd->id][BiosCmd->lun].InitLength = 0; + + if (lun_type == SCSI_NONE) + { + SpecificLog("BIOS Target ID %i and LUN %i have no device attached\n",BiosCmd->id,BiosCmd->lun); + return 0x80; + } + + dma_address = ADDR_TO_U32(BiosCmd->dma_address); + + SpecificLog("BIOS Data Buffer write: length %d, pointer 0x%04X\n", sector_len, dma_address); + + if (SCSIDevices[BiosCmd->id][BiosCmd->lun].CmdBuffer != NULL) + { + free(SCSIDevices[BiosCmd->id][BiosCmd->lun].CmdBuffer); + SCSIDevices[BiosCmd->id][BiosCmd->lun].CmdBuffer = NULL; + } + + switch(BiosCmd->command) + { + case 0x00: /* Reset Disk System, in practice it's a nop */ + return 0; + + break; + + case 0x01: /* Read Status of Last Operation */ + BuslogicIDCheck(lun_type, cdrom_id, hdc_id, BiosCmd); + + /* Assuming 14 bytes because that's the default length for SCSI sense, and no command-specific + indication is given. */ + SCSIDevices[BiosCmd->id][BiosCmd->lun].InitLength = 14; + + SCSIDevices[BiosCmd->id][BiosCmd->lun].CmdBuffer = (uint8_t *) malloc(14); + memset(SCSIDevices[BiosCmd->id][BiosCmd->lun].CmdBuffer, 0, 14); + + SCSIStatus = BuslogicBIOSCommand08((lun_type == SCSI_CDROM) ? cdrom_id : hdc_id, SCSIDevices[BiosCmd->id][BiosCmd->lun].CmdBuffer, lun_type) ? SCSI_STATUS_OK : SCSI_STATUS_CHECK_CONDITION; + + if (sector_len > 0) + { + SpecificLog("BusLogic BIOS DMA: Reading 14 bytes at %08X\n", dma_address); + if (lun_type == SCSI_CDROM) + { + DMAPageWrite(dma_address, (char *)cdrom[cdrom_id].sense, 14); + } + else + { + DMAPageWrite(dma_address, (char *)shdc[hdc_id].sense, 14); + } + } + + if (SCSIDevices[BiosCmd->id][BiosCmd->lun].CmdBuffer != NULL) + { + free(SCSIDevices[BiosCmd->id][BiosCmd->lun].CmdBuffer); + SCSIDevices[BiosCmd->id][BiosCmd->lun].CmdBuffer = NULL; + } + + return BuslogicCompletionCode((lun_type == SCSI_CDROM) ? cdrom[cdrom_id].sense : shdc[hdc_id].sense); + + break; + + case 0x02: /* Read Desired Sectors to Memory */ + BuslogicIDCheck(lun_type, cdrom_id, hdc_id, BiosCmd); + + if (lun_type == SCSI_CDROM) + { + block_shift = 11; + } + + SCSIDevices[BiosCmd->id][BiosCmd->lun].InitLength = sector_len << block_shift; + + SCSIDevices[BiosCmd->id][BiosCmd->lun].CmdBuffer = (uint8_t *) malloc(sector_len << block_shift); + memset(SCSIDevices[BiosCmd->id][BiosCmd->lun].CmdBuffer, 0, sector_len << block_shift); + + cdb[0] = GPCMD_READ_10; + cdb[2] = (lba >> 24) & 0xff; + cdb[3] = (lba >> 16) & 0xff; + cdb[4] = (lba >> 8) & 0xff; + cdb[5] = lba & 0xff; + cdb[7] = (sector_len >> 8) & 0xff; + cdb[8] = sector_len & 0xff; + + if (lun_type == SCSI_CDROM) + { + cdrom[cdrom_id].request_length = (BiosCmd->lun & 7) << 5; + cdrom_command(cdrom_id, cdb); + BuslogicSCSICDROMPhaseHandler(cdrom_id); + } + else + { + shdc[hdc_id].request_length = (BiosCmd->lun & 7) << 5; + scsi_hd_command(hdc_id, cdb); + BuslogicSCSIDiskPhaseHandler(hdc_id); + } + + if (sector_len > 0) + { + SpecificLog("BusLogic BIOS DMA: Reading %i bytes at %08X\n", sector_len << block_shift, dma_address); + DMAPageWrite(dma_address, (char *)SCSIDevices[BiosCmd->id][BiosCmd->lun].CmdBuffer, sector_len << block_shift); + } + + if (SCSIDevices[BiosCmd->id][BiosCmd->lun].CmdBuffer != NULL) + { + free(SCSIDevices[BiosCmd->id][BiosCmd->lun].CmdBuffer); + SCSIDevices[BiosCmd->id][BiosCmd->lun].CmdBuffer = NULL; + } + + return BuslogicCompletionCode((lun_type == SCSI_CDROM) ? cdrom[cdrom_id].sense : shdc[hdc_id].sense); + + break; + + case 0x03: /* Write Desired Sectors from Memory */ + BuslogicIDCheck(lun_type, cdrom_id, hdc_id, BiosCmd); + + if (lun_type == SCSI_CDROM) + { + block_shift = 11; + } + + SCSIDevices[BiosCmd->id][BiosCmd->lun].InitLength = sector_len << block_shift; + + SCSIDevices[BiosCmd->id][BiosCmd->lun].CmdBuffer = (uint8_t *) malloc(sector_len << block_shift); + memset(SCSIDevices[BiosCmd->id][BiosCmd->lun].CmdBuffer, 0, sector_len << block_shift); + + if (sector_len > 0) + { + SpecificLog("BusLogic BIOS DMA: Reading %i bytes at %08X\n", sector_len << block_shift, dma_address); + DMAPageRead(dma_address, (char *)SCSIDevices[BiosCmd->id][BiosCmd->lun].CmdBuffer, sector_len << block_shift); + } + + cdb[0] = GPCMD_WRITE_10; + cdb[2] = (lba >> 24) & 0xff; + cdb[3] = (lba >> 16) & 0xff; + cdb[4] = (lba >> 8) & 0xff; + cdb[5] = lba & 0xff; + cdb[7] = (sector_len >> 8) & 0xff; + cdb[8] = sector_len & 0xff; + + if (lun_type == SCSI_CDROM) + { + cdrom[cdrom_id].request_length = (BiosCmd->lun & 7) << 5; + cdrom_command(cdrom_id, cdb); + BuslogicSCSICDROMPhaseHandler(cdrom_id); + } + else + { + shdc[hdc_id].request_length = (BiosCmd->lun & 7) << 5; + scsi_hd_command(hdc_id, cdb); + BuslogicSCSIDiskPhaseHandler(hdc_id); + } + + if (SCSIDevices[BiosCmd->id][BiosCmd->lun].CmdBuffer != NULL) + { + free(SCSIDevices[BiosCmd->id][BiosCmd->lun].CmdBuffer); + SCSIDevices[BiosCmd->id][BiosCmd->lun].CmdBuffer = NULL; + } + + return BuslogicCompletionCode((lun_type == SCSI_CDROM) ? cdrom[cdrom_id].sense : shdc[hdc_id].sense); + + break; + + case 0x04: /* Verify Desired Sectors */ + BuslogicIDCheck(lun_type, cdrom_id, hdc_id, BiosCmd); + + if (lun_type == SCSI_CDROM) + { + block_shift = 11; + } + + cdb[0] = GPCMD_VERIFY_10; + cdb[2] = (lba >> 24) & 0xff; + cdb[3] = (lba >> 16) & 0xff; + cdb[4] = (lba >> 8) & 0xff; + cdb[5] = lba & 0xff; + cdb[7] = (sector_len >> 8) & 0xff; + cdb[8] = sector_len & 0xff; + + if (lun_type == SCSI_CDROM) + { + cdrom[cdrom_id].request_length = (BiosCmd->lun & 7) << 5; + cdrom_command(cdrom_id, cdb); + BuslogicSCSICDROMPhaseHandler(cdrom_id); + } + else + { + shdc[hdc_id].request_length = (BiosCmd->lun & 7) << 5; + scsi_hd_command(hdc_id, cdb); + BuslogicSCSIDiskPhaseHandler(hdc_id); + } + + return BuslogicCompletionCode((lun_type == SCSI_CDROM) ? cdrom[cdrom_id].sense : shdc[hdc_id].sense); + + break; + + case 0x05: /* Format Track, invalid since SCSI has no tracks */ + return 1; + + break; + + case 0x06: /* Identify SCSI Devices, in practice it's a nop */ + return 0; + + break; + + case 0x07: /* Format Unit */ + BuslogicIDCheck(lun_type, cdrom_id, hdc_id, BiosCmd); + + cdb[0] = GPCMD_FORMAT_UNIT; + + if (lun_type == SCSI_CDROM) + { + cdrom[cdrom_id].request_length = (BiosCmd->lun & 7) << 5; + cdrom_command(cdrom_id, cdb); + BuslogicSCSICDROMPhaseHandler(cdrom_id); + } + else + { + shdc[hdc_id].request_length = (BiosCmd->lun & 7) << 5; + scsi_hd_command(hdc_id, cdb); + BuslogicSCSIDiskPhaseHandler(hdc_id); + } + + return BuslogicCompletionCode((lun_type == SCSI_CDROM) ? cdrom[cdrom_id].sense : shdc[hdc_id].sense); + + break; + + case 0x08: /* Read Drive Parameters */ + BuslogicIDCheck(lun_type, cdrom_id, hdc_id, BiosCmd); + + SCSIDevices[BiosCmd->id][BiosCmd->lun].InitLength = 6; + + SCSIDevices[BiosCmd->id][BiosCmd->lun].CmdBuffer = (uint8_t *) malloc(6); + memset(SCSIDevices[BiosCmd->id][BiosCmd->lun].CmdBuffer, 0, 6); + + ret = BuslogicBIOSCommand08((lun_type == SCSI_CDROM) ? cdrom_id : hdc_id, SCSIDevices[BiosCmd->id][BiosCmd->lun].CmdBuffer, lun_type); + + SpecificLog("BusLogic BIOS DMA: Reading 6 bytes at %08X\n", dma_address); + DMAPageWrite(dma_address, (char *)SCSIDevices[BiosCmd->id][BiosCmd->lun].CmdBuffer, 6); + + if (SCSIDevices[BiosCmd->id][BiosCmd->lun].CmdBuffer != NULL) + { + free(SCSIDevices[BiosCmd->id][BiosCmd->lun].CmdBuffer); + SCSIDevices[BiosCmd->id][BiosCmd->lun].CmdBuffer = NULL; + } + + return ret; + + break; + + case 0x09: /* Initialize Drive Pair Characteristics, in practice it's a nop */ + return 0; + + break; + + case 0x0C: /* Seek */ + BuslogicIDCheck(lun_type, cdrom_id, hdc_id, BiosCmd); + + SCSIDevices[BiosCmd->id][BiosCmd->lun].InitLength = sector_len << block_shift; + + cdb[0] = GPCMD_SEEK_10; + cdb[2] = (lba >> 24) & 0xff; + cdb[3] = (lba >> 16) & 0xff; + cdb[4] = (lba >> 8) & 0xff; + cdb[5] = lba & 0xff; + + if (lun_type == SCSI_CDROM) + { + cdrom[cdrom_id].request_length = (BiosCmd->lun & 7) << 5; + cdrom_command(cdrom_id, cdb); + BuslogicSCSICDROMPhaseHandler(cdrom_id); + } + else + { + shdc[hdc_id].request_length = (BiosCmd->lun & 7) << 5; + scsi_hd_command(hdc_id, cdb); + BuslogicSCSIDiskPhaseHandler(hdc_id); + } + + return (SCSIStatus == SCSI_STATUS_OK) ? 1 : 0; + + break; + + case 0x0D: /* Alternate Disk Reset, in practice it's a nop */ + return 0; + + break; + + case 0x10: /* Test Drive Ready */ + BuslogicIDCheck(lun_type, cdrom_id, hdc_id, BiosCmd); + + cdb[0] = GPCMD_TEST_UNIT_READY; + + if (lun_type == SCSI_CDROM) + { + cdrom[cdrom_id].request_length = (BiosCmd->lun & 7) << 5; + cdrom_command(cdrom_id, cdb); + BuslogicSCSICDROMPhaseHandler(cdrom_id); + } + else + { + shdc[hdc_id].request_length = (BiosCmd->lun & 7) << 5; + scsi_hd_command(hdc_id, cdb); + BuslogicSCSIDiskPhaseHandler(hdc_id); + } + + return BuslogicCompletionCode((lun_type == SCSI_CDROM) ? cdrom[cdrom_id].sense : shdc[hdc_id].sense); + + break; + + case 0x11: /* Recalibrate */ + BuslogicIDCheck(lun_type, cdrom_id, hdc_id, BiosCmd); + + cdb[0] = GPCMD_REZERO_UNIT; + + if (lun_type == SCSI_CDROM) + { + cdrom[cdrom_id].request_length = (BiosCmd->lun & 7) << 5; + cdrom_command(cdrom_id, cdb); + BuslogicSCSICDROMPhaseHandler(cdrom_id); + } + else + { + shdc[hdc_id].request_length = (BiosCmd->lun & 7) << 5; + scsi_hd_command(hdc_id, cdb); + BuslogicSCSIDiskPhaseHandler(hdc_id); + } + + return BuslogicCompletionCode((lun_type == SCSI_CDROM) ? cdrom[cdrom_id].sense : shdc[hdc_id].sense); + + break; + + case 0x14: /* Controller Diagnostic */ + return 0; + + break; + + case 0x15: /* Read DASD Type */ + BuslogicIDCheck(lun_type, cdrom_id, hdc_id, BiosCmd); + + SCSIDevices[BiosCmd->id][BiosCmd->lun].InitLength = 6; + + SCSIDevices[BiosCmd->id][BiosCmd->lun].CmdBuffer = (uint8_t *) malloc(6); + memset(SCSIDevices[BiosCmd->id][BiosCmd->lun].CmdBuffer, 0, 6); + + ret = BuslogicBIOSCommand15((lun_type == SCSI_CDROM) ? cdrom_id : hdc_id, SCSIDevices[BiosCmd->id][BiosCmd->lun].CmdBuffer, lun_type); + + SpecificLog("BusLogic BIOS DMA: Reading 6 bytes at %08X\n", dma_address); + DMAPageWrite(dma_address, (char *)SCSIDevices[BiosCmd->id][BiosCmd->lun].CmdBuffer, 6); + + if (SCSIDevices[BiosCmd->id][BiosCmd->lun].CmdBuffer != NULL) + { + free(SCSIDevices[BiosCmd->id][BiosCmd->lun].CmdBuffer); + SCSIDevices[BiosCmd->id][BiosCmd->lun].CmdBuffer = NULL; + } + + return ret; + + break; + + default: + SpecificLog("BusLogic BIOS: Unimplemented command: %02X\n", BiosCmd->command); + return 1; + + break; + } + + pclog("BIOS Request complete\n"); +} static uint8_t BuslogicRead(uint16_t Port, void *p) @@ -993,15 +1888,21 @@ BuslogicRead(uint16_t Port, void *p) switch (Port & 3) { case 0: + default: Temp = bl->Status; break; case 1: - if (bl->UseLocalRAM) + if (bl->UseLocalRAM && (bl->Command == 0x91)) + { Temp = bl->LocalRAM.u8View[bl->DataReply]; + } else + { Temp = bl->DataBuf[bl->DataReply]; - if (bl->DataReplyLeft) { + } + if (bl->DataReplyLeft) + { bl->DataReply++; bl->DataReplyLeft--; if (!bl->DataReplyLeft) { @@ -1052,19 +1953,23 @@ BuslogicWrite(uint16_t Port, uint8_t Val, void *p) Buslogic_t *bl = (Buslogic_t *)p; uint8_t Offset; MailboxInit_t *MailboxInit; + BIOSCMD *BiosCmd; ReplyInquireSetupInformation *ReplyISI; MailboxInitExtended_t *MailboxInitE; ReplyInquireExtendedSetupInformation *ReplyIESI; BuslogicPCIInformation_t *ReplyPI; char aModelName[] = "542B "; /* Trailing \0 is fine, that's the filler anyway. */ int cCharsToTransfer; + uint16_t cyl = 0; pclog("Buslogic: Write Port 0x%02X, Value %02X\n", Port, Val); - switch (Port & 3) { + switch (Port & 3) + { case 0: - if ((Val & CTRL_HRST) || (Val & CTRL_SRST)) { - uint8_t Reset = !(Val & CTRL_HRST); + if ((Val & CTRL_HRST) || (Val & CTRL_SRST)) + { + uint8_t Reset = (Val & CTRL_HRST); BuslogicResetControl(bl, Reset); break; } @@ -1092,12 +1997,16 @@ BuslogicWrite(uint16_t Port, uint8_t Val, void *p) bl->CmdParamLeft = 0; bl->Status &= ~(STAT_INVCMD | STAT_IDLE); - pclog("Buslogic: Operation Code 0x%02X\n", Val); + SpecificLog("Buslogic: Operation Code 0x%02X\n", Val); switch (bl->Command) { case 0x01: bl->CmdParamLeft = sizeof(MailboxInit_t); break; - + + case 0x03: + bl->CmdParamLeft = 10; + break; + case 0x25: bl->CmdParamLeft = 1; break; @@ -1108,38 +2017,56 @@ BuslogicWrite(uint16_t Port, uint8_t Val, void *p) case 0x09: case 0x0D: case 0x1F: - case 0x21: - case 0x24: bl->CmdParamLeft = 1; + break; + + case 0x21: + bl->CmdParamLeft = 5; break; + case 0x1A: + case 0x1B: + bl->CmdParamLeft = 3; + break; + case 0x06: bl->CmdParamLeft = 4; break; - case 0x1C: - case 0x1D: - bl->CmdParamLeft = 3; - break; - case 0x8B: case 0x8D: case 0x8F: case 0x96: bl->CmdParamLeft = 1; break; - + case 0x81: bl->CmdParamLeft = sizeof(MailboxInitExtended_t); break; + + case 0x83: + bl->CmdParamLeft = 12; + break; case 0x8C: bl->CmdParamLeft = 1; break; + case 0x90: + bl->CmdParamLeft = 2; + break; + case 0x91: bl->CmdParamLeft = 2; break; + + case 0x92: + bl->CmdParamLeft = 1; + break; + + case 0x94: + bl->CmdParamLeft = 3; + break; case 0x95: /* Valid only for PCI */ bl->CmdParamLeft = (bl->chip == CHIP_BUSLOGIC_PCI) ? 1 : 0; @@ -1149,10 +2076,16 @@ BuslogicWrite(uint16_t Port, uint8_t Val, void *p) bl->CmdBuf[bl->CmdParam] = Val; bl->CmdParam++; bl->CmdParamLeft--; + + if ((bl->CmdParam == 2) && (bl->Command == 0x90)) + { + bl->CmdParamLeft = bl->CmdBuf[1]; + } } - if (!bl->CmdParamLeft) { - pclog("Running Operation Code 0x%02X\n", bl->Command); + if (!bl->CmdParamLeft) + { + SpecificLog("Running Operation Code 0x%02X\n", bl->Command); switch (bl->Command) { case 0x00: bl->DataReplyLeft = 0; @@ -1177,15 +2110,22 @@ BuslogicWrite(uint16_t Port, uint8_t Val, void *p) break; case 0x03: - bl->DataBuf[0] = 0x00; + BiosCmd = (BIOSCMD *)bl->CmdBuf; + + cyl = ((BiosCmd->cylinder & 0xff) << 8) | ((BiosCmd->cylinder >> 8) & 0xff); + BiosCmd->cylinder = cyl; + SpecificLog("C: %04X, H: %02X, S: %02X\n", BiosCmd->cylinder, BiosCmd->head, BiosCmd->sector); + bl->DataBuf[0] = HACommand03Handler((bl->chip >= CHIP_BUSLOGIC_ISA) ? 15 : 7, BiosCmd); + SpecificLog("BIOS Completion/Status Code %x\n", bl->DataBuf[0]); bl->DataReplyLeft = 1; break; case 0x04: + pclog("Inquire Board\n"); bl->DataBuf[0] = 0x41; bl->DataBuf[1] = 0x41; - bl->DataBuf[2] = '5'; - bl->DataBuf[3] = '0'; + bl->DataBuf[2] = '2'; + bl->DataBuf[3] = '2'; bl->DataReplyLeft = 4; break; @@ -1198,8 +2138,9 @@ BuslogicWrite(uint16_t Port, uint8_t Val, void *p) } bl->DataReplyLeft = 0; break; - + case 0x06: + pclog("Selection Time-Out\n"); bl->DataReplyLeft = 0; break; @@ -1235,6 +2176,7 @@ BuslogicWrite(uint16_t Port, uint8_t Val, void *p) break; case 0x0B: + pclog("Inquire Configuration\n"); bl->DataBuf[0] = (1 << bl->DmaChannel); if ((bl->Irq >= 9) && (bl->Irq <= 15)) { @@ -1271,7 +2213,7 @@ BuslogicWrite(uint16_t Port, uint8_t Val, void *p) } break; - case 0x1C: + case 0x1A: { uint32_t FIFOBuf; addr24 Address; @@ -1281,11 +2223,12 @@ BuslogicWrite(uint16_t Port, uint8_t Val, void *p) Address.mid = bl->CmdBuf[1]; Address.lo = bl->CmdBuf[2]; FIFOBuf = ADDR_TO_U32(Address); + pclog("Buslogic LocalRAM: Reading 64 bytes at %08X\n", FIFOBuf); DMAPageRead(FIFOBuf, (char *)&bl->LocalRAM.u8View[64], 64); } break; - case 0x1D: + case 0x1B: { uint32_t FIFOBuf; addr24 Address; @@ -1295,7 +2238,7 @@ BuslogicWrite(uint16_t Port, uint8_t Val, void *p) Address.mid = bl->CmdBuf[1]; Address.lo = bl->CmdBuf[2]; FIFOBuf = ADDR_TO_U32(Address); - pclog("Buslogic FIFO: Writing 64 bytes at %08X\n", FIFOBuf); + pclog("Buslogic LocalRAM: Writing 64 bytes at %08X\n", FIFOBuf); DMAPageWrite(FIFOBuf, (char *)&bl->LocalRAM.u8View[64], 64); } break; @@ -1319,17 +2262,11 @@ BuslogicWrite(uint16_t Port, uint8_t Val, void *p) case 0x23: memset(bl->DataBuf, 0, 8); for (i = 8; i < 16; i++) { -#if 1 /* FIXME: Kotori, check this! */ + /* FIXME: Kotori, check this! */ bl->DataBuf[i-8] = 0; for (j=0; j<8; j++) { if (SCSIDevices[i][j].LunType != SCSI_NONE) bl->DataBuf[i-8] |= (1<DataBuf[i] = 0; - for (i=0; j<8; j++) { - if (SCSIDevices[i][j].LunType != SCSI_NONE) - bl->DataBuf[i] |= (1<DataReplyLeft = 8; @@ -1379,14 +2316,27 @@ BuslogicWrite(uint16_t Port, uint8_t Val, void *p) bl->DataReplyLeft = 0; } break; + + case 0x83: + if (bl->CmdParam == 12) + { + bl->CmdParamLeft = bl->CmdBuf[11]; + pclog("Execute SCSI BIOS Command: %u more bytes follow\n", bl->CmdParamLeft); + } + else + { + pclog("Execute SCSI BIOS Command: received %u bytes\n", bl->CmdBuf[0]); + BuslogicSCSIBIOSRequestSetup(bl, bl->CmdBuf, bl->DataBuf, 4); + } + break; case 0x84: - bl->DataBuf[0] = '7'; + bl->DataBuf[0] = '1'; bl->DataReplyLeft = 1; break; case 0x85: - bl->DataBuf[0] = 'B'; + bl->DataBuf[0] = 'E'; bl->DataReplyLeft = 1; break; @@ -1445,6 +2395,13 @@ BuslogicWrite(uint16_t Port, uint8_t Val, void *p) for (i = 0; i < cCharsToTransfer; i++) bl->DataBuf[i] = aModelName[i]; + + pclog("Model Name\n"); + pclog("Buffer 0: %x\n", bl->DataBuf[0]); + pclog("Buffer 1: %x\n", bl->DataBuf[1]); + pclog("Buffer 2: %x\n", bl->DataBuf[2]); + pclog("Buffer 3: %x\n", bl->DataBuf[3]); + pclog("Buffer 4: %x\n", bl->DataBuf[4]); } break; @@ -1459,7 +2416,7 @@ BuslogicWrite(uint16_t Port, uint8_t Val, void *p) memset(ReplyIESI, 0, sizeof(ReplyInquireExtendedSetupInformation)); ReplyIESI->uBusType = (bl->chip == CHIP_BUSLOGIC_PCI) ? 'E' : 'A'; /* ISA style */ - ReplyIESI->uBiosAddress = 0; + ReplyIESI->uBiosAddress = 0xd8; ReplyIESI->u16ScatterGatherLimit = 8192; ReplyIESI->cMailbox = bl->MailboxCount; ReplyIESI->uMailboxAddressBase = bl->MailboxOutAddr; @@ -1468,8 +2425,8 @@ BuslogicWrite(uint16_t Port, uint8_t Val, void *p) ReplyIESI->fHostWideSCSI = 1; ReplyIESI->fHostUltraSCSI = 1; } - memcpy(ReplyIESI->aFirmwareRevision, "07B", sizeof(ReplyIESI->aFirmwareRevision)); - pclog("Return Extended Setup Information: %d\n", bl->CmdBuf[0]); + memcpy(ReplyIESI->aFirmwareRevision, "21E", sizeof(ReplyIESI->aFirmwareRevision)); + SpecificLog("Return Extended Setup Information: %d\n", bl->CmdBuf[0]); break; /* VirtualBox has these two modes implemented in reverse. @@ -1487,14 +2444,30 @@ BuslogicWrite(uint16_t Port, uint8_t Val, void *p) bl->DataReplyLeft = 0; break; + case 0x90: + pclog("Store Local RAM\n"); + + Offset = bl->CmdBuf[0]; + bl->DataReplyLeft = 0; + + for (i = 0; i < bl->CmdBuf[1]; i++) + { + bl->LocalRAM.u8View[Offset + i] = bl->CmdBuf[i + 2]; + } + + bl->UseLocalRAM = 0; + bl->DataReply = Offset; + break; + case 0x91: + pclog("Fetch Local RAM\n"); Offset = bl->CmdBuf[0]; bl->DataReplyLeft = bl->CmdBuf[1]; bl->UseLocalRAM = 1; bl->DataReply = Offset; break; - + case 0x95: if (bl->chip == CHIP_BUSLOGIC_PCI) { if (bl->Base != 0) { @@ -1555,18 +2528,25 @@ BuslogicWrite(uint16_t Port, uint8_t Val, void *p) bl->DataReplyLeft = 0; break; - + default: + SpecificLog("Invalid command %x\n", bl->Command); bl->DataReplyLeft = 0; bl->Status |= STAT_INVCMD; break; } } - + if (bl->DataReplyLeft) + { bl->Status |= STAT_DFULL; + pclog("Data Full\n"); + } else if (!bl->CmdParamLeft) + { BuslogicCommandComplete(bl); + pclog("No Command Parameters Left, completing command\n"); + } break; case 2: @@ -1594,22 +2574,6 @@ BuslogicWriteL(uint16_t Port, uint32_t Val, void *p) } -static uint8_t -BuslogicConvertSenseLength(uint8_t RequestSenseLength) -{ - pclog("Unconverted Request Sense length %i\n", RequestSenseLength); - - if (RequestSenseLength == 0) - RequestSenseLength = 14; - else if (RequestSenseLength == 1) - RequestSenseLength = 0; - - pclog("Request Sense length %i\n", RequestSenseLength); - - return(RequestSenseLength); -} - - static void BuslogicSenseBufferFree(Req_t *req, int Copy, int is_hd) { @@ -1668,12 +2632,12 @@ BuslogicHDCommand(Buslogic_t *bl) if (hdc_id == 0xff) fatal("SCSI hard disk on %02i:%02i has disappeared\n", Id, Lun); - pclog("SCSI HD command being executed on: SCSI ID %i, SCSI LUN %i, HD %i\n", + SpecificLog("SCSI HD command being executed on: SCSI ID %i, SCSI LUN %i, HD %i\n", Id, Lun, hdc_id); - pclog("SCSI Cdb[0]=0x%02X\n", req->CmdBlock.common.Cdb[0]); + SpecificLog("SCSI Cdb[0]=0x%02X\n", req->CmdBlock.common.Cdb[0]); for (i = 1; i < req->CmdBlock.common.CdbLength; i++) { - pclog("SCSI Cdb[%i]=%i\n", i, req->CmdBlock.common.Cdb[i]); + SpecificLog("SCSI Cdb[%i]=%i\n", i, req->CmdBlock.common.Cdb[i]); } memset(temp_cdb, 0, 12); @@ -2204,8 +3168,8 @@ BuslogicPCIWrite(int func, int addr, uint8_t val, void *p) bl->MMIOBase, 0x20); } } - return; - + return; + case 0x3C: buslogic_pci_regs[addr] = val; if (val != 0xFF) { @@ -2247,7 +3211,9 @@ BuslogicInit(int chip) bl->MMIOBase = 0; bl->Irq = device_get_config_int("irq"); bl->DmaChannel = device_get_config_int("dma"); + bl->has_bios = device_get_config_int("bios"); + if (bl->Base != 0) { if (bl->chip == CHIP_BUSLOGIC_PCI) { io_sethandler(bl->Base, 4, @@ -2261,23 +3227,31 @@ BuslogicInit(int chip) } } + if (bl->has_bios && bl->chip == CHIP_BUSLOGIC_ISA) + { + rom_init(&bl->bios, L"roms/scsi/buslogic/542_470.ROM", 0xd8000, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL); + } + pclog("Building SCSI hard disk map...\n"); build_scsi_hd_map(); pclog("Building SCSI CD-ROM map...\n"); build_scsi_cdrom_map(); - - for (i=0; i<16; i++) { - for (j=0; j<8; j++) { - if (scsi_hard_disks[i][j] != 0xff) { - SCSIDevices[i][j].LunType = SCSI_DISK; + + for (i=0; i<16; i++) + { + for (j=0; j<8; j++) + { + if (scsi_hard_disks[i][j] != 0xff) { + SCSIDevices[i][j].LunType = SCSI_DISK; + } + else if (find_cdrom_for_scsi_id(i, j) != 0xff) { + SCSIDevices[i][j].LunType = SCSI_CDROM; + } + else + { + SCSIDevices[i][j].LunType = SCSI_NONE; + } } - else if (find_cdrom_for_scsi_id(i, j) != 0xff) { - SCSIDevices[i][j].LunType = SCSI_CDROM; - } - else { - SCSIDevices[i][j].LunType = SCSI_NONE; - } - } } timer_add(BuslogicResetPoll, @@ -2307,7 +3281,7 @@ BuslogicInit(int chip) pclog("Buslogic on port 0x%04X\n", bl->Base); BuslogicResetControl(bl, CTRL_HRST); - + return(bl); } @@ -2408,6 +3382,9 @@ static device_config_t BuslogicConfig[] = { } }, }, + { + "bios", "Enable BIOS", CONFIG_BINARY, "", 0 + }, { "", "", -1 } diff --git a/src/scsi_disk.c b/src/scsi_disk.c index a3b8c7dda..1a7c95a65 100644 --- a/src/scsi_disk.c +++ b/src/scsi_disk.c @@ -14,6 +14,7 @@ #include #include #include +#include #include "86box.h" #include "cdrom.h" @@ -115,11 +116,12 @@ uint8_t scsi_hd_command_flags[0x100] = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; +/* #define ENABLE_SCSI_HD_LOG 0 */ int scsi_hd_do_log = 0; void scsi_hd_log(const char *format, ...) { -#ifdef ENABLE_scsi_hd_LOG +#ifdef ENABLE_SCSI_HD_LOG if (scsi_hd_do_log) { va_list ap; @@ -291,7 +293,13 @@ int scsi_hd_read_capacity(uint8_t id, uint8_t *cdb, uint8_t *buffer, uint32_t *l buffer[3] = size & 0xff; buffer[6] = 2; /* 512 = 0x0200 */ *len = 8; - + + pclog("Read Capacity\n"); + pclog("buffer[0]=%x\n", buffer[0]); + pclog("buffer[1]=%x\n", buffer[1]); + pclog("buffer[2]=%x\n", buffer[2]); + pclog("buffer[3]=%x\n", buffer[3]); + return 1; } @@ -353,7 +361,7 @@ static void scsi_hd_command_common(uint8_t id) } } -static void scsi_hd_command_complete(uint8_t id) +void scsi_hd_command_complete(uint8_t id) { shdc[id].packet_status = CDROM_PHASE_COMPLETE; scsi_hd_command_common(id); @@ -372,7 +380,7 @@ static void scsi_hd_command_write_dma(uint8_t id) scsi_hd_command_common(id); } -static void scsi_hd_data_command_finish(uint8_t id, int len, int block_len, int alloc_len, int direction) +void scsi_hd_data_command_finish(uint8_t id, int len, int block_len, int alloc_len, int direction) { scsi_hd_log("SCSI HD %i: Finishing command (%02X): %i, %i, %i, %i, %i\n", id, shdc[id].current_cdb[0], len, block_len, alloc_len, direction, shdc[id].request_length); shdc[id].pos=0; @@ -470,7 +478,7 @@ static void scsi_hd_illegal_opcode(uint8_t id) scsi_hd_cmd_error(id); } -static void scsi_hd_lba_out_of_range(uint8_t id) +void scsi_hd_lba_out_of_range(uint8_t id) { scsi_hd_sense_key = SENSE_ILLEGAL_REQUEST; scsi_hd_asc = ASC_LBA_OUT_OF_RANGE; @@ -792,7 +800,6 @@ void scsi_hd_command(uint8_t id, uint8_t *cdb) case GPCMD_READ_10: shdc[id].sector_len = (cdb[7] << 8) | cdb[8]; shdc[id].sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; - scsi_hd_log("SCSI HD %i: Length: %i, LBA: %i\n", id, shdc[id].sector_len, shdc[id].sector_pos); break; case GPCMD_READ_12: shdc[id].sector_len = (((uint32_t) cdb[6]) << 24) | (((uint32_t) cdb[7]) << 16) | (((uint32_t) cdb[8]) << 8) | ((uint32_t) cdb[9]); diff --git a/src/scsi_disk.h b/src/scsi_disk.h index db3ea9848..7d5b23e85 100644 --- a/src/scsi_disk.h +++ b/src/scsi_disk.h @@ -52,3 +52,5 @@ extern void scsi_reloadhd(int id); extern void scsi_unloadhd(int scsi_id, int scsi_lun, int id); extern FILE *shdf[HDC_NUM]; + +int scsi_hd_read_capacity(uint8_t id, uint8_t *cdb, uint8_t *buffer, uint32_t *len);