diff --git a/src/Makefile.mingw b/src/Makefile.mingw index 8b0bba5e3..fc210da6e 100644 --- a/src/Makefile.mingw +++ b/src/Makefile.mingw @@ -4,13 +4,13 @@ CC = gcc.exe WINDRES = windres.exe CFLAGS = -O3 -march=native -mtune=native -fbranch-probabilities -fvpt -fpeel-loops -ftracer -fomit-frame-pointer -ffast-math -msse -msse2 -msse3 -mssse3 -mfpmath=sse -mstackrealign DFLAGS = -O3 -march=i686 -fomit-frame-pointer -msse2 -mstackrealign -OBJ = 386.o 386_dynarec.o 386_dynarec_ops.o 808x.o acer386sx.o acerm3a.o aha154x.o ali1429.o amstrad.o cdrom-ioctl.o cdrom-iso.o \ +OBJ = 386.o 386_dynarec.o 386_dynarec_ops.o 808x.o acer386sx.o acerm3a.o ali1429.o amstrad.o buslogic.o cdrom-ioctl.o cdrom-iso.o \ cdrom-null.o codegen.o codegen_ops.o codegen_timing_486.o codegen_timing_686.o codegen_timing_pentium.o codegen_timing_winchip.o codegen_x86.o compaq.o config.o cpu.o dac.o \ device.o disc.o disc_86f.o disc_fdi.o disc_imd.o disc_img.o disc_random.o disc_td0.o dma.o fdc.o fdc37c665.o fdc37c932fr.o fdd.o fdi2raw.o gameport.o headland.o i430hx.o i430lx.o i430fx.o \ i430nx.o i430vx.o i440fx.o ide.o intel.o intel_flash.o io.o jim.o joystick_ch_flightstick_pro.o joystick_standard.o joystick_sw_pad.o joystick_tm_fcs.o keyboard.o keyboard_amstrad.o keyboard_at.o \ keyboard_olim24.o keyboard_pcjr.o keyboard_xt.o lpt.o mcr.o mem.o memregs.o model.o mouse.o mouse_ps2.o \ mouse_serial.o ne2000.o neat.o nethandler.o nmi.o nvr.o olivetti_m24.o opti495.o pc.o pc87306.o pci.o pic.o piix.o pit.o ppi.o ps1.o rom.o rtc.o \ - scat.o scattergather.o scsi.o scsi_cdrom.o serial.o sis496.o sis85c471.o sio.o sound.o sound_ad1848.o sound_adlib.o sound_adlibgold.o sound_cms.o \ + scat.o scsi.o scsi_cdrom.o serial.o sis496.o sis85c471.o sio.o sound.o sound_ad1848.o sound_adlib.o sound_adlibgold.o sound_cms.o \ sound_dbopl.o sound_emu8k.o sound_gus.o sound_mpu401_uart.o sound_opl.o sound_pas16.o sound_ps1.o sound_pssj.o sound_resid.o \ sound_sb.o sound_sb_dsp.o sound_sn76489.o sound_speaker.o sound_ssi2001.o sound_wss.o sound_ym7128.o \ soundopenal.o tandy_eeprom.o tandy_rom.o timer.o um8669f.o vid_ati_eeprom.o vid_ati_mach64.o vid_ati18800.o \ diff --git a/src/Makefile.mingw64 b/src/Makefile.mingw64 index 763838af4..87d95a549 100644 --- a/src/Makefile.mingw64 +++ b/src/Makefile.mingw64 @@ -4,13 +4,13 @@ CC = gcc.exe WINDRES = windres.exe CFLAGS = -O3 -march=native -mtune=native -fbranch-probabilities -fvpt -fpeel-loops -ftracer -fomit-frame-pointer -ffast-math -msse -msse2 -msse3 -mssse3 -mfpmath=sse -mstackrealign DFLAGS = -O3 -fomit-frame-pointer -msse2 -OBJ = 386.o 386_dynarec.o 386_dynarec_ops.o 808x.o acer386sx.o acerm3a.o aha154x.o ali1429.o amstrad.o cdrom-ioctl.o cdrom-iso.o \ +OBJ = 386.o 386_dynarec.o 386_dynarec_ops.o 808x.o acer386sx.o acerm3a.o ali1429.o amstrad.o buslogic.o cdrom-ioctl.o cdrom-iso.o \ cdrom-null.o codegen.o codegen_ops.o codegen_timing_486.o codegen_timing_686.o codegen_timing_pentium.o codegen_timing_winchip.o codegen_x86-64.o compaq.o config.o cpu.o dac.o \ device.o disc.o disc_86f.o disc_fdi.o disc_imd.o disc_img.o disc_random.o disc_td0.o dma.o fdc.o fdc37c665.o fdc37c932fr.o fdd.o fdi2raw.o gameport.o headland.o i430hx.o i430lx.o i430fx.o \ i430nx.o i430vx.o i440fx.o ide.o intel.o intel_flash.o io.o jim.o joystick_ch_flightstick_pro.o joystick_standard.o joystick_sw_pad.o joystick_tm_fcs.o keyboard.o keyboard_amstrad.o keyboard_at.o \ keyboard_olim24.o keyboard_pcjr.o keyboard_xt.o lpt.o mcr.o mem.o memregs.o model.o mouse.o mouse_ps2.o \ mouse_serial.o ne2000.o neat.o nethandler.o nmi.o nvr.o olivetti_m24.o opti495.o pc.o pc87306.o pci.o pic.o piix.o pit.o ppi.o ps1.o rom.o rtc.o \ - scat.o scattergather.o scsi.o scsi_cdrom.o serial.o sis496.o sis85c471.o sio.o sound.o sound_ad1848.o sound_adlib.o sound_adlibgold.o sound_cms.o \ + scat.o scsi.o scsi_cdrom.o serial.o sis496.o sis85c471.o sio.o sound.o sound_ad1848.o sound_adlib.o sound_adlibgold.o sound_cms.o \ sound_dbopl.o sound_emu8k.o sound_gus.o sound_mpu401_uart.o sound_opl.o sound_pas16.o sound_ps1.o sound_pssj.o sound_resid.o \ sound_sb.o sound_sb_dsp.o sound_sn76489.o sound_speaker.o sound_ssi2001.o sound_wss.o sound_ym7128.o \ soundopenal.o tandy_eeprom.o tandy_rom.o timer.o um8669f.o vid_ati_eeprom.o vid_ati_mach64.o vid_ati18800.o \ diff --git a/src/aha154x.c b/src/aha154x.c deleted file mode 100644 index c4b921920..000000000 --- a/src/aha154x.c +++ /dev/null @@ -1,1302 +0,0 @@ -/* Copyright holders: SA1988 - see COPYING for more details -*/ -/*Adaptec 154x SCSI emulation and clones (including Buslogic ISA adapters)*/ - -/* -ToDo: -Improve support for DOS, Windows 3.x and Windows 9x as well as NT. -*/ - -#include -#include -#include -#include - -#include "ibm.h" -#include "device.h" -#include "io.h" -#include "mem.h" -#include "dma.h" -#include "rom.h" -#include "pic.h" -#include "timer.h" - -#include "cdrom.h" -#include "scsi.h" - -#include "aha154x.h" - -typedef struct -{ - uint8_t hi; - uint8_t mid; - uint8_t lo; -} addr24; - -#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) - -// I/O Port interface -// READ Port x+0: STATUS -// WRITE Port x+0: CONTROL -// -// READ Port x+1: DATA -// WRITE Port x+1: COMMAND -// -// READ Port x+2: INTERRUPT STATUS -// WRITE Port x+2: (undefined?) -// -// R/W Port x+3: (undefined) - -// READ STATUS flags -#define STAT_STST 0x80 // self-test in progress -#define STAT_DFAIL 0x40 // internal diagnostic failure -#define STAT_INIT 0x20 // mailbox initialization required -#define STAT_IDLE 0x10 // HBA is idle -#define STAT_CDFULL 0x08 // Command/Data output port is full -#define STAT_DFULL 0x04 // Data input port is full -#define STAT_INVCMD 0x01 // Invalid command - -// READ INTERRUPT STATUS flags -#define INTR_ANY 0x80 // any interrupt -#define INTR_SRCD 0x08 // SCSI reset detected -#define INTR_HACC 0x04 // HA command complete -#define INTR_MBOA 0x02 // MBO empty -#define INTR_MBIF 0x01 // MBI full - -// WRITE CONTROL commands -#define CTRL_HRST 0x80 // Hard reset -#define CTRL_SRST 0x40 // Soft reset -#define CTRL_IRST 0x20 // interrupt reset -#define CTRL_SCRST 0x10 // SCSI bus reset - -// READ/WRITE DATA commands -#define CMD_NOP 0x00 // No operation -#define CMD_MBINIT 0x01 // mailbox initialization -#define CMD_START_SCSI 0x02 // Start SCSI command -#define CMD_INQUIRY 0x04 // Adapter inquiry -#define CMD_EMBOI 0x05 // enable Mailbox Out Interrupt -#define CMD_SELTIMEOUT 0x06 // Set SEL timeout -#define CMD_BUSON_TIME 0x07 // set bus-On time -#define CMD_BUSOFF_TIME 0x08 // set bus-off time -#define CMD_DMASPEED 0x09 // set ISA DMA speed -#define CMD_RETDEVS 0x0A // return installed devices -#define CMD_RETCONF 0x0B // return configuration data -#define CMD_TARGET 0x0C // set HBA to target mode -#define CMD_RETSETUP 0x0D // return setup data -#define CMD_ECHO 0x1F // ECHO command data - -/** Structure for the INQUIRE_SETUP_INFORMATION reply. */ -typedef struct ReplyInquireSetupInformationSynchronousValue -{ - uint8_t uOffset : 4; - uint8_t uTransferPeriod : 3; - uint8_t fSynchronous : 1; -}ReplyInquireSetupInformationSynchronousValue; - -typedef struct ReplyInquireSetupInformation -{ - uint8_t fSynchronousInitiationEnabled : 1; - uint8_t fParityCheckingEnabled : 1; - uint8_t uReserved1 : 6; - uint8_t uBusTransferRate; - uint8_t uPreemptTimeOnBus; - uint8_t uTimeOffBus; - uint8_t cMailbox; - addr24 MailboxAddress; - ReplyInquireSetupInformationSynchronousValue SynchronousValuesId0To7[8]; - uint8_t uDisconnectPermittedId0To7; - uint8_t uSignature; - uint8_t uCharacterD; - uint8_t uHostBusType; - uint8_t uWideTransferPermittedId0To7; - uint8_t uWideTransfersActiveId0To7; - ReplyInquireSetupInformationSynchronousValue SynchronousValuesId8To15[8]; - uint8_t uDisconnectPermittedId8To15; - uint8_t uReserved2; - uint8_t uWideTransferPermittedId8To15; - uint8_t uWideTransfersActiveId8To15; -} ReplyInquireSetupInformation; - -/** Structure for the INQUIRE_EXTENDED_SETUP_INFORMATION. */ -#pragma pack(1) -typedef struct ReplyInquireExtendedSetupInformation -{ - uint8_t uBusType; - uint8_t uBiosAddress; - uint16_t u16ScatterGatherLimit; - uint8_t cMailbox; - uint32_t uMailboxAddressBase; - uint8_t uReserved1 : 2; - uint8_t fFastEISA : 1; - uint8_t uReserved2 : 3; - uint8_t fLevelSensitiveInterrupt : 1; - uint8_t uReserved3 : 1; - uint8_t aFirmwareRevision[3]; - uint8_t fHostWideSCSI : 1; - uint8_t fHostDifferentialSCSI : 1; - uint8_t fHostSupportsSCAM : 1; - uint8_t fHostUltraSCSI : 1; - uint8_t fHostSmartTermination : 1; - uint8_t uReserved4 : 3; -} ReplyInquireExtendedSetupInformation; -#pragma pack() - -typedef struct MailboxInit_t -{ - uint8_t Count; - addr24 Address; -} MailboxInit_t; - -#pragma pack(1) -typedef struct MailboxInitExtended_t -{ - uint8_t Count; - uint32_t Address; -} MailboxInitExtended_t; -#pragma pack() - -/////////////////////////////////////////////////////////////////////////////// -// -// Mailbox Definitions -// -// -/////////////////////////////////////////////////////////////////////////////// - -// -// Mailbox Out -// -// -// MBO Command Values -// - -#define MBO_FREE 0x00 -#define MBO_START 0x01 -#define MBO_ABORT 0x02 - -// -// Mailbox In -// -// -// MBI Status Values -// - -#define MBI_FREE 0x00 -#define MBI_SUCCESS 0x01 -#define MBI_ABORT 0x02 -#define MBI_NOT_FOUND 0x03 -#define MBI_ERROR 0x04 - -typedef struct Mailbox_t -{ - uint8_t CmdStatus; - addr24 CCBPointer; -} Mailbox_t; - -typedef struct Mailbox32_t -{ - uint32_t CCBPointer; - union - { - struct - { - uint8_t Reserved[3]; - uint8_t ActionCode; - } out; - struct - { - uint8_t HostStatus; - uint8_t TargetStatus; - uint8_t Reserved; - uint8_t CompletionCode; - } in; - } u; -} Mailbox32_t; - - -/////////////////////////////////////////////////////////////////////////////// -// -// CCB - Adaptec SCSI Command Control Block -// -// The CCB is a superset of the CDB (Command Descriptor Block) -// and specifies detailed information about a SCSI command. -// -/////////////////////////////////////////////////////////////////////////////// - -// -// Byte 0 Command Control Block Operation Code -// - -#define SCSI_INITIATOR_COMMAND 0x00 -#define TARGET_MODE_COMMAND 0x01 -#define SCATTER_GATHER_COMMAND 0x02 -#define SCSI_INITIATOR_COMMAND_RES 0x03 -#define SCATTER_GATHER_COMMAND_RES 0x04 -#define BUS_RESET 0x81 - -// -// Byte 1 Address and Direction Control -// - -#define CCB_TARGET_ID_SHIFT 0x06 // CCB Op Code = 00, 02 -#define CCB_INITIATOR_ID_SHIFT 0x06 // CCB Op Code = 01 -#define CCB_DATA_XFER_IN 0x01 -#define CCB_DATA_XFER_OUT 0x02 -#define CCB_LUN_MASK 0x07 // Logical Unit Number - -// -// Byte 2 SCSI_Command_Length - Length of SCSI CDB -// -// Byte 3 Request Sense Allocation Length -// - -#define FOURTEEN_BYTES 0x00 // Request Sense Buffer size -#define NO_AUTO_REQUEST_SENSE 0x01 // No Request Sense Buffer - -// -// Bytes 4, 5 and 6 Data Length // Data transfer byte count -// -// Bytes 7, 8 and 9 Data Pointer // SGD List or Data Buffer -// -// Bytes 10, 11 and 12 Link Pointer // Next CCB in Linked List -// -// Byte 13 Command Link ID // TBD (I don't know yet) -// -// Byte 14 Host Status // Host Adapter status -// - -#define CCB_COMPLETE 0x00 // CCB completed without error -#define CCB_LINKED_COMPLETE 0x0A // Linked command completed -#define CCB_LINKED_COMPLETE_INT 0x0B // Linked complete with interrupt -#define CCB_SELECTION_TIMEOUT 0x11 // Set SCSI selection timed out -#define CCB_DATA_OVER_UNDER_RUN 0x12 -#define CCB_UNEXPECTED_BUS_FREE 0x13 // Target dropped SCSI BSY -#define CCB_PHASE_SEQUENCE_FAIL 0x14 // Target bus phase sequence failure -#define CCB_BAD_MBO_COMMAND 0x15 // MBO command not 0, 1 or 2 -#define CCB_INVALID_OP_CODE 0x16 // CCB invalid operation code -#define CCB_BAD_LINKED_LUN 0x17 // Linked CCB LUN different from first -#define CCB_INVALID_DIRECTION 0x18 // Invalid target direction -#define CCB_DUPLICATE_CCB 0x19 // Duplicate CCB -#define CCB_INVALID_CCB 0x1A // Invalid CCB - bad parameter - -// -// Byte 15 Target Status -// -// See scsi.h files for these statuses. -// - -// -// Bytes 16 and 17 Reserved (must be 0) -// - -// -// Bytes 18 through 18+n-1, where n=size of CDB Command Descriptor Block -// - -typedef struct CCB32 -{ - uint8_t Opcode; - uint8_t Reserved1:3; - uint8_t ControlByte:2; - uint8_t TagQueued:1; - uint8_t QueueTag:2; - uint8_t CdbLength; - uint8_t RequestSenseLength; - uint32_t DataLength; - uint32_t DataPointer; - uint8_t Reserved2[2]; - uint8_t HostStatus; - uint8_t TargetStatus; - uint8_t Id; - uint8_t Lun:5; - uint8_t LegacyTagEnable:1; - uint8_t LegacyQueueTag:2; - uint8_t Cdb[12]; - uint8_t Reserved3[6]; - uint32_t SensePointer; -} CCB32; - -typedef struct CCB -{ - uint8_t Opcode; - uint8_t Lun:3; - uint8_t ControlByte:2; - uint8_t Id:3; - uint8_t CdbLength; - uint8_t RequestSenseLength; - addr24 DataLength; - addr24 DataPointer; - addr24 LinkPointer; - uint8_t LinkId; - uint8_t HostStatus; - uint8_t TargetStatus; - uint8_t Reserved[2]; - uint8_t Cdb[12]; -} CCB; - -typedef struct CCBC -{ - uint8_t Opcode; - uint8_t Pad1:3; - uint8_t ControlByte:2; - uint8_t Pad2:3; - uint8_t CdbLength; - uint8_t RequestSenseLength; - uint8_t Pad3[10]; - uint8_t HostStatus; - uint8_t TargetStatus; - uint8_t Pad4[2]; - uint8_t Cdb[12]; -} CCBC; - -typedef union CCBU -{ - CCB32 new; - CCB old; - CCBC common; -} CCBU; - -/////////////////////////////////////////////////////////////////////////////// -// -// Scatter/Gather Segment List Definitions -// -/////////////////////////////////////////////////////////////////////////////// - -// -// Adapter limits -// - -#define MAX_SG_DESCRIPTORS 32 - -typedef struct SGE32 -{ - uint32_t Segment; - uint32_t SegmentPointer; -} SGE32; - -typedef struct SGE -{ - addr24 Segment; - addr24 SegmentPointer; -} SGE; - -typedef struct AdaptecRequests_t -{ - CCBU CmdBlock; - uint8_t *RequestSenseBuffer; - uint32_t CCBPointer; - int Is24bit; -} AdaptecRequests_t; - -typedef struct Adaptec_t -{ - rom_t BiosRom; - AdaptecRequests_t AdaptecRequests; - uint8_t Status; - uint8_t Interrupt; - uint8_t Geometry; - uint8_t Control; - uint8_t Command; - uint8_t CmdBuf[5]; - uint8_t CmdParam; - uint8_t CmdParamLeft; - uint8_t DataBuf[64]; - uint8_t DataReply; - uint8_t DataReplyLeft; - uint32_t MailboxCount; - uint32_t MailboxOutAddr; - uint32_t MailboxOutPosCur; - uint32_t MailboxInAddr; - uint32_t MailboxInPosCur; - int Irq; - int DmaChannel; - int IrqEnabled; - int Mbx24bit; -} Adaptec_t; - -Adaptec_t AdaptecLUN[7]; - -int scsi_base = 0x330; -int scsi_dma = 6; -int scsi_irq = 11; - -static void AdaptecSCSIRequestSetup(Adaptec_t *Adaptec, uint32_t CCBPointer); -static void AdaptecStartMailbox(Adaptec_t *Adaptec); - -typedef void (*AdaptecMemCopyCallback)(Adaptec_t *Adaptec, uint32_t Addr, SGBUF *SegmentBuffer, - uint32_t Copy, uint32_t *Skip); - -int aha154x_do_log = 0; - -void AdaptecLog(const char *format, ...) -{ - if (aha154x_do_log) - { - va_list ap; - va_start(ap, format); - vprintf(format, ap); - va_end(ap); - fflush(stdout); - } -} - -static void AdaptecClearInterrupt(Adaptec_t *Adaptec) -{ - AdaptecLog("Adaptec: Clearing Interrupt 0x%02X\n", Adaptec->Interrupt); - Adaptec->Interrupt = 0; - picintc(1 << Adaptec->Irq); -} - -static void AdaptecReset(Adaptec_t *Adaptec) -{ - Adaptec->Status = STAT_IDLE | STAT_INIT; - Adaptec->Geometry = 0x80; - Adaptec->Command = 0xFF; - Adaptec->CmdParam = 0; - Adaptec->CmdParamLeft = 0; - Adaptec->IrqEnabled = 1; - Adaptec->MailboxOutPosCur = 0; - Adaptec->MailboxInPosCur = 0; - - AdaptecClearInterrupt(Adaptec); -} - -static void AdaptecResetControl(Adaptec_t *Adaptec, uint8_t Reset) -{ - AdaptecReset(Adaptec); - if (Reset) - { - Adaptec->Status |= STAT_STST; - Adaptec->Status &= ~STAT_IDLE; - } -} - -static void AdaptecCommandComplete(Adaptec_t *Adaptec) -{ - Adaptec->Status |= STAT_IDLE; - Adaptec->DataReply = 0; - - if (Adaptec->Command != CMD_START_SCSI) - { - Adaptec->Status &= ~STAT_DFULL; - Adaptec->Interrupt = INTR_ANY | INTR_HACC; - picint(1 << Adaptec->Irq); - } - - Adaptec->Command = 0xFF; - Adaptec->CmdParam = 0; -} - -static void AdaptecMailboxIn(Adaptec_t *Adaptec, uint32_t CCBPointer, CCBU *CmdBlock, - uint8_t HostStatus, uint8_t TargetStatus, uint8_t MailboxCompletionCode) -{ - Mailbox32_t Mailbox32; - Mailbox_t MailboxIn; - - Mailbox32.CCBPointer = CCBPointer; - Mailbox32.u.in.HostStatus = HostStatus; - Mailbox32.u.in.TargetStatus = TargetStatus; - Mailbox32.u.in.CompletionCode = MailboxCompletionCode; - - uint32_t Incoming = Adaptec->MailboxInAddr + (Adaptec->MailboxInPosCur * (Adaptec->Mbx24bit ? sizeof(Mailbox_t) : sizeof(Mailbox32_t))); - - if (MailboxCompletionCode != MBI_NOT_FOUND) - { - CmdBlock->common.HostStatus = HostStatus; - CmdBlock->common.TargetStatus = TargetStatus; - - //Rewrite the CCB up to the CDB. - DMAPageWrite(CCBPointer, CmdBlock, offsetof(CCBC, Cdb)); - } - - pclog("Host Status 0x%02X, TargetStatus 0x%02X\n", HostStatus, TargetStatus); - - if (Adaptec->Mbx24bit) - { - MailboxIn.CmdStatus = Mailbox32.u.in.CompletionCode; - U32_TO_ADDR(MailboxIn.CCBPointer, Mailbox32.CCBPointer); - pclog("Mailbox 24-bit: Status=0x%02X, CCB at 0x%08X\n", MailboxIn.CmdStatus, ADDR_TO_U32(MailboxIn.CCBPointer)); - - DMAPageWrite(Incoming, &MailboxIn, sizeof(Mailbox_t)); - } - else - { - pclog("Mailbox 32-bit: Status=0x%02X, CCB at 0x%08X\n", Mailbox32.u.in.CompletionCode, Mailbox32.CCBPointer); - - DMAPageWrite(Incoming, &Mailbox32, sizeof(Mailbox32_t)); - } - - Adaptec->MailboxInPosCur++; - if (Adaptec->MailboxInPosCur > Adaptec->MailboxCount) - Adaptec->MailboxInPosCur = 0; - - Adaptec->Interrupt = INTR_MBIF | INTR_ANY; - picint(1 << Adaptec->Irq); -} - -static void AdaptecReadSGEntries(int Is24bit, uint32_t SGList, uint32_t Entries, SGE32 *SG) -{ - if (Is24bit) - { - uint32_t i; - SGE SGE24[MAX_SG_DESCRIPTORS]; - - DMAPageRead(SGList, &SGE24, Entries * sizeof(SGE)); - - for (i=0;iold.DataPointer); - DataLength = ADDR_TO_U32(CmdBlock->old.DataLength); - } - else - { - DataPointer = CmdBlock->new.DataPointer; - DataLength = CmdBlock->new.DataLength; - } - - if (DataLength && (CmdBlock->common.Opcode != 3)) - { - if (CmdBlock->common.Opcode == SCATTER_GATHER_COMMAND || - CmdBlock->common.Opcode == SCATTER_GATHER_COMMAND_RES) - { - uint32_t ScatterGatherRead; - uint32_t ScatterEntry; - SGE32 ScatterGatherBuffer[MAX_SG_DESCRIPTORS]; - uint32_t ScatterGatherLeft = DataLength / (Is24bit ? sizeof(SGE) : sizeof(SGE32)); - uint32_t ScatterGatherAddrCurrent = DataPointer; - - do - { - ScatterGatherRead = (ScatterGatherLeft < ELEMENTS(ScatterGatherBuffer)) - ? ScatterGatherLeft : ELEMENTS(ScatterGatherBuffer); - - ScatterGatherLeft -= ScatterGatherRead; - - AdaptecReadSGEntries(Is24bit, ScatterGatherAddrCurrent, ScatterGatherRead, ScatterGatherBuffer); - - for (ScatterEntry = 0; ScatterEntry < ScatterGatherRead; ScatterEntry++) - BufferSize += ScatterGatherBuffer[ScatterEntry].Segment; - - ScatterGatherAddrCurrent += ScatterGatherRead * (Is24bit ? sizeof(SGE) : sizeof(SGE32)); - } while (ScatterGatherLeft > 0); - - AdaptecLog("Adaptec: Query Data Buffer\n"); - AdaptecLog("Adaptec: Data Buffer Size=%u\n", BufferSize); - } - else if (CmdBlock->common.Opcode == SCSI_INITIATOR_COMMAND || - CmdBlock->common.Opcode == SCSI_INITIATOR_COMMAND_RES) - BufferSize = DataLength; - } - - *pBufferSize = BufferSize; -} - -static void AdaptecCopyBufferFromGuestWorker(Adaptec_t *Adaptec, uint32_t Address, SGBUF *SegmentBuffer, - uint32_t Copy, uint32_t *pSkip) -{ - uint32_t Skipped = MIN(Copy, *pSkip); - Copy -= Skipped; - Address += Skipped; - *pSkip -= Skipped; - - while (Copy) - { - uint32_t Segment = Copy; - uint8_t *SegmentPointer = SegmentBufferGetNextSegment(SegmentBuffer, Segment); - - DMAPageRead(Address, SegmentPointer, Segment); - - Address += Segment; - Copy -= Segment; - } -} - -static void AdaptecCopyBufferToGuestWorker(Adaptec_t *Adaptec, uint32_t Address, SGBUF *SegmentBuffer, - uint32_t Copy, uint32_t *pSkip) -{ - uint32_t Skipped = MIN(Copy, *pSkip); - Copy -= Skipped; - Address += Skipped; - *pSkip -= Skipped; - - while (Copy) - { - uint32_t Segment = Copy; - uint8_t *SegmentPointer = SegmentBufferGetNextSegment(SegmentBuffer, Segment); - - DMAPageWrite(Address, SegmentPointer, Segment); - - Address += Segment; - Copy -= Segment; - } -} - -static int AdaptecScatterGatherBufferWalker(Adaptec_t *Adaptec, AdaptecRequests_t *AdaptecRequests, - AdaptecMemCopyCallback IoCopyWorker, SGBUF *SegmentBuffer, - uint32_t Skip, uint32_t Copy) -{ - uint32_t Copied = 0; - - Copy += Skip; - - if (AdaptecRequests->Is24bit) - { - DataPointer = ADDR_TO_U32(AdaptecRequests->CmdBlock.old.DataPointer); - DataLength = ADDR_TO_U32(AdaptecRequests->CmdBlock.old.DataLength); - } - else - { - DataPointer = AdaptecRequests->CmdBlock.new.DataPointer; - DataLength = AdaptecRequests->CmdBlock.new.DataLength; - } - - /*Mostly a hack for NT 1991 as the CCB describes a 2K buffer, but Test Unit Ready is executed - and it returns no data, the buffer must be left alone*/ - if (AdaptecRequests->CmdBlock.common.Cdb[0] == GPCMD_TEST_UNIT_READY) - DataLength = 0; - - if ((DataLength > 0) && (AdaptecRequests->CmdBlock.common.ControlByte == CCB_DATA_XFER_IN || - AdaptecRequests->CmdBlock.common.ControlByte == CCB_DATA_XFER_OUT)) - { - if (AdaptecRequests->CmdBlock.common.Opcode == SCATTER_GATHER_COMMAND || - AdaptecRequests->CmdBlock.common.Opcode == SCATTER_GATHER_COMMAND_RES) - { - uint32_t ScatterGatherRead; - uint32_t ScatterEntry; - SGE32 ScatterGatherBuffer[MAX_SG_DESCRIPTORS]; - uint32_t ScatterGatherLeft = DataLength / (AdaptecRequests->Is24bit ? sizeof(SGE) : sizeof(SGE32)); - uint32_t ScatterGatherAddrCurrent = DataPointer; - - do - { - ScatterGatherRead = (ScatterGatherLeft < ELEMENTS(ScatterGatherBuffer)) - ? ScatterGatherLeft : ELEMENTS(ScatterGatherBuffer); - - ScatterGatherLeft -= ScatterGatherRead; - - AdaptecReadSGEntries(AdaptecRequests->Is24bit, ScatterGatherAddrCurrent, ScatterGatherRead, ScatterGatherBuffer); - - for (ScatterEntry = 0; ScatterEntry < ScatterGatherRead; ScatterEntry++) - { - uint32_t Address; - uint32_t CopyThis; - - AdaptecLog("Adaptec: Scatter Entry=%u\n", ScatterEntry); - - Address = ScatterGatherBuffer[ScatterEntry].SegmentPointer; - CopyThis = MIN(Copy, ScatterGatherBuffer[ScatterEntry].Segment); - - AdaptecLog("Adaptec: S/G Address=0x%04X, Copy=%u\n", Address, CopyThis); - - IoCopyWorker(Adaptec, Address, SegmentBuffer, CopyThis, &Skip); - Copied += CopyThis; - Copy -= CopyThis; - } - - ScatterGatherAddrCurrent += ScatterGatherRead * sizeof(SGE); - } while (ScatterGatherLeft > 0 && Copy > 0); - } - else if (AdaptecRequests->CmdBlock.common.Opcode == SCSI_INITIATOR_COMMAND || - AdaptecRequests->CmdBlock.common.Opcode == SCSI_INITIATOR_COMMAND_RES) - { - uint32_t Address = DataPointer; - - AdaptecLog("Adaptec: Non-scattered buffer\n"); - AdaptecLog("Data Pointer=%#x\n", DataPointer); - AdaptecLog("Data Length=%u\n", DataLength); - AdaptecLog("Pointer Address=%#x\n", Address); - - IoCopyWorker(Adaptec, Address, SegmentBuffer, MIN(DataLength, Copy), &Skip); - Copied += MIN(DataLength, Copy); - } - } - - pclog("Opcode %02X\n", AdaptecRequests->CmdBlock.common.Opcode); - - return Copied - MIN(Skip, Copied); -} - -static int AdaptecCopySegmentBufferToGuest(Adaptec_t *Adaptec, AdaptecRequests_t *AdaptecRequests, - SGBUF *SegmentBuffer, uint32_t Skip, uint32_t Copy) -{ - return AdaptecScatterGatherBufferWalker(Adaptec, AdaptecRequests, AdaptecCopyBufferToGuestWorker, SegmentBuffer, Skip, Copy); -} - -static int AdaptecCopySegmentBufferFromGuest(Adaptec_t *Adaptec, AdaptecRequests_t *AdaptecRequests, - SGBUF *SegmentBuffer, uint32_t Skip, uint32_t Copy) -{ - return AdaptecScatterGatherBufferWalker(Adaptec, AdaptecRequests, AdaptecCopyBufferFromGuestWorker, SegmentBuffer, Skip, Copy); -} - -uint8_t AdaptecRead(uint16_t Port, void *p) -{ - Adaptec_t *Adaptec = &AdaptecLUN[scsi_cdrom_id]; - uint8_t Temp; - - switch (Port & 3) - { - case 0: - Temp = Adaptec->Status; - if (Adaptec->Status & STAT_STST) - { - Adaptec->Status &= ~STAT_STST; - Adaptec->Status |= STAT_IDLE; - Temp = Adaptec->Status; - } - break; - - case 1: - Temp = Adaptec->DataBuf[Adaptec->DataReply]; - if (Adaptec->DataReplyLeft) - { - Adaptec->DataReply++; - Adaptec->DataReplyLeft--; - if (!Adaptec->DataReplyLeft) - { - AdaptecCommandComplete(Adaptec); - } - } - break; - - case 2: - Temp = Adaptec->Interrupt; - break; - - case 3: - Temp = Adaptec->Geometry; - break; - } - - AdaptecLog("Adaptec: Read Port 0x%02X, Returned Value %02X\n", Port, Temp); - return Temp; -} - -void AdaptecWrite(uint16_t Port, uint8_t Val, void *p) -{ - Adaptec_t *Adaptec = &AdaptecLUN[scsi_cdrom_id]; - pclog("Adaptec: 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); - AdaptecResetControl(Adaptec, Reset); - break; - } - - if (Val & CTRL_IRST) - AdaptecClearInterrupt(Adaptec); - break; - - case 1: - if ((Val == 0x02) && (Adaptec->Command == 0xFF)) - { - ScsiCallback[scsi_cdrom_id] = 1; - break; - } - - if (Adaptec->Command == 0xFF) - { - Adaptec->Command = Val; - Adaptec->CmdParam = 0; - - Adaptec->Status &= ~(STAT_INVCMD | STAT_IDLE); - pclog("Adaptec: Operation Code 0x%02X\n", Val); - switch (Adaptec->Command) - { - case 0x00: - case 0x03: - case 0x04: - case 0x0A: - case 0x0B: - case 0x84: - case 0x85: - Adaptec->CmdParamLeft = 0; - break; - - case 0x07: - case 0x08: - case 0x09: - case 0x0D: - case 0x1F: - case 0x21: - case 0x8B: - case 0x8D: - case 0x25: - Adaptec->CmdParamLeft = 1; - break; - - case 0x06: - Adaptec->CmdParamLeft = 4; - break; - - case 0x01: - Adaptec->CmdParamLeft = sizeof(MailboxInit_t); - break; - - case 0x81: - Adaptec->CmdParamLeft = sizeof(MailboxInitExtended_t); - break; - - case 0x28: - case 0x29: - Adaptec->CmdParamLeft = 0; - break; - } - } - else - { - Adaptec->CmdBuf[Adaptec->CmdParam] = Val; - Adaptec->CmdParam++; - Adaptec->CmdParamLeft--; - } - - if (!Adaptec->CmdParamLeft) - { - pclog("Running Operation Code 0x%02X\n", Adaptec->Command); - switch (Adaptec->Command) - { - case 0x00: - Adaptec->DataReplyLeft = 0; - break; - - case 0x01: - { - Adaptec->Mbx24bit = 1; - - MailboxInit_t *MailboxInit = (MailboxInit_t *)Adaptec->CmdBuf; - - Adaptec->MailboxCount = MailboxInit->Count; - Adaptec->MailboxOutAddr = ADDR_TO_U32(MailboxInit->Address); - Adaptec->MailboxInAddr = Adaptec->MailboxOutAddr + (Adaptec->MailboxCount * sizeof(Mailbox_t)); - - AdaptecLog("Adaptec Initialize Mailbox Command\n"); - AdaptecLog("Mailbox Out Address=0x%08X\n", Adaptec->MailboxOutAddr); - AdaptecLog("Mailbox In Address=0x%08X\n", Adaptec->MailboxInAddr); - pclog("Initialized Mailbox, %d entries at 0x%08X\n", MailboxInit->Count, ADDR_TO_U32(MailboxInit->Address)); - - Adaptec->Status &= ~STAT_INIT; - Adaptec->DataReplyLeft = 0; - } - break; - - case 0x81: - { - Adaptec->Mbx24bit = 0; - - MailboxInitExtended_t *MailboxInit = (MailboxInitExtended_t *)Adaptec->CmdBuf; - - Adaptec->MailboxCount = MailboxInit->Count; - Adaptec->MailboxOutAddr = MailboxInit->Address; - Adaptec->MailboxInAddr = MailboxInit->Address + (Adaptec->MailboxCount * sizeof(Mailbox32_t)); - - AdaptecLog("Adaptec Extended Initialize Mailbox Command\n"); - AdaptecLog("Mailbox Out Address=0x%08X\n", Adaptec->MailboxOutAddr); - AdaptecLog("Mailbox In Address=0x%08X\n", Adaptec->MailboxInAddr); - pclog("Initialized Extended Mailbox, %d entries at 0x%08X\n", MailboxInit->Count, MailboxInit->Address); - - Adaptec->Status &= ~STAT_INIT; - Adaptec->DataReplyLeft = 0; - } - break; - - case 0x03: - break; - - case 0x04: - Adaptec->DataBuf[0] = 0x41; - Adaptec->DataBuf[1] = 0x41; - Adaptec->DataBuf[2] = '4'; - Adaptec->DataBuf[3] = '7'; - Adaptec->DataReplyLeft = 4; - break; - - case 0x84: - Adaptec->DataBuf[0] = '0'; - Adaptec->DataReplyLeft = 1; - break; - - case 0x85: - Adaptec->DataBuf[0] = 'M'; - Adaptec->DataReplyLeft = 1; - break; - - case 0x06: - Adaptec->DataReplyLeft = 0; - break; - - case 0x07: - Adaptec->DataReplyLeft = 0; - pclog("Bus-on time: %d\n", Adaptec->CmdBuf[0]); - break; - - case 0x08: - Adaptec->DataReplyLeft = 0; - pclog("Bus-off time: %d\n", Adaptec->CmdBuf[0]); - break; - - case 0x09: - Adaptec->DataReplyLeft = 0; - pclog("DMA transfer rate: %02X\n", Adaptec->CmdBuf[0]); - break; - - case 0x0A: - if (ScsiDrives[scsi_cdrom_id].LunType == SCSI_CDROM) - Adaptec->DataBuf[scsi_cdrom_id] = 1; - - Adaptec->DataBuf[7] = 0; - Adaptec->DataReplyLeft = 8; - break; - - case 0x0B: - Adaptec->DataBuf[0] = (1 << Adaptec->DmaChannel); - Adaptec->DataBuf[1] = (1 << (Adaptec->Irq - 9)); - Adaptec->DataBuf[2] = 7; - Adaptec->DataReplyLeft = 3; - break; - - case 0x0D: - { - Adaptec->DataReplyLeft = Adaptec->CmdBuf[0]; - - ReplyInquireSetupInformation *Reply = (ReplyInquireSetupInformation *)Adaptec->DataBuf; - - Reply->fSynchronousInitiationEnabled = 1; - Reply->fParityCheckingEnabled = 1; - Reply->cMailbox = Adaptec->MailboxCount; - U32_TO_ADDR(Reply->MailboxAddress, Adaptec->MailboxOutAddr); - Reply->uSignature = 'B'; - /* The 'D' signature prevents Adaptec's OS/2 drivers from getting too - * friendly with BusLogic hardware and upsetting the HBA state. - */ - Reply->uCharacterD = 'D'; /* BusLogic model. */ - Reply->uHostBusType = 'A'; /* ISA bus. */ - } - break; - - case 0x8B: - { - int i; - - /* The reply length is set by the guest and is found in the first byte of the command buffer. */ - Adaptec->DataReplyLeft = Adaptec->CmdBuf[0]; - memset(Adaptec->DataBuf, 0, Adaptec->DataReplyLeft); - const char aModelName[] = "542B "; /* Trailing \0 is fine, that's the filler anyway. */ - int cCharsToTransfer = Adaptec->DataReplyLeft <= sizeof(aModelName) - ? Adaptec->DataReplyLeft - : sizeof(aModelName); - - for (i = 0; i < cCharsToTransfer; i++) - Adaptec->DataBuf[i] = aModelName[i]; - - } - break; - - case 0x8D: - { - Adaptec->DataReplyLeft = Adaptec->CmdBuf[0]; - ReplyInquireExtendedSetupInformation *Reply = (ReplyInquireExtendedSetupInformation *)Adaptec->DataBuf; - - Reply->uBusType = 'A'; /* ISA style */ - Reply->u16ScatterGatherLimit = 16; - Reply->cMailbox = Adaptec->MailboxCount; - Reply->uMailboxAddressBase = Adaptec->MailboxOutAddr; - Reply->fLevelSensitiveInterrupt = 1; - memcpy(Reply->aFirmwareRevision, "70M", sizeof(Reply->aFirmwareRevision)); - - } - break; - - case 0x1F: - Adaptec->DataBuf[0] = Adaptec->CmdBuf[0]; - Adaptec->DataReplyLeft = 1; - break; - - case 0x21: - if (Adaptec->CmdParam == 1) - Adaptec->CmdParamLeft = Adaptec->CmdBuf[0]; - - Adaptec->DataReplyLeft = 0; - break; - - case 0x25: - if (Adaptec->CmdBuf[0] == 0) - Adaptec->IrqEnabled = 0; - else - Adaptec->IrqEnabled = 1; - break; - - case 0x28: - case 0x29: - Adaptec->DataReplyLeft = 0; - Adaptec->Status |= STAT_INVCMD; - break; - } - } - - if (Adaptec->DataReplyLeft) - Adaptec->Status |= STAT_DFULL; - else if (!Adaptec->CmdParamLeft) - AdaptecCommandComplete(Adaptec); - break; - - case 2: - Adaptec->Irq = Val; - break; - - case 3: - Adaptec->Geometry = Val; - break; - } -} - -static uint8_t AdaptecConvertSenseLength(uint8_t RequestSenseLength) -{ - if (RequestSenseLength == 0) - RequestSenseLength = 14; - else if (RequestSenseLength == 1) - RequestSenseLength = 0; - - return RequestSenseLength; -} - -static void AdaptecSenseBufferAllocate(AdaptecRequests_t *AdaptecRequests) -{ - uint8_t SenseLength = AdaptecConvertSenseLength(AdaptecRequests->CmdBlock.common.RequestSenseLength); - - if (SenseLength) - AdaptecRequests->RequestSenseBuffer = malloc(SenseLength); -} - -static void AdaptecSenseBufferFree(AdaptecRequests_t *AdaptecRequests, int Copy) -{ - uint8_t SenseLength = AdaptecConvertSenseLength(AdaptecRequests->CmdBlock.common.RequestSenseLength); - - if (Copy && SenseLength) - { - uint32_t SenseBufferAddress; - - /*The Sense address, in 32-bit mode, is located in the Sense Pointer of the CCB, but in - 24-bit mode, it is located at the end of the Command Descriptor Block. */ - - if (AdaptecRequests->Is24bit) - { - SenseBufferAddress = AdaptecRequests->CCBPointer; - SenseBufferAddress += AdaptecRequests->CmdBlock.common.CdbLength + offsetof(CCB, Cdb); - } - else - SenseBufferAddress = AdaptecRequests->CmdBlock.new.SensePointer; - - DMAPageWrite(SenseBufferAddress, AdaptecRequests->RequestSenseBuffer, SenseLength); - } - //Free the sense buffer when needed. - free(AdaptecRequests->RequestSenseBuffer); -} - -uint32_t AdaptecIoRequestCopyFromBuffer(uint32_t OffDst, SGBUF *SegmentBuffer, uint32_t Copy) -{ - Adaptec_t *Adaptec = &AdaptecLUN[scsi_cdrom_id]; - uint32_t Copied = 0; - - Copied = AdaptecCopySegmentBufferToGuest(Adaptec, &Adaptec->AdaptecRequests, SegmentBuffer, OffDst, Copy); - - return Copied; -} - -uint32_t AdaptecIoRequestCopyToBuffer(uint32_t OffSrc, SGBUF *SegmentBuffer, uint32_t Copy) -{ - Adaptec_t *Adaptec = &AdaptecLUN[scsi_cdrom_id]; - uint32_t Copied = 0; - - Copied = AdaptecCopySegmentBufferFromGuest(Adaptec, &Adaptec->AdaptecRequests, SegmentBuffer, OffSrc, Copy); - - return Copied; -} - -static void AdaptecSCSIRequestComplete(Adaptec_t *Adaptec, AdaptecRequests_t *AdaptecRequests) -{ - if (AdaptecRequests->RequestSenseBuffer) - AdaptecSenseBufferFree(AdaptecRequests, (ScsiStatus != SCSI_STATUS_OK)); - - uint8_t Status = ScsiStatus; - uint32_t CCBPointer = AdaptecRequests->CCBPointer; - CCBU CmdBlock; - memcpy(&CmdBlock, &AdaptecRequests->CmdBlock, sizeof(CCBU)); - - if (Status == SCSI_STATUS_OK) - { - //A Good status must return good results. - AdaptecMailboxIn(Adaptec, CCBPointer, &CmdBlock, CCB_COMPLETE, SCSI_STATUS_OK, - MBI_SUCCESS); - } - else if (ScsiStatus == SCSI_STATUS_CHECK_CONDITION) - { - AdaptecMailboxIn(Adaptec, CCBPointer, &CmdBlock, CCB_COMPLETE, SCSI_STATUS_CHECK_CONDITION, - MBI_ERROR); - } -} - -static void AdaptecSCSIRequestSetup(Adaptec_t *Adaptec, uint32_t CCBPointer) -{ - AdaptecRequests_t *AdaptecRequests = &Adaptec->AdaptecRequests; - CCBU CmdBlock; - - //Fetch data from the Command Control Block. - DMAPageRead(CCBPointer, &CmdBlock, sizeof(CCB32)); - - uint8_t Id = Adaptec->Mbx24bit ? CmdBlock.old.Id : CmdBlock.new.Id; - uint8_t Lun = Adaptec->Mbx24bit ? CmdBlock.old.Lun : CmdBlock.new.Lun; - - pclog("Scanning SCSI Target ID %d\n", Id); - - if (Id < ELEMENTS(ScsiDrives)) - { - if (Id == scsi_cdrom_id && Lun == 0) - { - int retcode; - - pclog("SCSI Target ID %d detected and working\n", Id); - - SCSI *Scsi = &ScsiDrives[Id]; - - AdaptecRequests->CCBPointer = CCBPointer; - AdaptecRequests->Is24bit = Adaptec->Mbx24bit; - - memcpy(&AdaptecRequests->CmdBlock, &CmdBlock, sizeof(CmdBlock)); - - uint8_t SenseLength = AdaptecConvertSenseLength(CmdBlock.common.RequestSenseLength); - - AdaptecSenseBufferAllocate(AdaptecRequests); - - uint32_t BufferSize = 0; - AdaptecQueryDataBufferSize(Adaptec, &AdaptecRequests->CmdBlock, AdaptecRequests->Is24bit, &BufferSize); - - if (CmdBlock.common.ControlByte == CCB_DATA_XFER_IN) - { - SCSIReadTransfer(Scsi, Id); - } - else if (CmdBlock.common.ControlByte == CCB_DATA_XFER_OUT) - { - SCSIWriteTransfer(Scsi, Id); - } - - SCSISendCommand(Scsi, Id, AdaptecRequests->CmdBlock.common.Cdb, AdaptecRequests->CmdBlock.common.CdbLength, BufferSize, AdaptecRequests->RequestSenseBuffer, SenseLength); - - AdaptecSCSIRequestComplete(Adaptec, AdaptecRequests); - - pclog("Status %02X, Sense Key %02X, Asc %02X, Ascq %02X\n", ScsiStatus, SCSISense.SenseKey, SCSISense.Asc, SCSISense.Ascq); - pclog("Transfer Control %02X\n", CmdBlock.common.ControlByte); - } - else - { - AdaptecMailboxIn(Adaptec, CCBPointer, &CmdBlock, CCB_SELECTION_TIMEOUT, SCSI_STATUS_OK, - MBI_ERROR); - } - } - else - { - AdaptecMailboxIn(Adaptec, CCBPointer, &CmdBlock, CCB_INVALID_CCB, SCSI_STATUS_OK, - MBI_ERROR); - } -} - -static uint32_t AdaptecMailboxOut(Adaptec_t *Adaptec, Mailbox32_t *Mailbox32) -{ - Mailbox_t MailboxOut; - uint32_t Outgoing; - - if (Adaptec->Mbx24bit) - { - Outgoing = Adaptec->MailboxOutAddr + (Adaptec->MailboxOutPosCur * sizeof(Mailbox_t)); - - DMAPageRead(Outgoing, &MailboxOut, sizeof(Mailbox_t)); - - Mailbox32->CCBPointer = ADDR_TO_U32(MailboxOut.CCBPointer); - Mailbox32->u.out.ActionCode = MailboxOut.CmdStatus; - } - else - { - Outgoing = Adaptec->MailboxOutAddr + (Adaptec->MailboxOutPosCur * sizeof(Mailbox32_t)); - - DMAPageRead(Outgoing, Mailbox32, sizeof(Mailbox32_t)); - } - - return Outgoing; -} - -static void AdaptecStartMailbox(Adaptec_t *Adaptec) -{ - Mailbox32_t Mailbox32; - Mailbox_t MailboxOut; - uint32_t Outgoing; - - uint8_t MailboxOutCur = Adaptec->MailboxOutPosCur; - - do - { - Outgoing = AdaptecMailboxOut(Adaptec, &Mailbox32); - Adaptec->MailboxOutPosCur = (Adaptec->MailboxOutPosCur + 1) % Adaptec->MailboxCount; - } while (Mailbox32.u.out.ActionCode == MBO_FREE && MailboxOutCur != Adaptec->MailboxOutPosCur); - - Adaptec->MailboxOutPosCur = MailboxOutCur; - - uint8_t CmdStatus = MBO_FREE; - uint32_t CodeOffset = Adaptec->Mbx24bit ? offsetof(Mailbox_t, CmdStatus) : offsetof(Mailbox32_t, u.out.ActionCode); - - DMAPageWrite(Outgoing + CodeOffset, &CmdStatus, sizeof(CmdStatus)); - - if (Mailbox32.u.out.ActionCode == MBO_START) - { - Adaptec->MailboxOutPosCur = 1; //Make sure that at least one outgoing mailbox is loaded. - pclog("Start Mailbox Command\n"); - AdaptecSCSIRequestSetup(Adaptec, Mailbox32.CCBPointer); - } -} - -void AdaptecCallback(void *p) -{ - Adaptec_t *Adaptec = &AdaptecLUN[scsi_cdrom_id]; - - ScsiCallback[scsi_cdrom_id] = 0; - - AdaptecStartMailbox(Adaptec); -} - -void AdaptecInit() -{ - Adaptec_t *Adaptec = &AdaptecLUN[scsi_cdrom_id]; - - Adaptec->Irq = scsi_irq; - Adaptec->DmaChannel = scsi_dma; - - pfnIoRequestCopyFromBuffer = AdaptecIoRequestCopyFromBuffer; - pfnIoRequestCopyToBuffer = AdaptecIoRequestCopyToBuffer; - - io_sethandler(scsi_base, 0x0004, AdaptecRead, NULL, NULL, AdaptecWrite, NULL, NULL, NULL); - timer_add(AdaptecCallback, &ScsiCallback[scsi_cdrom_id], &ScsiCallback[scsi_cdrom_id], NULL); - pclog("Adaptec on port 0x%04X\n", scsi_base); - - AdaptecReset(Adaptec); - Adaptec->Status |= STAT_STST; - Adaptec->Status &= ~STAT_IDLE; -} diff --git a/src/aha154x.h b/src/aha154x.h deleted file mode 100644 index 801bd6441..000000000 --- a/src/aha154x.h +++ /dev/null @@ -1 +0,0 @@ -extern void AdaptecInit(); \ No newline at end of file diff --git a/src/buslogic.c b/src/buslogic.c new file mode 100644 index 000000000..5d7231c7f --- /dev/null +++ b/src/buslogic.c @@ -0,0 +1,1573 @@ +/* Copyright holders: SA1988 + see COPYING for more details +*/ +/*Buslogic SCSI emulation (including Adaptec 154x ISA software backward compatibility)*/ + +/* ToDo: */ +/* Improve DOS support */ + +#include +#include +#include +#include + +#include "ibm.h" +#include "device.h" +#include "io.h" +#include "mem.h" +#include "rom.h" +#include "dma.h" +#include "pic.h" +#include "timer.h" + +#include "scsi.h" +#include "cdrom.h" + +#include "buslogic.h" + +typedef struct +{ + uint8_t hi; + uint8_t mid; + uint8_t lo; +} addr24; + +#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) + +// I/O Port interface +// READ Port x+0: STATUS +// WRITE Port x+0: CONTROL +// +// READ Port x+1: DATA +// WRITE Port x+1: COMMAND +// +// READ Port x+2: INTERRUPT STATUS +// WRITE Port x+2: (undefined?) +// +// R/W Port x+3: (undefined) + +// READ STATUS flags +#define STAT_STST 0x80 // self-test in progress +#define STAT_DFAIL 0x40 // internal diagnostic failure +#define STAT_INIT 0x20 // mailbox initialization required +#define STAT_IDLE 0x10 // HBA is idle +#define STAT_CDFULL 0x08 // Command/Data output port is full +#define STAT_DFULL 0x04 // Data input port is full +#define STAT_INVCMD 0x01 // Invalid command + +// READ INTERRUPT STATUS flags +#define INTR_ANY 0x80 // any interrupt +#define INTR_SRCD 0x08 // SCSI reset detected +#define INTR_HACC 0x04 // HA command complete +#define INTR_MBOA 0x02 // MBO empty +#define INTR_MBIF 0x01 // MBI full + +// WRITE CONTROL commands +#define CTRL_HRST 0x80 // Hard reset +#define CTRL_SRST 0x40 // Soft reset +#define CTRL_IRST 0x20 // interrupt reset +#define CTRL_SCRST 0x10 // SCSI bus reset + +// READ/WRITE DATA commands +#define CMD_NOP 0x00 // No operation +#define CMD_MBINIT 0x01 // mailbox initialization +#define CMD_START_SCSI 0x02 // Start SCSI command +#define CMD_INQUIRY 0x04 // Adapter inquiry +#define CMD_EMBOI 0x05 // enable Mailbox Out Interrupt +#define CMD_SELTIMEOUT 0x06 // Set SEL timeout +#define CMD_BUSON_TIME 0x07 // set bus-On time +#define CMD_BUSOFF_TIME 0x08 // set bus-off time +#define CMD_DMASPEED 0x09 // set ISA DMA speed +#define CMD_RETDEVS 0x0A // return installed devices +#define CMD_RETCONF 0x0B // return configuration data +#define CMD_TARGET 0x0C // set HBA to target mode +#define CMD_RETSETUP 0x0D // return setup data +#define CMD_ECHO 0x1F // ECHO command data + +#pragma pack(1) +/** + * Auto SCSI structure which is located + * in host adapter RAM and contains several + * configuration parameters. + */ +typedef struct AutoSCSIRam +{ + uint8_t aInternalSignature[2]; + uint8_t cbInformation; + uint8_t aHostAdaptertype[6]; + uint8_t uReserved1; + uint8_t fFloppyEnabled : 1; + uint8_t fFloppySecondary : 1; + uint8_t fLevelSensitiveInterrupt : 1; + unsigned char uReserved2 : 2; + unsigned char uSystemRAMAreForBIOS : 3; + unsigned char uDMAChannel : 7; + uint8_t fDMAAutoConfiguration : 1; + unsigned char uIrqChannel : 7; + uint8_t fIrqAutoConfiguration : 1; + uint8_t uDMATransferRate; + uint8_t uSCSIId; + uint8_t fLowByteTerminated : 1; + uint8_t fParityCheckingEnabled : 1; + uint8_t fHighByteTerminated : 1; + uint8_t fNoisyCablingEnvironment : 1; + uint8_t fFastSynchronousNeogtiation : 1; + uint8_t fBusResetEnabled : 1; + uint8_t fReserved3 : 1; + uint8_t fActiveNegotiationEnabled : 1; + uint8_t uBusOnDelay; + uint8_t uBusOffDelay; + uint8_t fHostAdapterBIOSEnabled : 1; + uint8_t fBIOSRedirectionOfInt19 : 1; + uint8_t fExtendedTranslation : 1; + uint8_t fMapRemovableAsFixed : 1; + uint8_t fReserved4 : 1; + uint8_t fBIOSSupportsMoreThan2Drives : 1; + uint8_t fBIOSInterruptMode : 1; + uint8_t fFlopticalSupport : 1; + uint16_t u16DeviceEnabledMask; + uint16_t u16WidePermittedMask; + uint16_t u16FastPermittedMask; + uint16_t u16SynchronousPermittedMask; + uint16_t u16DisconnectPermittedMask; + uint16_t u16SendStartUnitCommandMask; + uint16_t u16IgnoreInBIOSScanMask; + unsigned char uPCIInterruptPin : 2; + unsigned char uHostAdapterIoPortAddress : 2; + uint8_t fStrictRoundRobinMode : 1; + uint8_t fVesaBusSpeedGreaterThan33MHz : 1; + uint8_t fVesaBurstWrite : 1; + uint8_t fVesaBurstRead : 1; + uint16_t u16UltraPermittedMask; + uint32_t uReserved5; + uint8_t uReserved6; + uint8_t uAutoSCSIMaximumLUN; + uint8_t fReserved7 : 1; + uint8_t fSCAMDominant : 1; + uint8_t fSCAMenabled : 1; + uint8_t fSCAMLevel2 : 1; + unsigned char uReserved8 : 4; + uint8_t fInt13Extension : 1; + uint8_t fReserved9 : 1; + uint8_t fCDROMBoot : 1; + unsigned char uReserved10 : 5; + unsigned char uBootTargetId : 4; + unsigned char uBootChannel : 4; + uint8_t fForceBusDeviceScanningOrder : 1; + unsigned char uReserved11 : 7; + uint16_t u16NonTaggedToAlternateLunPermittedMask; + uint16_t u16RenegotiateSyncAfterCheckConditionMask; + uint8_t aReserved12[10]; + uint8_t aManufacturingDiagnostic[2]; + uint16_t u16Checksum; +} AutoSCSIRam; +#pragma pack() + +/** + * The local Ram. + */ +typedef union HostAdapterLocalRam +{ + /** Byte view. */ + uint8_t u8View[256]; + /** Structured view. */ + struct + { + /** Offset 0 - 63 is for BIOS. */ + uint8_t u8Bios[64]; + /** Auto SCSI structure. */ + AutoSCSIRam autoSCSIData; + } structured; +} HostAdapterLocalRam; + +/** Structure for the INQUIRE_SETUP_INFORMATION reply. */ +typedef struct ReplyInquireSetupInformationSynchronousValue +{ + uint8_t uOffset : 4; + uint8_t uTransferPeriod : 3; + uint8_t fSynchronous : 1; +}ReplyInquireSetupInformationSynchronousValue; + +typedef struct ReplyInquireSetupInformation +{ + uint8_t fSynchronousInitiationEnabled : 1; + uint8_t fParityCheckingEnabled : 1; + uint8_t uReserved1 : 6; + uint8_t uBusTransferRate; + uint8_t uPreemptTimeOnBus; + uint8_t uTimeOffBus; + uint8_t cMailbox; + addr24 MailboxAddress; + ReplyInquireSetupInformationSynchronousValue SynchronousValuesId0To7[8]; + uint8_t uDisconnectPermittedId0To7; + uint8_t uSignature; + uint8_t uCharacterD; + uint8_t uHostBusType; + uint8_t uWideTransferPermittedId0To7; + uint8_t uWideTransfersActiveId0To7; + ReplyInquireSetupInformationSynchronousValue SynchronousValuesId8To15[8]; + uint8_t uDisconnectPermittedId8To15; + uint8_t uReserved2; + uint8_t uWideTransferPermittedId8To15; + uint8_t uWideTransfersActiveId8To15; +} ReplyInquireSetupInformation; + +/** Structure for the INQUIRE_EXTENDED_SETUP_INFORMATION. */ +#pragma pack(1) +typedef struct ReplyInquireExtendedSetupInformation +{ + uint8_t uBusType; + uint8_t uBiosAddress; + uint16_t u16ScatterGatherLimit; + uint8_t cMailbox; + uint32_t uMailboxAddressBase; + uint8_t uReserved1 : 2; + uint8_t fFastEISA : 1; + uint8_t uReserved2 : 3; + uint8_t fLevelSensitiveInterrupt : 1; + uint8_t uReserved3 : 1; + uint8_t aFirmwareRevision[3]; + uint8_t fHostWideSCSI : 1; + uint8_t fHostDifferentialSCSI : 1; + uint8_t fHostSupportsSCAM : 1; + uint8_t fHostUltraSCSI : 1; + uint8_t fHostSmartTermination : 1; + uint8_t uReserved4 : 3; +} ReplyInquireExtendedSetupInformation; +#pragma pack() + +typedef struct MailboxInit_t +{ + uint8_t Count; + addr24 Address; +} MailboxInit_t; + +#pragma pack(1) +typedef struct MailboxInitExtended_t +{ + uint8_t Count; + uint32_t Address; +} MailboxInitExtended_t; +#pragma pack() + +/////////////////////////////////////////////////////////////////////////////// +// +// Mailbox Definitions +// +// +/////////////////////////////////////////////////////////////////////////////// + +// +// Mailbox Out +// +// +// MBO Command Values +// + +#define MBO_FREE 0x00 +#define MBO_START 0x01 +#define MBO_ABORT 0x02 + +// +// Mailbox In +// +// +// MBI Status Values +// + +#define MBI_FREE 0x00 +#define MBI_SUCCESS 0x01 +#define MBI_ABORT 0x02 +#define MBI_NOT_FOUND 0x03 +#define MBI_ERROR 0x04 + +typedef struct Mailbox_t +{ + uint8_t CmdStatus; + addr24 CCBPointer; +} Mailbox_t; + +typedef struct Mailbox32_t +{ + uint32_t CCBPointer; + union + { + struct + { + uint8_t Reserved[3]; + uint8_t ActionCode; + } out; + struct + { + uint8_t HostStatus; + uint8_t TargetStatus; + uint8_t Reserved; + uint8_t CompletionCode; + } in; + } u; +} Mailbox32_t; + + +/////////////////////////////////////////////////////////////////////////////// +// +// CCB - Buslogic SCSI Command Control Block +// +// The CCB is a superset of the CDB (Command Descriptor Block) +// and specifies detailed information about a SCSI command. +// +/////////////////////////////////////////////////////////////////////////////// + +// +// Byte 0 Command Control Block Operation Code +// + +#define SCSI_INITIATOR_COMMAND 0x00 +#define TARGET_MODE_COMMAND 0x01 +#define SCATTER_GATHER_COMMAND 0x02 +#define SCSI_INITIATOR_COMMAND_RES 0x03 +#define SCATTER_GATHER_COMMAND_RES 0x04 +#define BUS_RESET 0x81 + +// +// Byte 1 Address and Direction Control +// + +#define CCB_TARGET_ID_SHIFT 0x06 // CCB Op Code = 00, 02 +#define CCB_INITIATOR_ID_SHIFT 0x06 // CCB Op Code = 01 +#define CCB_DATA_XFER_IN 0x01 +#define CCB_DATA_XFER_OUT 0x02 +#define CCB_LUN_MASK 0x07 // Logical Unit Number + +// +// Byte 2 SCSI_Command_Length - Length of SCSI CDB +// +// Byte 3 Request Sense Allocation Length +// + +#define FOURTEEN_BYTES 0x00 // Request Sense Buffer size +#define NO_AUTO_REQUEST_SENSE 0x01 // No Request Sense Buffer + +// +// Bytes 4, 5 and 6 Data Length // Data transfer byte count +// +// Bytes 7, 8 and 9 Data Pointer // SGD List or Data Buffer +// +// Bytes 10, 11 and 12 Link Pointer // Next CCB in Linked List +// +// Byte 13 Command Link ID // TBD (I don't know yet) +// +// Byte 14 Host Status // Host Adapter status +// + +#define CCB_COMPLETE 0x00 // CCB completed without error +#define CCB_LINKED_COMPLETE 0x0A // Linked command completed +#define CCB_LINKED_COMPLETE_INT 0x0B // Linked complete with interrupt +#define CCB_SELECTION_TIMEOUT 0x11 // Set SCSI selection timed out +#define CCB_DATA_OVER_UNDER_RUN 0x12 +#define CCB_UNEXPECTED_BUS_FREE 0x13 // Target dropped SCSI BSY +#define CCB_PHASE_SEQUENCE_FAIL 0x14 // Target bus phase sequence failure +#define CCB_BAD_MBO_COMMAND 0x15 // MBO command not 0, 1 or 2 +#define CCB_INVALID_OP_CODE 0x16 // CCB invalid operation code +#define CCB_BAD_LINKED_LUN 0x17 // Linked CCB LUN different from first +#define CCB_INVALID_DIRECTION 0x18 // Invalid target direction +#define CCB_DUPLICATE_CCB 0x19 // Duplicate CCB +#define CCB_INVALID_CCB 0x1A // Invalid CCB - bad parameter + +// +// Byte 15 Target Status +// +// See scsi.h files for these statuses. +// + +// +// Bytes 16 and 17 Reserved (must be 0) +// + +// +// Bytes 18 through 18+n-1, where n=size of CDB Command Descriptor Block +// + +typedef struct CCB32 +{ + uint8_t Opcode; + uint8_t Reserved1:3; + uint8_t ControlByte:2; + uint8_t TagQueued:1; + uint8_t QueueTag:2; + uint8_t CdbLength; + uint8_t RequestSenseLength; + uint32_t DataLength; + uint32_t DataPointer; + uint8_t Reserved2[2]; + uint8_t HostStatus; + uint8_t TargetStatus; + uint8_t Id; + uint8_t Lun:5; + uint8_t LegacyTagEnable:1; + uint8_t LegacyQueueTag:2; + uint8_t Cdb[12]; + uint8_t Reserved3[6]; + uint32_t SensePointer; +} CCB32; + +typedef struct CCB +{ + uint8_t Opcode; + uint8_t Lun:3; + uint8_t ControlByte:2; + uint8_t Id:3; + uint8_t CdbLength; + uint8_t RequestSenseLength; + addr24 DataLength; + addr24 DataPointer; + addr24 LinkPointer; + uint8_t LinkId; + uint8_t HostStatus; + uint8_t TargetStatus; + uint8_t Reserved[2]; + uint8_t Cdb[12]; +} CCB; + +typedef struct CCBC +{ + uint8_t Opcode; + uint8_t Pad1:3; + uint8_t ControlByte:2; + uint8_t Pad2:3; + uint8_t CdbLength; + uint8_t RequestSenseLength; + uint8_t Pad3[10]; + uint8_t HostStatus; + uint8_t TargetStatus; + uint8_t Pad4[2]; + uint8_t Cdb[12]; +} CCBC; + +typedef union CCBU +{ + CCB32 new; + CCB old; + CCBC common; +} CCBU; + +/////////////////////////////////////////////////////////////////////////////// +// +// Scatter/Gather Segment List Definitions +// +/////////////////////////////////////////////////////////////////////////////// + +// +// Adapter limits +// + +#define MAX_SG_DESCRIPTORS 32 + +typedef struct SGE32 +{ + uint32_t Segment; + uint32_t SegmentPointer; +} SGE32; + +typedef struct SGE +{ + addr24 Segment; + addr24 SegmentPointer; +} SGE; + +typedef struct BuslogicRequests_t +{ + CCBU CmdBlock; + uint8_t *RequestSenseBuffer; + uint32_t CCBPointer; + int Is24bit; + uint8_t TargetID; + uint8_t LUN; +} BuslogicRequests_t; + +typedef struct Buslogic_t +{ + rom_t bios; + int UseLocalRam; + int StrictRoundRobinMode; + int ExtendedLUNCCBFormat; + HostAdapterLocalRam LocalRam; + BuslogicRequests_t BuslogicRequests; + uint8_t Status; + uint8_t Interrupt; + uint8_t Geometry; + uint8_t Control; + uint8_t Command; + uint8_t CmdBuf[53]; + uint8_t CmdParam; + uint8_t CmdParamLeft; + uint8_t DataBuf[64]; + uint8_t DataReply; + uint8_t DataReplyLeft; + uint32_t MailboxCount; + uint32_t MailboxOutAddr; + uint32_t MailboxOutPosCur; + uint32_t MailboxInAddr; + uint32_t MailboxInPosCur; + int Irq; + int DmaChannel; + int IrqEnabled; + int Mbx24bit; + int CommandCallback; +} Buslogic_t; + +int scsi_base = 0x330; +int scsi_dma = 6; +int scsi_irq = 11; + +int aha154x_do_log = 0; + +void BuslogicLog(const char *format, ...) +{ + if (aha154x_do_log) + { + va_list ap; + va_start(ap, format); + vprintf(format, ap); + va_end(ap); + fflush(stdout); + } +} + +static void BuslogicClearInterrupt(Buslogic_t *Buslogic) +{ + BuslogicLog("Buslogic: Clearing Interrupt 0x%02X\n", Buslogic->Interrupt); + Buslogic->Interrupt = 0; + picintc(1 << Buslogic->Irq); +} + +static void BuslogicLocalRam(Buslogic_t *Buslogic) +{ + /* + * 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(Buslogic->LocalRam.u8View, 0, sizeof(HostAdapterLocalRam)); + Buslogic->LocalRam.structured.autoSCSIData.fLevelSensitiveInterrupt = 1; + Buslogic->LocalRam.structured.autoSCSIData.fParityCheckingEnabled = 1; + Buslogic->LocalRam.structured.autoSCSIData.fExtendedTranslation = 1; /* Same as in geometry register. */ + Buslogic->LocalRam.structured.autoSCSIData.u16DeviceEnabledMask = UINT16_MAX; /* All enabled. Maybe mask out non present devices? */ + Buslogic->LocalRam.structured.autoSCSIData.u16WidePermittedMask = UINT16_MAX; + Buslogic->LocalRam.structured.autoSCSIData.u16FastPermittedMask = UINT16_MAX; + Buslogic->LocalRam.structured.autoSCSIData.u16SynchronousPermittedMask = UINT16_MAX; + Buslogic->LocalRam.structured.autoSCSIData.u16DisconnectPermittedMask = UINT16_MAX; + Buslogic->LocalRam.structured.autoSCSIData.fStrictRoundRobinMode = Buslogic->StrictRoundRobinMode; + Buslogic->LocalRam.structured.autoSCSIData.u16UltraPermittedMask = UINT16_MAX; + /** @todo calculate checksum? */ +} + +static void BuslogicReset(Buslogic_t *Buslogic) +{ + Buslogic->Status = STAT_IDLE | STAT_INIT; + Buslogic->Geometry = 0x80; + Buslogic->Command = 0xFF; + Buslogic->CmdParam = 0; + Buslogic->CmdParamLeft = 0; + Buslogic->IrqEnabled = 1; + Buslogic->StrictRoundRobinMode = 0; + Buslogic->ExtendedLUNCCBFormat = 0; + Buslogic->MailboxOutPosCur = 0; + Buslogic->MailboxInPosCur = 0; + + BuslogicClearInterrupt(Buslogic); + + BuslogicLocalRam(Buslogic); +} + +static void BuslogicResetControl(Buslogic_t *Buslogic, uint8_t Reset) +{ + BuslogicReset(Buslogic); + if (Reset & CTRL_HRST) + { + Buslogic->Status = STAT_STST; + Buslogic->Status &= ~STAT_IDLE; + } +} + +static void BuslogicCommandComplete(Buslogic_t *Buslogic) +{ + Buslogic->Status |= STAT_IDLE; + Buslogic->DataReply = 0; + + if (Buslogic->Command != CMD_START_SCSI) + { + Buslogic->Status &= ~STAT_DFULL; + Buslogic->Interrupt = INTR_ANY | INTR_HACC; + picint(1 << Buslogic->Irq); + } + + Buslogic->Command = 0xFF; + Buslogic->CmdParam = 0; +} + +static void BuslogicMailboxIn(Buslogic_t *Buslogic, uint32_t CCBPointer, CCBU *CmdBlock, + uint8_t HostStatus, uint8_t TargetStatus, uint8_t MailboxCompletionCode) +{ + Mailbox32_t Mailbox32; + Mailbox_t MailboxIn; + + Mailbox32.CCBPointer = CCBPointer; + Mailbox32.u.in.HostStatus = HostStatus; + Mailbox32.u.in.TargetStatus = TargetStatus; + Mailbox32.u.in.CompletionCode = MailboxCompletionCode; + + uint32_t Incoming = Buslogic->MailboxInAddr + (Buslogic->MailboxInPosCur * (Buslogic->Mbx24bit ? sizeof(Mailbox_t) : sizeof(Mailbox32_t))); + + if (MailboxCompletionCode != MBI_NOT_FOUND) + { + CmdBlock->common.HostStatus = HostStatus; + CmdBlock->common.TargetStatus = TargetStatus; + + //Rewrite the CCB up to the CDB. + DMAPageWrite(CCBPointer, CmdBlock, offsetof(CCBC, Cdb)); + } + + pclog("Host Status 0x%02X, Target Status 0x%02X\n", HostStatus, TargetStatus); + + if (Buslogic->Mbx24bit) + { + MailboxIn.CmdStatus = Mailbox32.u.in.CompletionCode; + U32_TO_ADDR(MailboxIn.CCBPointer, Mailbox32.CCBPointer); + pclog("Mailbox 24-bit: Status=0x%02X, CCB at 0x%08X\n", MailboxIn.CmdStatus, ADDR_TO_U32(MailboxIn.CCBPointer)); + + DMAPageWrite(Incoming, &MailboxIn, sizeof(Mailbox_t)); + } + else + { + pclog("Mailbox 32-bit: Status=0x%02X, CCB at 0x%08X\n", Mailbox32.u.in.CompletionCode, Mailbox32.CCBPointer); + + DMAPageWrite(Incoming, &Mailbox32, sizeof(Mailbox32_t)); + } + + Buslogic->MailboxInPosCur++; + if (Buslogic->MailboxInPosCur > Buslogic->MailboxCount) + Buslogic->MailboxInPosCur = 0; + + Buslogic->Interrupt = INTR_MBIF | INTR_ANY; + picint(1 << Buslogic->Irq); +} + +static void BuslogicReadSGEntries(int Is24bit, uint32_t SGList, uint32_t Entries, SGE32 *SG) +{ + if (Is24bit) + { + uint32_t i; + SGE SGE24[MAX_SG_DESCRIPTORS]; + + DMAPageRead(SGList, &SGE24, Entries * sizeof(SGE)); + + for (i=0;iTargetID; + + if (Is24bit) + { + DataPointer = ADDR_TO_U32(CmdBlock->old.DataPointer); + DataLength = ADDR_TO_U32(CmdBlock->old.DataLength); + } + else + { + DataPointer = CmdBlock->new.DataPointer; + DataLength = CmdBlock->new.DataLength; + } + + if (CmdBlock->common.Cdb[0] == GPCMD_TEST_UNIT_READY) + DataLength = 0; + + pclog("Data Buffer write: length %d, pointer %d\n", DataLength, DataPointer); + + if (DataLength && CmdBlock->common.ControlByte != 0x03) + { + if (CmdBlock->common.Opcode == SCATTER_GATHER_COMMAND || + CmdBlock->common.Opcode == SCATTER_GATHER_COMMAND_RES) + { + uint32_t ScatterGatherRead; + uint32_t ScatterEntry; + SGE32 ScatterGatherBuffer[MAX_SG_DESCRIPTORS]; + uint32_t ScatterGatherLeft = DataLength / (Is24bit ? sizeof(SGE) : sizeof(SGE32)); + uint32_t ScatterGatherAddrCurrent = DataPointer; + uint32_t DataToTransfer = 0; + + do + { + ScatterGatherRead = (ScatterGatherLeft < ELEMENTS(ScatterGatherBuffer)) + ? ScatterGatherLeft : ELEMENTS(ScatterGatherBuffer); + + ScatterGatherLeft -= ScatterGatherRead; + + BuslogicReadSGEntries(Is24bit, ScatterGatherAddrCurrent, ScatterGatherRead, ScatterGatherBuffer); + + for (ScatterEntry = 0; ScatterEntry < ScatterGatherRead; ScatterEntry++) + { + uint32_t Address; + + Address = ScatterGatherBuffer[ScatterEntry].SegmentPointer; + DataToTransfer += ScatterGatherBuffer[ScatterEntry].Segment; + } + + ScatterGatherAddrCurrent += ScatterGatherRead * (Is24bit ? sizeof(SGE) : sizeof(SGE32)); + } while (ScatterGatherLeft > 0); + + SCSIDevices[Id].buffer_size = DataToTransfer; + + //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 no length/read/write commands. + if (CmdBlock->common.ControlByte == CCB_DATA_XFER_OUT || CmdBlock->common.ControlByte == 0x00) + { + ScatterGatherLeft = DataLength / (Is24bit ? sizeof(SGE) : sizeof(SGE32)); + ScatterGatherAddrCurrent = DataPointer; + + do + { + ScatterGatherRead = (ScatterGatherLeft < ELEMENTS(ScatterGatherBuffer)) + ? ScatterGatherLeft : ELEMENTS(ScatterGatherBuffer); + + ScatterGatherLeft -= ScatterGatherRead; + + BuslogicReadSGEntries(Is24bit, ScatterGatherAddrCurrent, ScatterGatherRead, ScatterGatherBuffer); + + for (ScatterEntry = 0; ScatterEntry < ScatterGatherRead; ScatterEntry++) + { + uint32_t Address; + + Address = ScatterGatherBuffer[ScatterEntry].SegmentPointer; + DataToTransfer = ScatterGatherBuffer[ScatterEntry].Segment; + + DMAPageRead(Address, SCSIDevices[Id].CmdBuffer, DataToTransfer); + } + + ScatterGatherAddrCurrent += ScatterGatherRead * (Is24bit ? sizeof(SGE) : sizeof(SGE32)); + } while (ScatterGatherLeft > 0); + } + } + else if (CmdBlock->common.Opcode == SCSI_INITIATOR_COMMAND || + CmdBlock->common.Opcode == SCSI_INITIATOR_COMMAND_RES) + { + uint32_t Address = DataPointer; + SCSIDevices[Id].InitLength = DataLength; + + DMAPageRead(Address, SCSIDevices[Id].CmdBuffer, SCSIDevices[Id].InitLength); + } + } +} + +void BuslogicDataBufferFree(BuslogicRequests_t *BuslogicRequests) +{ + uint8_t Id = BuslogicRequests->TargetID; + uint32_t Count; + + if (BuslogicRequests->Is24bit) + { + DataPointer = ADDR_TO_U32(BuslogicRequests->CmdBlock.old.DataPointer); + DataLength = ADDR_TO_U32(BuslogicRequests->CmdBlock.old.DataLength); + } + else + { + DataPointer = BuslogicRequests->CmdBlock.new.DataPointer; + DataLength = BuslogicRequests->CmdBlock.new.DataLength; + } + + if (BuslogicRequests->CmdBlock.common.Cdb[0] == GPCMD_TEST_UNIT_READY) + DataLength = 0; + + pclog("Data Buffer read: length %d, pointer %d\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 no length/read/write commands. + if (DataLength > 0 && (BuslogicRequests->CmdBlock.common.ControlByte == CCB_DATA_XFER_IN || + BuslogicRequests->CmdBlock.common.ControlByte == 0x00)) + { + if (BuslogicRequests->CmdBlock.common.Opcode == SCATTER_GATHER_COMMAND || + BuslogicRequests->CmdBlock.common.Opcode == SCATTER_GATHER_COMMAND_RES) + { + uint32_t ScatterGatherRead; + uint32_t ScatterEntry; + SGE32 ScatterGatherBuffer[MAX_SG_DESCRIPTORS]; + uint32_t ScatterGatherLeft = DataLength / (BuslogicRequests->Is24bit ? sizeof(SGE) : sizeof(SGE32)); + uint32_t ScatterGatherAddrCurrent = DataPointer; + + do + { + ScatterGatherRead = (ScatterGatherLeft < ELEMENTS(ScatterGatherBuffer)) + ? ScatterGatherLeft : ELEMENTS(ScatterGatherBuffer); + + ScatterGatherLeft -= ScatterGatherRead; + + BuslogicReadSGEntries(BuslogicRequests->Is24bit, ScatterGatherAddrCurrent, ScatterGatherRead, ScatterGatherBuffer); + + for (ScatterEntry = 0; ScatterEntry < ScatterGatherRead; ScatterEntry++) + { + uint32_t Address; + uint32_t DataToTransfer; + + Address = ScatterGatherBuffer[ScatterEntry].SegmentPointer; + DataToTransfer = ScatterGatherBuffer[ScatterEntry].Segment; + + DMAPageWrite(Address, SCSIDevices[Id].CmdBuffer, DataToTransfer); + } + + ScatterGatherAddrCurrent += ScatterGatherRead * (BuslogicRequests->Is24bit ? sizeof(SGE) : sizeof(SGE32)); + } while (ScatterGatherLeft > 0); + } + else if (BuslogicRequests->CmdBlock.common.Opcode == SCSI_INITIATOR_COMMAND || + BuslogicRequests->CmdBlock.common.Opcode == SCSI_INITIATOR_COMMAND_RES) + { + uint32_t Address = DataPointer; + DMAPageWrite(Address, SCSIDevices[Id].CmdBuffer, SCSIDevices[Id].InitLength); + } + } +} + +uint8_t BuslogicRead(uint16_t Port, void *p) +{ + Buslogic_t *Buslogic = (Buslogic_t *)p; + uint8_t Temp; + + switch (Port & 3) + { + case 0: + Temp = Buslogic->Status; + if (Buslogic->Status & STAT_STST) + { + Buslogic->Status &= ~STAT_STST; + Buslogic->Status |= STAT_IDLE; + Temp = Buslogic->Status; + } + break; + + case 1: + if (Buslogic->UseLocalRam) + Temp = Buslogic->LocalRam.u8View[Buslogic->DataReply]; + else + Temp = Buslogic->DataBuf[Buslogic->DataReply]; + if (Buslogic->DataReplyLeft) + { + Buslogic->DataReply++; + Buslogic->DataReplyLeft--; + if (!Buslogic->DataReplyLeft) + { + BuslogicCommandComplete(Buslogic); + } + } + break; + + case 2: + Temp = Buslogic->Interrupt; + break; + + case 3: + Temp = Buslogic->Geometry; + break; + } + + BuslogicLog("Buslogic: Read Port 0x%02X, Returned Value %02X\n", Port, Temp); + return Temp; +} + +void BuslogicWrite(uint16_t Port, uint8_t Val, void *p) +{ + Buslogic_t *Buslogic = (Buslogic_t *)p; + BuslogicRequests_t *BuslogicRequests = &Buslogic->BuslogicRequests; + BuslogicLog("Buslogic: 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); + BuslogicResetControl(Buslogic, Reset); + break; + } + + if (Val & CTRL_IRST) + BuslogicClearInterrupt(Buslogic); + break; + + case 1: + if ((Val == 0x02) && (Buslogic->Command == 0xFF)) + { + SCSICallback[scsi_cdrom_id] = 1; + break; + } + + if (Buslogic->Command == 0xFF) + { + Buslogic->Command = Val; + Buslogic->CmdParam = 0; + + Buslogic->Status &= ~(STAT_INVCMD | STAT_IDLE); + pclog("Buslogic: Operation Code 0x%02X\n", Val); + switch (Buslogic->Command) + { + case 0x00: + case 0x03: + case 0x04: + case 0x0B: + case 0x84: + case 0x85: + case 0x22: + Buslogic->CmdParamLeft = 0; + break; + + case 0x0A: + //case 0x8D: //For Aha-154x + Buslogic->CmdParamLeft = 0; + break; + + case 0x07: + case 0x08: + case 0x09: + case 0x0D: + case 0x1F: + case 0x21: + case 0x8B: //For Buslogic + case 0x8D: //For Buslogic + case 0x24: + case 0x25: + case 0x8F: + case 0x96: //For Buslogic + Buslogic->CmdParamLeft = 1; + break; + + case 0x91: + Buslogic->CmdParamLeft = 2; + break; + + case 0x1C: + case 0x1D: + Buslogic->CmdParamLeft = 3; + break; + + case 0x06: + Buslogic->CmdParamLeft = 4; + break; + + case 0x01: + Buslogic->CmdParamLeft = sizeof(MailboxInit_t); + break; + + case 0x81: + Buslogic->CmdParamLeft = sizeof(MailboxInitExtended_t); + break; + + case 0x28: + Buslogic->CmdParamLeft = 0; + break; + + case 0x29: + Buslogic->CmdParamLeft = 2; + break; + } + } + else + { + Buslogic->CmdBuf[Buslogic->CmdParam] = Val; + Buslogic->CmdParam++; + Buslogic->CmdParamLeft--; + } + + if (!Buslogic->CmdParamLeft) + { + pclog("Running Operation Code 0x%02X\n", Buslogic->Command); + switch (Buslogic->Command) + { + case 0x00: + Buslogic->DataReplyLeft = 0; + break; + + case 0x01: + { + Buslogic->Mbx24bit = 1; + + MailboxInit_t *MailboxInit = (MailboxInit_t *)Buslogic->CmdBuf; + + Buslogic->MailboxCount = MailboxInit->Count; + Buslogic->MailboxOutAddr = ADDR_TO_U32(MailboxInit->Address); + Buslogic->MailboxInAddr = Buslogic->MailboxOutAddr + (Buslogic->MailboxCount * sizeof(Mailbox_t)); + + BuslogicLog("Buslogic Initialize Mailbox Command\n"); + BuslogicLog("Mailbox Out Address=0x%08X\n", Buslogic->MailboxOutAddr); + BuslogicLog("Mailbox In Address=0x%08X\n", Buslogic->MailboxInAddr); + pclog("Initialized Mailbox, %d entries at 0x%08X\n", MailboxInit->Count, ADDR_TO_U32(MailboxInit->Address)); + + Buslogic->Status &= ~STAT_INIT; + Buslogic->DataReplyLeft = 0; + } + break; + + case 0x81: + { + Buslogic->Mbx24bit = 0; + + MailboxInitExtended_t *MailboxInit = (MailboxInitExtended_t *)Buslogic->CmdBuf; + + Buslogic->MailboxCount = MailboxInit->Count; + Buslogic->MailboxOutAddr = MailboxInit->Address; + Buslogic->MailboxInAddr = MailboxInit->Address + (Buslogic->MailboxCount * sizeof(Mailbox32_t)); + + BuslogicLog("Buslogic Extended Initialize Mailbox Command\n"); + BuslogicLog("Mailbox Out Address=0x%08X\n", Buslogic->MailboxOutAddr); + BuslogicLog("Mailbox In Address=0x%08X\n", Buslogic->MailboxInAddr); + pclog("Initialized Extended Mailbox, %d entries at 0x%08X\n", MailboxInit->Count, MailboxInit->Address); + + Buslogic->Status &= ~STAT_INIT; + Buslogic->DataReplyLeft = 0; + } + break; + + case 0x03: + break; + + case 0x04: + Buslogic->DataBuf[0] = 0x41; + Buslogic->DataBuf[1] = 0x41; + Buslogic->DataBuf[2] = '5'; + Buslogic->DataBuf[3] = '0'; + Buslogic->DataReplyLeft = 4; + break; + + case 0x84: + Buslogic->DataBuf[0] = '7'; + Buslogic->DataReplyLeft = 1; + break; + + case 0x85: + Buslogic->DataBuf[0] = 'B'; + Buslogic->DataReplyLeft = 1; + break; + + case 0x06: + Buslogic->DataReplyLeft = 0; + break; + + case 0x07: + Buslogic->DataReplyLeft = 0; + Buslogic->LocalRam.structured.autoSCSIData.uBusOnDelay = Buslogic->CmdBuf[0]; + pclog("Bus-on time: %d\n", Buslogic->CmdBuf[0]); + break; + + case 0x08: + Buslogic->DataReplyLeft = 0; + Buslogic->LocalRam.structured.autoSCSIData.uBusOffDelay = Buslogic->CmdBuf[0]; + pclog("Bus-off time: %d\n", Buslogic->CmdBuf[0]); + break; + + case 0x09: + Buslogic->DataReplyLeft = 0; + Buslogic->LocalRam.structured.autoSCSIData.uDMATransferRate = Buslogic->CmdBuf[0]; + pclog("DMA transfer rate: %02X\n", Buslogic->CmdBuf[0]); + break; + + case 0x0A: + { + int i; + memset(Buslogic->DataBuf, 0, 8); + for (i=0;i<7;++i) + { + if (SCSIDevices[i].LunType == SCSI_CDROM) + Buslogic->DataBuf[i] = 1; + } + + Buslogic->DataBuf[7] = 0; + Buslogic->DataReplyLeft = 8; + } + break; + + case 0x0B: + Buslogic->DataBuf[0] = (1 << Buslogic->DmaChannel); + Buslogic->DataBuf[1] = (1 << (Buslogic->Irq - 9)); + Buslogic->DataBuf[2] = 7; + Buslogic->DataReplyLeft = 3; + break; + + case 0x0D: + { + Buslogic->DataReplyLeft = Buslogic->CmdBuf[0]; + + ReplyInquireSetupInformation *Reply = (ReplyInquireSetupInformation *)Buslogic->DataBuf; + + Reply->fSynchronousInitiationEnabled = 1; + Reply->fParityCheckingEnabled = 1; + Reply->cMailbox = Buslogic->MailboxCount; + U32_TO_ADDR(Reply->MailboxAddress, Buslogic->MailboxOutAddr); +#if 1 + Reply->uSignature = 'B'; + /* The 'D' signature prevents Buslogic's OS/2 drivers from getting too + * friendly with BusLogic hardware and upsetting the HBA state. + */ + Reply->uCharacterD = 'D'; /* BusLogic model. */ + Reply->uHostBusType = 'A'; /* ISA bus. */ +#endif + pclog("Return Setup Information: %d\n", Buslogic->CmdBuf[0]); + } + break; + +#if 1 + case 0x8B: + { + int i; + + /* The reply length is set by the guest and is found in the first byte of the command buffer. */ + Buslogic->DataReplyLeft = Buslogic->CmdBuf[0]; + memset(Buslogic->DataBuf, 0, Buslogic->DataReplyLeft); + const char aModelName[] = "540B "; /* Trailing \0 is fine, that's the filler anyway. */ + int cCharsToTransfer = Buslogic->DataReplyLeft <= sizeof(aModelName) + ? Buslogic->DataReplyLeft + : sizeof(aModelName); + + for (i = 0; i < cCharsToTransfer; i++) + Buslogic->DataBuf[i] = aModelName[i]; + } + break; +#endif + case 0x8D: +#if 1 + { + Buslogic->DataReplyLeft = Buslogic->CmdBuf[0]; + ReplyInquireExtendedSetupInformation *Reply = (ReplyInquireExtendedSetupInformation *)Buslogic->DataBuf; + + Reply->uBusType = 'A'; /* ISA style */ + Reply->u16ScatterGatherLimit = 8192; + Reply->cMailbox = Buslogic->MailboxCount; + Reply->uMailboxAddressBase = Buslogic->MailboxOutAddr; + memcpy(Reply->aFirmwareRevision, "07B", sizeof(Reply->aFirmwareRevision)); + pclog("Return Extended Setup Information: %d\n", Buslogic->CmdBuf[0]); + } +#endif +#if 0 + Buslogic->DataReplyLeft = 0; + Buslogic->Status |= STAT_INVCMD; +#endif + break; + + case 0x1C: + { + uint32_t FIFOBuf; + addr24 Address; + + Buslogic->DataReplyLeft = 0; + Address.hi = Buslogic->CmdBuf[0]; + Address.mid = Buslogic->CmdBuf[1]; + Address.lo = Buslogic->CmdBuf[2]; + FIFOBuf = ADDR_TO_U32(Address); + DMAPageRead(FIFOBuf, &Buslogic->LocalRam.u8View[64], 64); + } + break; + + case 0x1D: + { + uint32_t FIFOBuf; + addr24 Address; + + Buslogic->DataReplyLeft = 0; + Address.hi = Buslogic->CmdBuf[0]; + Address.mid = Buslogic->CmdBuf[1]; + Address.lo = Buslogic->CmdBuf[2]; + FIFOBuf = ADDR_TO_U32(Address); + DMAPageWrite(FIFOBuf, &Buslogic->LocalRam.u8View[64], 64); + } + break; + + case 0x1F: + Buslogic->DataBuf[0] = Buslogic->CmdBuf[0]; + Buslogic->DataReplyLeft = 1; + break; + + case 0x21: + if (Buslogic->CmdParam == 1) + Buslogic->CmdParamLeft = Buslogic->CmdBuf[0]; + + Buslogic->DataReplyLeft = 0; + break; + + case 0x24: + { + uint8_t i; + uint16_t TargetsPresentMask = 0; + + for (i=0;iDataBuf[0] = TargetsPresentMask&0x0F; + Buslogic->DataBuf[1] = TargetsPresentMask>>8; + Buslogic->DataReplyLeft = 2; + } + break; + + case 0x25: + if (Buslogic->CmdBuf[0] == 0) + Buslogic->IrqEnabled = 0; + else + Buslogic->IrqEnabled = 1; + picintc(1 << Buslogic->Irq); + break; + + case 0x8F: + if (Buslogic->CmdBuf[0] == 0) + Buslogic->StrictRoundRobinMode = 0; + else if (Buslogic->CmdBuf[0] == 1) + Buslogic->StrictRoundRobinMode = 1; + + Buslogic->DataReplyLeft = 0; + break; + + case 0x91: + { + uint8_t Offset = Buslogic->CmdBuf[0]; + Buslogic->DataReplyLeft = Buslogic->CmdBuf[1]; + + Buslogic->UseLocalRam = 1; + Buslogic->DataReply = Offset; + } + break; + + case 0x22: + Buslogic->DataReplyLeft = 0; + Buslogic->Status |= STAT_INVCMD; + break; + + case 0x96: + if (Buslogic->CmdBuf[0] == 0) + Buslogic->ExtendedLUNCCBFormat = 0; + else if (Buslogic->CmdBuf[0] == 1) + Buslogic->ExtendedLUNCCBFormat = 1; + + Buslogic->DataReplyLeft = 0; + break; + + case 0x28: + Buslogic->DataReplyLeft = 2; + break; + + case 0x29: + Buslogic->DataReplyLeft = 0; + break; + } + } + + if (Buslogic->DataReplyLeft) + Buslogic->Status |= STAT_DFULL; + else if (!Buslogic->CmdParamLeft) + BuslogicCommandComplete(Buslogic); + break; + + case 2: + Buslogic->Irq = Val; //For Buslogic + break; + + case 3: + Buslogic->Geometry = Val; //For Buslogic + break; + } +} + +static uint8_t BuslogicConvertSenseLength(uint8_t RequestSenseLength) +{ + if (RequestSenseLength == 0) + RequestSenseLength = 14; + else if (RequestSenseLength == 1) + RequestSenseLength = 0; + + return RequestSenseLength; +} + +static void BuslogicSenseBufferAllocate(BuslogicRequests_t *BuslogicRequests) +{ + uint8_t SenseLength = BuslogicConvertSenseLength(BuslogicRequests->CmdBlock.common.RequestSenseLength); + + if (SenseLength) + BuslogicRequests->RequestSenseBuffer = malloc(SenseLength); +} + +static void BuslogicSenseBufferFree(BuslogicRequests_t *BuslogicRequests, int Copy) +{ + uint8_t SenseLength = BuslogicConvertSenseLength(BuslogicRequests->CmdBlock.common.RequestSenseLength); + + if (Copy && SenseLength) + { + uint32_t SenseBufferAddress; + + /*The sense address, in 32-bit mode, is located in the Sense Pointer of the CCB, but in + 24-bit mode, it is located at the end of the Command Descriptor Block. */ + + if (BuslogicRequests->Is24bit) + { + SenseBufferAddress = BuslogicRequests->CCBPointer; + SenseBufferAddress += BuslogicRequests->CmdBlock.common.CdbLength + offsetof(CCB, Cdb); + } + else + SenseBufferAddress = BuslogicRequests->CmdBlock.new.SensePointer; + + DMAPageWrite(SenseBufferAddress, BuslogicRequests->RequestSenseBuffer, SenseLength); + } + //Free the sense buffer when needed. + free(BuslogicRequests->RequestSenseBuffer); +} + +static void BuslogicSCSIRequestComplete(Buslogic_t *Buslogic, BuslogicRequests_t *BuslogicRequests) +{ + uint8_t Status = SCSIStatus; + uint32_t CCBPointer = BuslogicRequests->CCBPointer; + CCBU CmdBlock; + memcpy(&CmdBlock, &BuslogicRequests->CmdBlock, sizeof(CCBU)); + + BuslogicDataBufferFree(BuslogicRequests); + + if (BuslogicRequests->RequestSenseBuffer) + BuslogicSenseBufferFree(BuslogicRequests, (SCSIStatus != SCSI_STATUS_OK)); + + if (Status == SCSI_STATUS_OK) + { + BuslogicMailboxIn(Buslogic, CCBPointer, &CmdBlock, CCB_COMPLETE, SCSI_STATUS_OK, + MBI_SUCCESS); + } + else if (Status == SCSI_STATUS_CHECK_CONDITION) + { + BuslogicMailboxIn(Buslogic, CCBPointer, &CmdBlock, CCB_COMPLETE, SCSI_STATUS_CHECK_CONDITION, + MBI_ERROR); + } +} + +static void BuslogicSCSIRequestSetup(Buslogic_t *Buslogic, uint32_t CCBPointer) +{ + BuslogicRequests_t *BuslogicRequests = &Buslogic->BuslogicRequests; + CCBU CmdBlock; + uint8_t Id, Lun; + + //Fetch data from the Command Control Block. + DMAPageRead(CCBPointer, &CmdBlock, sizeof(CCB32)); + + BuslogicRequests->TargetID = Buslogic->Mbx24bit ? CmdBlock.old.Id : CmdBlock.new.Id; + BuslogicRequests->LUN = Buslogic->Mbx24bit ? CmdBlock.old.Lun : CmdBlock.new.Lun; + + Id = BuslogicRequests->TargetID; + Lun = BuslogicRequests->LUN; + + pclog("Scanning SCSI Target ID %i\n", Id); + + //Only SCSI CD-ROMs are supported at the moment, SCSI hard disk support will come soon. + if (Id < ELEMENTS(SCSIDevices)) + { + if (Id == scsi_cdrom_id && Lun == 0) + { + pclog("SCSI Target ID %i detected and working\n", Id); + + BuslogicRequests->CCBPointer = CCBPointer; + BuslogicRequests->Is24bit = Buslogic->Mbx24bit; + + memcpy(&BuslogicRequests->CmdBlock, &CmdBlock, sizeof(CmdBlock)); + + BuslogicDataBufferAllocate(BuslogicRequests, &BuslogicRequests->CmdBlock, BuslogicRequests->Is24bit); + BuslogicSenseBufferAllocate(BuslogicRequests); + +#if 1 //for finding bugs. + uint32_t i; + + pclog("SCSI Cdb[0]=0x%02X\n", BuslogicRequests->CmdBlock.common.Cdb[0]); + for (i = 1; i < BuslogicRequests->CmdBlock.common.CdbLength; i++) + pclog("SCSI Cdb[%i]=%i\n", i, BuslogicRequests->CmdBlock.common.Cdb[i]); + + pclog("Transfer Control %02X\n", BuslogicRequests->CmdBlock.common.ControlByte); + pclog("CDB Length %i\n", BuslogicRequests->CmdBlock.common.CdbLength); + pclog("CCB Opcode %x\n", BuslogicRequests->CmdBlock.common.Opcode); +#endif + //First, get the data buffer otherwise putting it after the + //exec function results into not getting read/write commands right and + //failing to detect the device. + + if (CmdBlock.common.ControlByte == CCB_DATA_XFER_IN) + { + SCSIRead(Id, SCSIDevices[Id].buffer_size); + } + else if (CmdBlock.common.ControlByte == CCB_DATA_XFER_OUT) + { + SCSIWrite(Id, SCSIDevices[Id].buffer_size); + } + + //Finally, execute the SCSI command immediately and get the transfer length. + SCSIPhase = SCSI_PHASE_COMMAND; + SCSIExecCommand(Id, BuslogicRequests->CmdBlock.common.Cdb); + SCSIGetLength(Id, &SCSIDevices[Id].InitLength); + + if (SCSIPhase == SCSI_PHASE_DATAOUT) + { + SCSIWriteData(Id, BuslogicRequests->CmdBlock.common.Cdb, SCSIDevices[Id].CmdBuffer, SCSIDevices[Id].InitLength); + } + else if (SCSIPhase == SCSI_PHASE_DATAIN) + { + SCSIReadData(Id, BuslogicRequests->CmdBlock.common.Cdb, SCSIDevices[Id].CmdBuffer, SCSIDevices[Id].InitLength); + } + else if (SCSIPhase == SCSI_PHASE_STATUS) + { + //If the executed command doesn't return any length, end the request immediately. + SCSIDevices[Id].buffer_size = 0; + } + + if (BuslogicRequests->CmdBlock.common.Opcode == SCSI_INITIATOR_COMMAND_RES || + BuslogicRequests->CmdBlock.common.Opcode == SCATTER_GATHER_COMMAND_RES) + { + if (BuslogicRequests->Is24bit) + { + U32_TO_ADDR(BuslogicRequests->CmdBlock.old.DataLength, SCSIDevices[Id].InitLength); + pclog("24-bit Residual data length for reading: %d\n", ADDR_TO_U32(BuslogicRequests->CmdBlock.old.DataLength)); + } + else + { + BuslogicRequests->CmdBlock.new.DataLength = SCSIDevices[Id].InitLength; + pclog("32-bit Residual data length for reading: %d\n", BuslogicRequests->CmdBlock.new.DataLength); + } + } + + //If the initialized data length is higher than the requested length, signal complete request. + if (SCSIDevices[Id].InitLength >= SCSIDevices[Id].buffer_size) + BuslogicSCSIRequestComplete(Buslogic, BuslogicRequests); + } + else + { + pclog("No device is present in the SCSI bus\n"); + + BuslogicDataBufferFree(BuslogicRequests); + + if (BuslogicRequests->RequestSenseBuffer) + BuslogicSenseBufferFree(BuslogicRequests, 1); + + BuslogicMailboxIn(Buslogic, CCBPointer, &CmdBlock, CCB_SELECTION_TIMEOUT, SCSI_STATUS_OK, + MBI_ERROR); + } + } + else + { + pclog("ID equal or higher than 7 not supported at the moment\n"); + + BuslogicDataBufferFree(BuslogicRequests); + + if (BuslogicRequests->RequestSenseBuffer) + BuslogicSenseBufferFree(BuslogicRequests, 1); + + BuslogicMailboxIn(Buslogic, CCBPointer, &CmdBlock, CCB_INVALID_CCB, SCSI_STATUS_OK, + MBI_ERROR); + } + +} + +static uint32_t BuslogicMailboxOut(Buslogic_t *Buslogic, Mailbox32_t *Mailbox32) +{ + Mailbox_t MailboxOut; + uint32_t Outgoing; + + if (Buslogic->Mbx24bit) + { + Outgoing = Buslogic->MailboxOutAddr + (Buslogic->MailboxOutPosCur * sizeof(Mailbox_t)); + + DMAPageRead(Outgoing, &MailboxOut, sizeof(Mailbox_t)); + + Mailbox32->CCBPointer = ADDR_TO_U32(MailboxOut.CCBPointer); + Mailbox32->u.out.ActionCode = MailboxOut.CmdStatus; + } + else + { + Outgoing = Buslogic->MailboxOutAddr + (Buslogic->MailboxOutPosCur * sizeof(Mailbox32_t)); + + DMAPageRead(Outgoing, Mailbox32, sizeof(Mailbox32_t)); + } + + return Outgoing; +} + +static void BuslogicStartMailbox(Buslogic_t *Buslogic) +{ + Mailbox32_t Mailbox32; + Mailbox_t MailboxOut; + uint32_t Outgoing; + + uint8_t MailboxOutCur = Buslogic->MailboxOutPosCur; + + do + { + Outgoing = BuslogicMailboxOut(Buslogic, &Mailbox32); + Buslogic->MailboxOutPosCur = (Buslogic->MailboxOutPosCur + 1) % Buslogic->MailboxCount; + } while (Mailbox32.u.out.ActionCode == MBO_FREE && MailboxOutCur != Buslogic->MailboxOutPosCur); + + Buslogic->MailboxOutPosCur = MailboxOutCur; + + uint8_t CmdStatus = MBO_FREE; + uint32_t CodeOffset = Buslogic->Mbx24bit ? offsetof(Mailbox_t, CmdStatus) : offsetof(Mailbox32_t, u.out.ActionCode); + + DMAPageWrite(Outgoing + CodeOffset, &CmdStatus, sizeof(CmdStatus)); + + if (Mailbox32.u.out.ActionCode == MBO_START) + BuslogicSCSIRequestSetup(Buslogic, Mailbox32.CCBPointer); +} + +void BuslogicCommandCallback(void *p) +{ + Buslogic_t *Buslogic = (Buslogic_t *)p; + + SCSICallback[scsi_cdrom_id] = 0; + + if (Buslogic->MailboxCount) + { + BuslogicStartMailbox(Buslogic); + } +} + +void *BuslogicInit() +{ + Buslogic_t *Buslogic = malloc(sizeof(Buslogic_t)); + memset(Buslogic, 0, sizeof(Buslogic_t)); + + Buslogic->Irq = scsi_irq; + Buslogic->DmaChannel = scsi_dma; + + io_sethandler(scsi_base, 0x0004, BuslogicRead, NULL, NULL, BuslogicWrite, NULL, NULL, Buslogic); + + timer_add(BuslogicCommandCallback, &SCSICallback[scsi_cdrom_id], &SCSICallback[scsi_cdrom_id], Buslogic); + + pclog("Buslogic on port 0x%04X\n", scsi_base); + + BuslogicResetControl(Buslogic, CTRL_HRST); + + return Buslogic; +} + +void BuslogicClose(void *p) +{ + Buslogic_t *Buslogic = (Buslogic_t *)p; + free(Buslogic); +} + +device_t BuslogicDevice = +{ + "Buslogic BT-540B", + 0, + BuslogicInit, + BuslogicClose, + NULL,//BuslogicAvailable, + NULL, + NULL, + NULL +}; \ No newline at end of file diff --git a/src/buslogic.h b/src/buslogic.h new file mode 100644 index 000000000..ffb5b4a05 --- /dev/null +++ b/src/buslogic.h @@ -0,0 +1 @@ +extern device_t BuslogicDevice; \ No newline at end of file diff --git a/src/dma.c b/src/dma.c index 870d35d1f..969ffca34 100644 --- a/src/dma.c +++ b/src/dma.c @@ -565,9 +565,9 @@ int dma_channel_write(int channel, uint16_t val) return 0; } -static size_t PageLengthReadWrite(uint32_t PhysAddress, size_t TotalSize) +static uint32_t PageLengthReadWrite(uint32_t PhysAddress, uint32_t TotalSize) { - size_t LengthSize; + uint32_t LengthSize; uint32_t Page; Page = PhysAddress & 4095; @@ -579,20 +579,20 @@ static size_t PageLengthReadWrite(uint32_t PhysAddress, size_t TotalSize) } //DMA Bus Master Page Read/Write -void DMAPageRead(uint32_t PhysAddress, void *DataRead, size_t TotalSize) +void DMAPageRead(uint32_t PhysAddress, void *DataRead, uint32_t TotalSize) { uint32_t PageLen = PageLengthReadWrite(PhysAddress, TotalSize); memcpy(DataRead, &ram[PhysAddress], PageLen); DataRead -= PageLen; - PageLen -= TotalSize; + TotalSize += PageLen; } -void DMAPageWrite(uint32_t PhysAddress, const void *DataWrite, size_t TotalSize) +void DMAPageWrite(uint32_t PhysAddress, const void *DataWrite, uint32_t TotalSize) { uint32_t PageLen = PageLengthReadWrite(PhysAddress, TotalSize); memcpy(&ram[PhysAddress], DataWrite, PageLen); DataWrite -= PageLen; - PageLen -= TotalSize; + TotalSize += PageLen; } int dma_mode(int channel) diff --git a/src/dma.h b/src/dma.h index 14a6ab0ea..e8eb7fbc4 100644 --- a/src/dma.h +++ b/src/dma.h @@ -19,5 +19,5 @@ void writedma2(uint8_t temp); int dma_channel_read(int channel); int dma_channel_write(int channel, uint16_t val); -void DMAPageRead(uint32_t PhysAddress, void *DataRead, size_t TotalSize); -void DMAPageWrite(uint32_t PhysAddress, const void *DataWrite, size_t TotalSize); \ No newline at end of file +void DMAPageRead(uint32_t PhysAddress, void *DataRead, uint32_t TotalSize); +void DMAPageWrite(uint32_t PhysAddress, const void *DataWrite, uint32_t TotalSize); \ No newline at end of file diff --git a/src/ibm.h b/src/ibm.h index e4382fa90..6d4236ff0 100644 --- a/src/ibm.h +++ b/src/ibm.h @@ -345,7 +345,7 @@ int driveempty[4]; #define PCJR (romset == ROM_IBMPCJR) #define AMIBIOS (romset==ROM_AMI386SX || romset==ROM_AMI486 || romset == ROM_WIN486) -int GAMEBLASTER, GUS, SSI2001, voodoo_enabled, aha154x_enabled; +int GAMEBLASTER, GUS, SSI2001, voodoo_enabled, buslogic_enabled; extern int AMSTRAD, AT, is286, is386, PCI, TANDY; enum diff --git a/src/ide.c b/src/ide.c index aa53183d5..307e869d1 100644 --- a/src/ide.c +++ b/src/ide.c @@ -125,7 +125,6 @@ typedef struct IDE int spt,hpc; int tracks; int packetstatus; - int cdpos,cdlen; uint8_t asc; int reset; FILE *hdfile; @@ -167,49 +166,6 @@ int ide_ter_enabled = 0; uint8_t getstat(IDE *ide) { return ide->atastat; } -#define MSFtoLBA(m,s,f) ((((m*60)+s)*75)+f) - -typedef struct __attribute__((packed)) -{ - uint8_t user_data[2048]; - uint8_t ecc[288]; -} m1_data_t; - -typedef struct __attribute__((packed)) -{ - uint8_t sub_header[8]; - uint8_t user_data[2328]; -} m2_data_t; - -typedef union __attribute__((packed)) -{ - m1_data_t m1_data; - m2_data_t m2_data; - uint8_t raw_data[2352]; -} sector_data_t; - -typedef struct __attribute__((packed)) -{ - uint8_t sync[12]; - uint8_t header[4]; - sector_data_t data; - uint8_t c2[296]; - uint8_t subchannel_raw[96]; - uint8_t subchannel_q[16]; - uint8_t subchannel_rw[96]; -} cdrom_sector_t; - -typedef union __attribute__((packed)) -{ - cdrom_sector_t cdrom_sector; - uint8_t buffer[2856]; -} sector_buffer_t; - -sector_buffer_t cdrom_sector_buffer; - -int cdrom_sector_type, cdrom_sector_flags; -int cdrom_sector_size, cdrom_sector_ismsf; - int image_is_hdi(const char *s) { int i, len; @@ -1907,266 +1863,6 @@ static void atapi_sense_clear(int command, int ignore_ua) } } -static int cdrom_add_error_and_subchannel(uint8_t *b, int real_sector_type) -{ - if ((cdrom_sector_flags & 0x06) == 0x02) - { - /* Add error flags. */ - memcpy(b + cdrom_sector_size, cdrom_sector_buffer.cdrom_sector.c2, 294); - cdrom_sector_size += 294; - } - else if ((cdrom_sector_flags & 0x06) == 0x04) - { - /* Add error flags. */ - memcpy(b + cdrom_sector_size, cdrom_sector_buffer.cdrom_sector.c2, 296); - cdrom_sector_size += 296; - } - else if ((cdrom_sector_flags & 0x06) == 0x06) - { - // pclog("Invalid error flags\n"); - return 0; - } - - /* if (real_sector_type == 1) - { */ - if ((cdrom_sector_flags & 0x700) == 0x100) - { - memcpy(b + cdrom_sector_size, cdrom_sector_buffer.cdrom_sector.subchannel_raw, 96); - cdrom_sector_size += 96; - } - else if ((cdrom_sector_flags & 0x700) == 0x200) - { - memcpy(b + cdrom_sector_size, cdrom_sector_buffer.cdrom_sector.subchannel_q, 16); - cdrom_sector_size += 16; - } - else if ((cdrom_sector_flags & 0x700) == 0x400) - { - memcpy(b + cdrom_sector_size, cdrom_sector_buffer.cdrom_sector.subchannel_rw, 96); - cdrom_sector_size += 96; - } - else if (((cdrom_sector_flags & 0x700) == 0x300) || ((cdrom_sector_flags & 0x700) > 0x400)) - { - // pclog("Invalid subchannel data flags\n"); - return 0; - } - // } - - // pclog("CD-ROM sector size after processing: %i (%i, %i) [%04X]\n", cdrom_sector_size, cdrom_sector_type, real_sector_type, cdrom_sector_flags); - - return cdrom_sector_size; -} - -static int cdrom_LBAtoMSF_accurate(IDE *ide) -{ - int temp_pos; - int m, s, f; - - temp_pos = ide->cdpos + 150; - f = temp_pos % 75; - temp_pos -= f; - temp_pos /= 75; - s = temp_pos % 60; - temp_pos -= s; - temp_pos /= 60; - m = temp_pos; - - return ((m << 16) | (s << 8) | f); -} - -static int cdrom_read_data(IDE *ide, uint8_t *buffer) -{ - int real_sector_type; - uint8_t *b; - uint8_t *temp_b; - int is_audio; - int real_pos; - - b = temp_b = buffer; - - if (cdrom_sector_ismsf) - { - real_pos = cdrom_LBAtoMSF_accurate(ide); - } - else - { - real_pos = ide->cdpos; - } - - memset(cdrom_sector_buffer.buffer, 0, 2856); - - // is_audio = cdrom->is_track_audio(real_pos, cdrom_sector_ismsf); - real_sector_type = cdrom->sector_data_type(real_pos, cdrom_sector_ismsf); - // pclog("Sector type: %i\n", real_sector_type); - - if ((cdrom_sector_type > 0) && (cdrom_sector_type < 6)) - { - if (real_sector_type != cdrom_sector_type) - { - return 0; - } - } - else if (cdrom_sector_type == 6) - { - /* READ (6), READ (10), READ (12) */ - if ((real_sector_type != 2) && (real_sector_type != 4)) - { - return 0; - } - } - - if (!(cdrom_sector_flags & 0xf0)) /* 0x00 and 0x08 are illegal modes */ - { - return 0; - } - - cdrom->readsector_raw(cdrom_sector_buffer.buffer, real_pos, cdrom_sector_ismsf); - - if (real_sector_type == 1) - { - memcpy(b, cdrom_sector_buffer.buffer, 2352); - cdrom_sector_size = 2352; - } - else - { - if ((cdrom_sector_flags & 0x18) == 0x08) /* EDC/ECC without user data is an illegal mode */ - { - return 0; - } - - cdrom_sector_size = 0; - - if (cdrom_sector_flags & 0x80) /* Sync */ - { - memcpy(temp_b, cdrom_sector_buffer.cdrom_sector.sync, 12); - cdrom_sector_size += 12; - temp_b += 12; - } - if (cdrom_sector_flags & 0x20) /* Header */ - { - memcpy(temp_b, cdrom_sector_buffer.cdrom_sector.header, 4); - cdrom_sector_size += 4; - temp_b += 4; - } - - if (real_sector_type == 2) - { - /* Mode 1 sector, expected type is 1 type. */ - if (cdrom_sector_flags & 0x40) /* Sub-header */ - { - if (!(cdrom_sector_flags & 0x10)) /* No user data */ - { - memcpy(temp_b, cdrom_sector_buffer.cdrom_sector.data.m1_data.user_data, 8); - cdrom_sector_size += 8; - temp_b += 8; - } - } - if (cdrom_sector_flags & 0x10) /* User data */ - { - memcpy(temp_b, cdrom_sector_buffer.cdrom_sector.data.m1_data.user_data, 2048); - cdrom_sector_size += 2048; - temp_b += 2048; - } - if (cdrom_sector_flags & 0x08) /* EDC/ECC */ - { - memcpy(temp_b, cdrom_sector_buffer.cdrom_sector.data.m1_data.ecc, 288); - cdrom_sector_size += 288; - temp_b += 288; - } - } - else if (real_sector_type == 3) - { - /* Mode 2 sector, non-XA mode. */ - if (cdrom_sector_flags & 0x40) /* Sub-header */ - { - if (!(cdrom_sector_flags & 0x10)) /* No user data */ - { - memcpy(temp_b, cdrom_sector_buffer.cdrom_sector.data.m2_data.sub_header, 8); - cdrom_sector_size += 8; - temp_b += 8; - } - } - if (cdrom_sector_flags & 0x10) /* User data */ - { - memcpy(temp_b, cdrom_sector_buffer.cdrom_sector.data.m2_data.sub_header, 2328); - cdrom_sector_size += 8; - temp_b += 8; - memcpy(temp_b, cdrom_sector_buffer.cdrom_sector.data.m2_data.user_data, 2328); - cdrom_sector_size += 2328; - temp_b += 2328; - } - } - else if (real_sector_type == 4) - { - /* Mode 2 sector, XA Form 1 mode */ - if ((cdrom_sector_flags & 0xf0) == 0x30) - { - return 0; - } - if (((cdrom_sector_flags & 0xf8) >= 0xa8) && ((cdrom_sector_flags & 0xf8) <= 0xd8)) - { - return 0; - } - if (cdrom_sector_flags & 0x40) /* Sub-header */ - { - memcpy(temp_b, cdrom_sector_buffer.cdrom_sector.data.m2_data.sub_header, 8); - cdrom_sector_size += 8; - temp_b += 8; - } - if (cdrom_sector_flags & 0x10) /* User data */ - { - if ((cdrom_sector_flags & 0xf0) == 0x10) - { - /* The data is alone, include sub-header. */ - memcpy(temp_b, cdrom_sector_buffer.cdrom_sector.data.m2_data.sub_header, 8); - cdrom_sector_size += 8; - temp_b += 8; - } - memcpy(temp_b, cdrom_sector_buffer.cdrom_sector.data.m2_data.user_data, 2040); - cdrom_sector_size += 2040; - temp_b += 2040; - } - if (cdrom_sector_flags & 0x08) /* EDC/ECC */ - { - memcpy(temp_b, cdrom_sector_buffer.cdrom_sector.data.m2_data.user_data + 2040, 288); - cdrom_sector_size += 288; - temp_b += 288; - } - } - else if (real_sector_type == 5) - { - /* Mode 2 sector, XA Form 2 mode */ - if ((cdrom_sector_flags & 0xf0) == 0x30) - { - return 0; - } - if (((cdrom_sector_flags & 0xf8) >= 0xa8) || ((cdrom_sector_flags & 0xf8) <= 0xd8)) - { - return 0; - } - /* Mode 2 sector, XA Form 1 mode */ - if (cdrom_sector_flags & 0x40) /* Sub-header */ - { - memcpy(temp_b, cdrom_sector_buffer.cdrom_sector.data.m2_data.sub_header, 8); - cdrom_sector_size += 8; - temp_b += 8; - } - if (cdrom_sector_flags & 0x10) /* User data */ - { - memcpy(temp_b, cdrom_sector_buffer.cdrom_sector.data.m2_data.user_data, 2328); - cdrom_sector_size += 2328; - temp_b += 2328; - } - } - else - { - return 0; - } - } - - // pclog("CD-ROM sector size: %i (%i, %i) [%04X]\n", cdrom_sector_size, cdrom_sector_type, real_sector_type, cdrom_sector_flags); - return cdrom_add_error_and_subchannel(b, real_sector_type); -} - static void atapicommand(int ide_board) { IDE *ide = &ide_drives[cur_ide[ide_board]]; @@ -2202,7 +1898,7 @@ static void atapicommand(int ide_board) #endif msf=idebufferb[1]&2; - ide->cdlen=0; + SectorLen=0; if (cdrom->medium_changed()) { @@ -2412,18 +2108,18 @@ static void atapicommand(int ide_board) // pclog("Read CD : start LBA %02X%02X%02X%02X Length %02X%02X%02X Flags %02X\n",idebufferb[2],idebufferb[3],idebufferb[4],idebufferb[5],idebufferb[6],idebufferb[7],idebufferb[8],idebufferb[9]); if (idebufferb[0] == GPCMD_READ_CD_MSF) { - ide->cdpos=MSFtoLBA(idebufferb[3],idebufferb[4],idebufferb[5]); - ide->cdlen=MSFtoLBA(idebufferb[6],idebufferb[7],idebufferb[8]); + SectorLBA=MSFtoLBA(idebufferb[3],idebufferb[4],idebufferb[5]); + SectorLen=MSFtoLBA(idebufferb[6],idebufferb[7],idebufferb[8]); - ide->cdlen -= ide->cdpos; - ide->cdlen++; + SectorLen -= SectorLBA; + SectorLen++; cdrom_sector_ismsf = 1; } else { - ide->cdlen=(idebufferb[6]<<16)|(idebufferb[7]<<8)|idebufferb[8]; - ide->cdpos=(idebufferb[2]<<24)|(idebufferb[3]<<16)|(idebufferb[4]<<8)|idebufferb[5]; + SectorLen=(idebufferb[6]<<16)|(idebufferb[7]<<8)|idebufferb[8]; + SectorLBA=(idebufferb[2]<<24)|(idebufferb[3]<<16)|(idebufferb[4]<<8)|idebufferb[5]; cdrom_sector_ismsf = 0; } @@ -2431,7 +2127,7 @@ static void atapicommand(int ide_board) cdrom_sector_type = (idebufferb[1] >> 2) & 7; cdrom_sector_flags = idebufferb[9] || (((uint32_t) idebufferb[10]) << 8); - if (ide->cdpos > (cdrom->size() - 1)) + if (SectorLBA > (cdrom->size() - 1)) { pclog("Trying to read beyond the end of disc\n"); ide->atastat = READY_STAT | ERR_STAT; /*CHECK CONDITION*/ @@ -2446,7 +2142,7 @@ static void atapicommand(int ide_board) break; } - ret = cdrom_read_data(ide, idebufferb); + ret = cdrom_read_data(idebufferb); if (!ret) { @@ -2466,9 +2162,9 @@ static void atapicommand(int ide_board) readflash=1; #endif - ide->cdpos++; - ide->cdlen--; - if (ide->cdlen >= 0) + SectorLBA++; + SectorLen--; + if (SectorLen >= 0) ide->packetstatus = ATAPI_STATUS_READCD; else ide->packetstatus = ATAPI_STATUS_DATA; @@ -2487,21 +2183,21 @@ static void atapicommand(int ide_board) if (idebufferb[0] == GPCMD_READ_6) { - ide->cdlen=idebufferb[4]; - ide->cdpos=((((uint32_t) idebufferb[1]) & 0x1f)<<16)|(((uint32_t) idebufferb[2])<<8)|((uint32_t) idebufferb[3]); + SectorLen=idebufferb[4]; + SectorLBA=((((uint32_t) idebufferb[1]) & 0x1f)<<16)|(((uint32_t) idebufferb[2])<<8)|((uint32_t) idebufferb[3]); } else if (idebufferb[0] == GPCMD_READ_10) { - ide->cdlen=(idebufferb[7]<<8)|idebufferb[8]; - ide->cdpos=(idebufferb[2]<<24)|(idebufferb[3]<<16)|(idebufferb[4]<<8)|idebufferb[5]; + SectorLen=(idebufferb[7]<<8)|idebufferb[8]; + SectorLBA=(idebufferb[2]<<24)|(idebufferb[3]<<16)|(idebufferb[4]<<8)|idebufferb[5]; } else { - ide->cdlen=(((uint32_t) idebufferb[6])<<24)|(((uint32_t) idebufferb[7])<<16)|(((uint32_t) idebufferb[8])<<8)|((uint32_t) idebufferb[9]); - ide->cdpos=(((uint32_t) idebufferb[2])<<24)|(((uint32_t) idebufferb[3])<<16)|(((uint32_t) idebufferb[4])<<8)|((uint32_t) idebufferb[5]); + SectorLen=(((uint32_t) idebufferb[6])<<24)|(((uint32_t) idebufferb[7])<<16)|(((uint32_t) idebufferb[8])<<8)|((uint32_t) idebufferb[9]); + SectorLBA=(((uint32_t) idebufferb[2])<<24)|(((uint32_t) idebufferb[3])<<16)|(((uint32_t) idebufferb[4])<<8)|((uint32_t) idebufferb[5]); } - if (ide->cdpos > (cdrom->size() - 1)) + if (SectorLBA > (cdrom->size() - 1)) { pclog("Trying to read beyond the end of disc\n"); ide->atastat = READY_STAT | ERR_STAT; /*CHECK CONDITION*/ @@ -2516,7 +2212,7 @@ static void atapicommand(int ide_board) break; } - if (!ide->cdlen) + if (!SectorLen) { // pclog("All done - callback set\n"); ide->packetstatus = ATAPI_STATUS_COMPLETE; @@ -2527,7 +2223,7 @@ static void atapicommand(int ide_board) cdrom_sector_type = 6; cdrom_sector_flags = 0x10; - ret = cdrom_read_data(ide, idebufferb); + ret = cdrom_read_data(idebufferb); if (!ret) { @@ -2544,9 +2240,9 @@ static void atapicommand(int ide_board) #ifndef RPCEMU_IDE readflash=1; #endif - ide->cdpos++; - ide->cdlen--; - if (ide->cdlen >= 0) + SectorLBA++; + SectorLen--; + if (SectorLen >= 0) ide->packetstatus = ATAPI_STATUS_READCD; else ide->packetstatus = ATAPI_STATUS_DATA; @@ -2564,15 +2260,15 @@ static void atapicommand(int ide_board) } else { - ide->cdlen=(idebufferb[7]<<8)|idebufferb[8]; - ide->cdpos=(idebufferb[2]<<24)|(idebufferb[3]<<16)|(idebufferb[4]<<8)|idebufferb[5]; + SectorLen=(idebufferb[7]<<8)|idebufferb[8]; + SectorLBA=(idebufferb[2]<<24)|(idebufferb[3]<<16)|(idebufferb[4]<<8)|idebufferb[5]; if (msf) { real_pos = cdrom_LBAtoMSF_accurate(ide); } else { - real_pos = ide->cdpos; + real_pos = SectorLBA; } idebufferb[4] = (real_pos >> 24); idebufferb[5] = ((real_pos >> 16) & 0xff); @@ -3200,24 +2896,24 @@ static void callreadcd(IDE *ide) int ret; ide_irq_lower(ide); - if (ide->cdlen<=0) + if (SectorLen<=0) { // pclog("All done - callback set\n"); ide->packetstatus = ATAPI_STATUS_COMPLETE; idecallback[ide->board]=20*IDE_TIME; return; } -// pclog("Continue readcd! %i blocks left\n",ide->cdlen); +// pclog("Continue readcd! %i blocks left\n",SectorLen); ide->atastat = BUSY_STAT; - ret = cdrom_read_data(ide, (uint8_t *) ide->buffer); + ret = cdrom_read_data((uint8_t *) ide->buffer); #ifndef RPCEMU_IDE readflash=1; #endif - ide->cdpos++; - ide->cdlen--; + SectorLBA++; + SectorLen--; ide->packetstatus = ATAPI_STATUS_READCD; ide->cylinder=cdrom_sector_size; ide->secount=2; diff --git a/src/pc.c b/src/pc.c index 2e85b9091..3958f471f 100644 --- a/src/pc.c +++ b/src/pc.c @@ -23,7 +23,7 @@ #include "fdd.h" #include "gameport.h" #include "sound_gus.h" -#include "aha154x.h" +#include "buslogic.h" #include "cdrom.h" #include "scsi.h" #include "ide.h" @@ -292,10 +292,10 @@ void initpc(int argc, char *argv[]) loadnvr(); sound_init(); resetide(); - if (aha154x_enabled) + if (buslogic_enabled) { - SCSIReset(&ScsiDrives[scsi_cdrom_id], scsi_cdrom_id); - AdaptecInit(scsi_cdrom_id); + SCSIReset(scsi_cdrom_id); + device_add(&BuslogicDevice); } if ((cdrom_drive == -1) || (cdrom_drive == 0)) @@ -419,11 +419,11 @@ void resetpchard() resetide(); - if (aha154x_enabled) + if (buslogic_enabled) { - SCSIReset(&ScsiDrives[scsi_cdrom_id], scsi_cdrom_id); - AdaptecInit(scsi_cdrom_id); - } + SCSIReset(scsi_cdrom_id); + device_add(&BuslogicDevice); + } loadnvr(); @@ -626,7 +626,7 @@ void loadconfig(char *fn) GUS = config_get_int(NULL, "gus", 0); SSI2001 = config_get_int(NULL, "ssi2001", 0); voodoo_enabled = config_get_int(NULL, "voodoo", 0); - aha154x_enabled = config_get_int(NULL, "aha154x", 0); + buslogic_enabled = config_get_int(NULL, "buslogic", 0); scsi_base = config_get_int(NULL, "scsi_base", 0x330); scsi_irq = config_get_int(NULL, "scsi_irq", 11); @@ -814,7 +814,7 @@ void saveconfig() config_set_int(NULL, "gus", GUS); config_set_int(NULL, "ssi2001", SSI2001); config_set_int(NULL, "voodoo", voodoo_enabled); - config_set_int(NULL, "aha154x", aha154x_enabled); + config_set_int(NULL, "buslogic", buslogic_enabled); config_set_int(NULL, "scsi_base", scsi_base); config_set_int(NULL, "scsi_irq", scsi_irq); diff --git a/src/scsi.c b/src/scsi.c index bdf5c28c0..c66234a0b 100644 --- a/src/scsi.c +++ b/src/scsi.c @@ -1,4 +1,4 @@ -/* Copyright holders: SA1988 +/* Copyright holders: SA1988, Tenshi see COPYING for more details */ /*SCSI layer emulation*/ @@ -11,98 +11,101 @@ #include "cdrom.h" #include "scsi.h" -int ScsiCallback[7] = {0,0,0,0,0,0,0}; +#include "timer.h" + +int SCSICallback[7] = {0,0,0,0,0,0,0}; uint8_t scsi_cdrom_id = 3; /*common setting*/ -void SCSIQueryResidual(SCSI *Scsi, uint32_t *Residual) +//Get the transfer length of the command +void SCSIGetLength(uint8_t id, int *datalen) { - *Residual = ScsiStatus == SCSI_STATUS_OK ? 0 : Scsi->SegmentData.Length; + *datalen = SCSIDevices[id].CmdBufferLength; } -static uint32_t SCSICopyFromBuffer(uint32_t OffDst, SGBUF *SegmentBuffer, - uint32_t Copy) +//Execute SCSI command +void SCSIExecCommand(uint8_t id, uint8_t *cdb) { - const SGSEG *SegmentArray = SegmentBuffer->SegmentPtr; - unsigned SegmentNum = SegmentBuffer->SegmentNum; - uint32_t Copied = 0; + SCSICDROM_Command(id, cdb); +} + +//Read pending data from the resulting SCSI command +void SCSIReadData(uint8_t id, uint8_t *cdb, uint8_t *data, int datalen) +{ + SCSICDROM_ReadData(id, cdb, data, datalen); +} + +//Write pending data to the resulting SCSI command +void SCSIWriteData(uint8_t id, uint8_t *cdb, uint8_t *data, int datalen) +{ + SCSICDROM_WriteData(id, cdb, data, datalen); +} + +///// +void SCSIDMAResetPosition(uint8_t Id) +{ + //Reset position in memory after reaching the + SCSIDevices[Id].pos = 0; +} + +//Read data from buffer with given position in buffer memory +void SCSIRead(uint8_t Id, uint32_t len_size) +{ + if (!len_size) //If there's no data, don't try to do anything. + return; - SGBUF SegmentBuffer2; - SegmentBufferInit(&SegmentBuffer2, SegmentArray, SegmentNum); - - SegmentBufferAdvance(&SegmentBuffer2, OffDst); - Copied = SegmentBufferCopy(&SegmentBuffer2, SegmentBuffer, Copy); - - return Copied; -} - -static uint32_t SCSICopyToBuffer(uint32_t OffSrc, SGBUF *SegmentBuffer, - uint32_t Copy) -{ - const SGSEG *SegmentArray = SegmentBuffer->SegmentPtr; - unsigned SegmentNum = SegmentBuffer->SegmentNum; - uint32_t Copied = 0; + int c; - SGBUF SegmentBuffer2; - SegmentBufferInit(&SegmentBuffer2, SegmentArray, SegmentNum); - - SegmentBufferAdvance(&SegmentBuffer2, OffSrc); - Copied = SegmentBufferCopy(&SegmentBuffer2, SegmentBuffer, Copy); - - return Copied; -} - -void SCSIWriteTransfer(SCSI *Scsi, uint8_t Id) -{ - if ((Scsi->BufferPosition >= prefix_len + 4) && (page_flags[page_current] & PAGE_CHANGEABLE)) + for (c = 0; c <= len_size; c++) //Count as many bytes as the length of the buffer is requested { - mode_pages_in[page_current][Scsi->BufferPosition - prefix_len - 4] = Scsi->SegmentData.Address[Scsi->BufferPosition - 2]; - mode_pages_in[page_current][Scsi->BufferPosition - prefix_len - 3] = Scsi->SegmentData.Address[Scsi->BufferPosition - 1]; + memcpy(SCSIDevices[Id].CmdBuffer, SCSIDevices[Id].CmdBuffer + SCSIDevices[Id].pos, len_size); + SCSIDevices[Id].pos = c; + + //pclog("SCSI Read: position at %i\n", SCSIDevices[Id].pos); } - SGBUF SegmentBuffer; - SCSICopyToBuffer(Scsi->SegmentData.Length, &SegmentBuffer, 1); - pfnIoRequestCopyToBuffer(0, &SegmentBuffer, Scsi->SegmentData.Length); } -void SCSIReadTransfer(SCSI *Scsi, uint8_t Id) +//Write data to buffer with given position in buffer memory +void SCSIWrite(uint8_t Id, uint32_t len_size) { - SCSICDROM_ReadCallback(Scsi, Id); + if (!len_size) //If there's no data, don't try to do anything. + return; - SGBUF SegmentBuffer; - SCSICopyFromBuffer(Scsi->SegmentData.Length, &SegmentBuffer, 1); - pfnIoRequestCopyFromBuffer(0, &SegmentBuffer, Scsi->SegmentData.Length); -} + int c; + + for (c = 0; c <= len_size; c++) //Count as many bytes as the length of the buffer is requested + { + memcpy(SCSIDevices[Id].CmdBuffer + SCSIDevices[Id].pos, SCSIDevices[Id].CmdBuffer, len_size); + SCSIDevices[Id].pos = c; + + //Mode Sense/Select stuff + if ((SCSIDevices[Id].pos >= prefix_len+4) && (page_flags[page_current] & PAGE_CHANGEABLE)) + { + mode_pages_in[page_current][SCSIDevices[Id].pos - prefix_len - 4] = SCSIDevices[Id].CmdBuffer[SCSIDevices[Id].pos - 2]; + mode_pages_in[page_current][SCSIDevices[Id].pos - prefix_len - 3] = SCSIDevices[Id].CmdBuffer[SCSIDevices[Id].pos - 1]; + } -void SCSISendCommand(SCSI *Scsi, uint8_t Id, uint8_t *Cdb, uint8_t CdbLength, uint32_t DataBufferLength, uint8_t *SenseBufferPointer, uint8_t SenseBufferLength) + //pclog("SCSI Write: position at %i\n", SCSIDevices[Id].pos); + } +} +///// + +//Initialization function for the SCSI layer +void SCSIReset(uint8_t Id) { - uint32_t i; - for (i = 0; i < CdbLength; i++) - pclog("Cdb[%d]=0x%02X\n", i, Cdb[i]); - - Scsi->CdbLength = CdbLength; - - pclog("SCSI CD-ROM in ID %d\n", Id); - SCSICDROM_RunCommand(Scsi, Id, Cdb, SenseBufferLength, SenseBufferPointer, DataBufferLength); -} - -void SCSIReset(SCSI *Scsi, uint8_t Id) -{ page_flags[GPMODE_CDROM_AUDIO_PAGE] &= 0xFD; /* Clear changed flag for CDROM AUDIO mode page. */ memset(mode_pages_in[GPMODE_CDROM_AUDIO_PAGE], 0, 256); /* Clear the page itself. */ - - if (scsi_cdrom_enabled) + + if (cdrom_enabled && scsi_cdrom_enabled) { - if (cdrom_enabled) - { - Scsi->LunType = SCSI_CDROM; - } + SCSICallback[Id]=0; + SCSIDevices[Id].LunType = SCSI_CDROM; } else { - Scsi->LunType = SCSI_NONE; - } - - pfnIoRequestCopyFromBuffer = SCSICopyFromBuffer; - pfnIoRequestCopyToBuffer = SCSICopyToBuffer; - + SCSIDevices[Id].LunType = SCSI_NONE; + } + page_flags[GPMODE_CDROM_AUDIO_PAGE] &= ~PAGE_CHANGED; -} \ No newline at end of file + + SCSISense.UnitAttention = 0; +} diff --git a/src/scsi.h b/src/scsi.h index 4514aa104..439c2a966 100644 --- a/src/scsi.h +++ b/src/scsi.h @@ -4,7 +4,11 @@ #ifndef __SCSI_H__ #define __SCSI_H__ -#include "scattergather.h" +//#include "scattergather.h" + +#include "timer.h" + +#define SCSI_TIME (5 * 100 * (1 << TIMER_SHIFT)) /* SCSI Commands */ #define GPCMD_TEST_UNIT_READY 0x00 @@ -138,6 +142,8 @@ #define MMC_PROFILE_HDDVD_RW_DL 0x005A #define MMC_PROFILE_INVALID 0xFFFF +#define WRITEDATA 0x10 +#define READDATA 8 #define NONDATA 4 #define CHECK_READY 2 #define ALLOW_UA 1 @@ -162,8 +168,12 @@ extern uint8_t page_current; uint32_t DataLength; uint32_t DataPointer; -extern uint8_t ScsiStatus; -extern int ScsiCallback[7]; +int SectorLBA; +int SectorLen; + +extern uint8_t SCSIStatus; +extern uint8_t SCSIPhase; +extern int SCSICallback[7]; extern uint8_t scsi_cdrom_id; struct @@ -181,52 +191,81 @@ extern int prev_status; #define SCSI_HDD 1 /*not present yet*/ #define SCSI_CDROM 2 -// extern sector_buffer_t cdrom_sector_buffer; +#define MSFtoLBA(m,s,f) ((((m*60)+s)*75)+f) -// extern int cdrom_sector_type, cdrom_sector_flags; -// extern int cdrom_sector_size, cdrom_sector_ismsf; - -typedef struct SCSI +typedef struct __attribute__((packed)) { - uint8_t Cdb[32]; - uint8_t CdbLength; - SGBUF SegmentBuffer; - int SectorLen; - int SectorLba; - int BufferLength; - int BufferPosition; - SGSEG SegmentData; + uint8_t user_data[2048]; + uint8_t ecc[288]; +} m1_data_t; + +typedef struct __attribute__((packed)) +{ + uint8_t sub_header[8]; + uint8_t user_data[2328]; +} m2_data_t; + +typedef union __attribute__((packed)) +{ + m1_data_t m1_data; + m2_data_t m2_data; + uint8_t raw_data[2352]; +} sector_data_t; + +typedef struct __attribute__((packed)) +{ + uint8_t sync[12]; + uint8_t header[4]; + sector_data_t data; + uint8_t c2[296]; + uint8_t subchannel_raw[96]; + uint8_t subchannel_q[16]; + uint8_t subchannel_rw[96]; +} cdrom_sector_t; + +typedef union __attribute__((packed)) +{ + cdrom_sector_t cdrom_sector; + uint8_t buffer[2856]; +} sector_buffer_t; + +extern sector_buffer_t cdrom_sector_buffer; + +extern int cdrom_sector_type, cdrom_sector_flags; +extern int cdrom_sector_size, cdrom_sector_ismsf; + +#define SCSI_PHASE_DATAOUT ( 0 ) +#define SCSI_PHASE_DATAIN ( 1 ) +#define SCSI_PHASE_COMMAND ( 2 ) +#define SCSI_PHASE_STATUS ( 3 ) +#define SCSI_PHASE_MESSAGE_OUT ( 6 ) +#define SCSI_PHASE_MESSAGE_IN ( 7 ) +#define SCSI_PHASE_BUS_FREE ( 8 ) +#define SCSI_PHASE_SELECT ( 9 ) + +#define BUFFER_LEN 262144 + +struct +{ + uint32_t buffer_size; + uint32_t pos; + uint8_t *Cdb; + uint8_t CmdBuffer[BUFFER_LEN]; + uint32_t CmdBufferLength; int LunType; - uint8_t PacketStatus; - int ReadCDCallback; - int RequestSenseEnabled; - void *p; -} SCSI; + uint32_t InitLength; +} SCSIDevices[7]; -SCSI ScsiDrives[7]; +extern void SCSIReset(uint8_t Id); -void SCSIQueryResidual(SCSI *Scsi, uint32_t *Residual); +uint32_t SCSICDROMModeSense(uint8_t *buf, uint32_t pos, uint8_t type); +uint8_t SCSICDROMSetProfile(uint8_t *buf, uint8_t *index, uint16_t profile); +int SCSICDROMReadDVDStructure(int format, const uint8_t *packet, uint8_t *buf); +uint32_t SCSICDROMEventStatus(uint8_t *buffer); +void SCSICDROM_Insert(); -void SCSISendCommand(SCSI *Scsi, uint8_t Id, uint8_t *Cdb, uint8_t CdbLength, - uint32_t DataBufferLength, uint8_t *SenseBufferPointer, - uint8_t SenseBufferLength); - -uint32_t (*pfnIoRequestCopyFromBuffer)(uint32_t OffDst, SGBUF *SegmentBuffer, - uint32_t Copy); -uint32_t (*pfnIoRequestCopyToBuffer)(uint32_t OffSrc, SGBUF *SegmentBuffer, - uint32_t Copy); -void SCSIReadTransfer(SCSI *Scsi, uint8_t Id); -void SCSIWriteTransfer(SCSI *Scsi, uint8_t Id); - -extern void SCSIReset(SCSI *Scsi, uint8_t Id); - -extern uint32_t SCSICDROMModeSense(uint8_t *buf, uint32_t pos, uint8_t type); -extern uint8_t SCSICDROMSetProfile(uint8_t *buf, uint8_t *index, uint16_t profile); -extern int SCSICDROMReadDVDStructure(int format, const uint8_t *packet, uint8_t *buf); -extern uint32_t SCSICDROMEventStatus(uint8_t *buffer); - -extern void SCSICDROM_ReadyHandler(int IsReady); -extern void SCSICDROM_Insert(); -// extern int cdrom_add_error_and_subchannel(uint8_t *b, int real_sector_type); +int cdrom_add_error_and_subchannel(uint8_t *b, int real_sector_type); +int cdrom_LBAtoMSF_accurate(); +int cdrom_read_data(uint8_t *buffer); #endif \ No newline at end of file diff --git a/src/scsi_cdrom.c b/src/scsi_cdrom.c index 928f4053c..c97ea91bc 100644 --- a/src/scsi_cdrom.c +++ b/src/scsi_cdrom.c @@ -1,4 +1,4 @@ -/* Copyright holders: SA1988 +/* Copyright holders: SA1988, Tenshi see COPYING for more details */ /*SCSI CD-ROM emulation*/ @@ -10,68 +10,27 @@ #include "cdrom.h" #include "scsi.h" -#include "timer.h" - -#define SCSI_TIME (5 * 100 * (1 << TIMER_SHIFT)) - -#define MSFtoLBA(m,s,f) ((((m*60)+s)*75)+f) - -typedef struct __attribute__((packed)) -{ - uint8_t user_data[2048]; - uint8_t ecc[288]; -} m1_data_t; - -typedef struct __attribute__((packed)) -{ - uint8_t sub_header[8]; - uint8_t user_data[2328]; -} m2_data_t; - -typedef union __attribute__((packed)) -{ - m1_data_t m1_data; - m2_data_t m2_data; - uint8_t raw_data[2352]; -} sector_data_t; - -typedef struct __attribute__((packed)) -{ - uint8_t sync[12]; - uint8_t header[4]; - sector_data_t data; - uint8_t c2[296]; - uint8_t subchannel_raw[96]; - uint8_t subchannel_q[16]; - uint8_t subchannel_rw[96]; -} cdrom_sector_t; - -typedef union __attribute__((packed)) -{ - cdrom_sector_t cdrom_sector; - uint8_t buffer[2856]; -} sector_buffer_t; - sector_buffer_t cdrom_sector_buffer; int cdrom_sector_type, cdrom_sector_flags; int cdrom_sector_size, cdrom_sector_ismsf; -uint8_t ScsiStatus = SCSI_STATUS_OK; +uint8_t SCSIPhase = SCSI_PHASE_BUS_FREE; +uint8_t SCSIStatus = SCSI_STATUS_OK; -/* Table of all ATAPI commands and their flags, needed for the new disc change / not ready handler. */ +/* Table of all SCSI commands and their flags, needed for the new disc change / not ready handler. */ uint8_t SCSICommandTable[0x100] = { [GPCMD_TEST_UNIT_READY] = CHECK_READY | NONDATA, [GPCMD_REQUEST_SENSE] = ALLOW_UA, - [GPCMD_READ_6] = CHECK_READY, + [GPCMD_READ_6] = CHECK_READY | READDATA, [GPCMD_INQUIRY] = ALLOW_UA, [GPCMD_MODE_SELECT_6] = 0, [GPCMD_MODE_SENSE_6] = 0, [GPCMD_START_STOP_UNIT] = CHECK_READY, [GPCMD_PREVENT_REMOVAL] = CHECK_READY, [GPCMD_READ_CDROM_CAPACITY] = CHECK_READY, - [GPCMD_READ_10] = CHECK_READY, + [GPCMD_READ_10] = CHECK_READY | READDATA, [GPCMD_SEEK] = CHECK_READY | NONDATA, [GPCMD_READ_SUBCHANNEL] = CHECK_READY, [GPCMD_READ_TOC_PMA_ATIP] = CHECK_READY | ALLOW_UA, /* Read TOC - can get through UNIT_ATTENTION, per VIDE-CDD.SYS @@ -90,13 +49,13 @@ uint8_t SCSICommandTable[0x100] = [GPCMD_MODE_SELECT_10] = 0, [GPCMD_MODE_SENSE_10] = 0, [GPCMD_PLAY_AUDIO_12] = CHECK_READY, - [GPCMD_READ_12] = CHECK_READY, + [GPCMD_READ_12] = CHECK_READY | READDATA, [GPCMD_READ_DVD_STRUCTURE] = CHECK_READY, - [GPCMD_READ_CD_MSF] = CHECK_READY, + [GPCMD_READ_CD_MSF] = CHECK_READY | READDATA, [GPCMD_SET_SPEED] = 0, [GPCMD_PLAY_CD] = CHECK_READY, [GPCMD_MECHANISM_STATUS] = 0, - [GPCMD_READ_CD] = CHECK_READY, + [GPCMD_READ_CD] = CHECK_READY | READDATA, [GPCMD_SEND_DVD_STRUCTURE] = CHECK_READY }; @@ -229,11 +188,10 @@ uint32_t SCSICDROMModeSense(uint8_t *buf, uint32_t pos, uint8_t type) /* &2A - CD-ROM capabilities and mechanical status */ buf[pos++] = GPMODE_CAPABILITIES_PAGE; buf[pos++] = 0x12; /* Page length */ - buf[pos++] = 7; buf[pos++] = 0; /* Supports reading CD-R and CD-E */ - buf[pos++] = 0; /* Does not support writing any type of CD */ - buf[pos++] = 0x71; /* Supportsd audio play, Mode 2 Form 1, Mode 2 Form 2, and Multi-Session */ - buf[pos++] = 0x1d; /* Some other stuff not supported (lock state + eject), but C2 and CD DA are supported, as are the R-W subchannel data in both raw - and interlaved & corrected formats */ + buf[pos++] = 0; buf[pos++] = 0; /* CD-R methods */ + buf[pos++] = 1; /* Supports audio play, not multisession */ + buf[pos++] = 0; /* Some other stuff not supported */ + buf[pos++] = 0; /* Some other stuff not supported (lock state + eject) */ buf[pos++] = 0; /* Some other stuff not supported */ buf[pos++] = (uint8_t) (CDROM_SPEED >> 8); buf[pos++] = (uint8_t) CDROM_SPEED; /* Maximum speed */ @@ -409,7 +367,6 @@ uint32_t SCSICDROMEventStatus(uint8_t *buffer) void SCSICDROM_Insert() { - // pclog("SCSICDROM_Insert()\n"); SCSISense.UnitAttention=1; } @@ -419,7 +376,7 @@ int prev_status; static uint8_t ScsiPrev; static int SenseCompleted; -static int cdrom_add_error_and_subchannel(uint8_t *b, int real_sector_type) +int cdrom_add_error_and_subchannel(uint8_t *b, int real_sector_type) { if ((cdrom_sector_flags & 0x06) == 0x02) { @@ -435,7 +392,7 @@ static int cdrom_add_error_and_subchannel(uint8_t *b, int real_sector_type) } else if ((cdrom_sector_flags & 0x06) == 0x06) { - pclog("Invalid error flags\n"); + // pclog("Invalid error flags\n"); return 0; } @@ -458,7 +415,7 @@ static int cdrom_add_error_and_subchannel(uint8_t *b, int real_sector_type) } else if (((cdrom_sector_flags & 0x700) == 0x300) || ((cdrom_sector_flags & 0x700) > 0x400)) { - pclog("Invalid subchannel data flags\n"); + // pclog("Invalid subchannel data flags\n"); return 0; } // } @@ -468,12 +425,12 @@ static int cdrom_add_error_and_subchannel(uint8_t *b, int real_sector_type) return cdrom_sector_size; } -static int SCSICDROM_LBAtoMSF_accurate(SCSI *Scsi) +int cdrom_LBAtoMSF_accurate() { int temp_pos; int m, s, f; - temp_pos = Scsi->SectorLba; + temp_pos = SectorLBA + 150; f = temp_pos % 75; temp_pos -= f; temp_pos /= 75; @@ -485,7 +442,7 @@ static int SCSICDROM_LBAtoMSF_accurate(SCSI *Scsi) return ((m << 16) | (s << 8) | f); } -static int SCSICDROMReadData(SCSI *Scsi, uint8_t *buffer) +int cdrom_read_data(uint8_t *buffer) { int real_sector_type; uint8_t *b; @@ -497,36 +454,46 @@ static int SCSICDROMReadData(SCSI *Scsi, uint8_t *buffer) if (cdrom_sector_ismsf) { - real_pos = SCSICDROM_LBAtoMSF_accurate(Scsi); + real_pos = cdrom_LBAtoMSF_accurate(); } else { - real_pos = Scsi->SectorLba; + real_pos = SectorLBA; } memset(cdrom_sector_buffer.buffer, 0, 2856); - cdrom->readsector_raw(cdrom_sector_buffer.buffer, real_pos, cdrom_sector_ismsf); - is_audio = cdrom->is_track_audio(real_pos, cdrom_sector_ismsf); + // is_audio = cdrom->is_track_audio(real_pos, cdrom_sector_ismsf); + real_sector_type = cdrom->sector_data_type(real_pos, cdrom_sector_ismsf); + // pclog("Sector type: %i\n", real_sector_type); + + if ((cdrom_sector_type > 0) && (cdrom_sector_type < 6)) + { + if (real_sector_type != cdrom_sector_type) + { + return 0; + } + } + else if (cdrom_sector_type == 6) + { + /* READ (6), READ (10), READ (12) */ + if ((real_sector_type != 2) && (real_sector_type != 4)) + { + return 0; + } + } if (!(cdrom_sector_flags & 0xf0)) /* 0x00 and 0x08 are illegal modes */ { return 0; } + + cdrom->readsector_raw(cdrom_sector_buffer.buffer, real_pos, cdrom_sector_ismsf); - if (cdrom->is_track_audio(Scsi->SectorLba, 0)) + if (real_sector_type == 1) { - real_sector_type = 1; - - if (cdrom_sector_type > 1) - { - return 0; - } - else - { - memcpy(b, cdrom_sector_buffer.buffer, 2352); - cdrom_sector_size = 2352; - } + memcpy(b, cdrom_sector_buffer.buffer, 2352); + cdrom_sector_size = 2352; } else { @@ -550,140 +517,114 @@ static int SCSICDROMReadData(SCSI *Scsi, uint8_t *buffer) temp_b += 4; } - switch(cdrom_sector_buffer.cdrom_sector.header[3]) - { - case 1: - real_sector_type = 2; /* Mode 1 */ - break; - case 2: - real_sector_type = 3; /* Mode 2 */ - break; - default: - return 0; - } - if (real_sector_type == 2) { - if ((cdrom_sector_type == 0) || (cdrom_sector_type == 2)) + /* Mode 1 sector, expected type is 1 type. */ + if (cdrom_sector_flags & 0x40) /* Sub-header */ { - /* Mode 1 sector, expected type is 1 type. */ - if (cdrom_sector_flags & 0x40) /* Sub-header */ + if (!(cdrom_sector_flags & 0x10)) /* No user data */ { - if (!(cdrom_sector_flags & 0x10)) /* No user data */ - { - memcpy(temp_b, cdrom_sector_buffer.cdrom_sector.data.m1_data.user_data, 8); - cdrom_sector_size += 8; - temp_b += 8; - } - } - if (cdrom_sector_flags & 0x10) /* User data */ - { - memcpy(temp_b, cdrom_sector_buffer.cdrom_sector.data.m1_data.user_data, 2048); - cdrom_sector_size += 2048; - temp_b += 2048; - } - if (cdrom_sector_flags & 0x08) /* EDC/ECC */ - { - memcpy(temp_b, cdrom_sector_buffer.cdrom_sector.data.m1_data.ecc, 288); - cdrom_sector_size += 288; - temp_b += 288; + memcpy(temp_b, cdrom_sector_buffer.cdrom_sector.data.m1_data.user_data, 8); + cdrom_sector_size += 8; + temp_b += 8; } } - else + if (cdrom_sector_flags & 0x10) /* User data */ { - return 0; + memcpy(temp_b, cdrom_sector_buffer.cdrom_sector.data.m1_data.user_data, 2048); + cdrom_sector_size += 2048; + temp_b += 2048; + } + if (cdrom_sector_flags & 0x08) /* EDC/ECC */ + { + memcpy(temp_b, cdrom_sector_buffer.cdrom_sector.data.m1_data.ecc, 288); + cdrom_sector_size += 288; + temp_b += 288; } } else if (real_sector_type == 3) { - if ((cdrom_sector_type == 0) || (cdrom_sector_type == 3)) + /* Mode 2 sector, non-XA mode. */ + if (cdrom_sector_flags & 0x40) /* Sub-header */ { - /* Mode 2 sector, non-XA mode. */ - if (cdrom_sector_flags & 0x40) /* Sub-header */ - { - if (!(cdrom_sector_flags & 0x10)) /* No user data */ - { - memcpy(temp_b, cdrom_sector_buffer.cdrom_sector.data.m2_data.sub_header, 8); - cdrom_sector_size += 8; - temp_b += 8; - } - } - if (cdrom_sector_flags & 0x10) /* User data */ - { - memcpy(temp_b, cdrom_sector_buffer.cdrom_sector.data.m2_data.sub_header, 2328); - cdrom_sector_size += 8; - temp_b += 8; - memcpy(temp_b, cdrom_sector_buffer.cdrom_sector.data.m2_data.user_data, 2328); - cdrom_sector_size += 2328; - temp_b += 2328; - } - } - else if (cdrom_sector_type == 4) - { - /* Mode 2 sector, XA Form 1 mode */ - if ((cdrom_sector_flags & 0xf0) == 0x30) - { - return 0; - } - if (((cdrom_sector_flags & 0xf8) >= 0xa8) || ((cdrom_sector_flags & 0xf8) <= 0xd8)) - { - return 0; - } - if (cdrom_sector_flags & 0x40) /* Sub-header */ + if (!(cdrom_sector_flags & 0x10)) /* No user data */ { memcpy(temp_b, cdrom_sector_buffer.cdrom_sector.data.m2_data.sub_header, 8); cdrom_sector_size += 8; temp_b += 8; } - if (cdrom_sector_flags & 0x10) /* User data */ - { - if ((cdrom_sector_flags & 0xf0) == 0x10) - { - /* The data is alone, include sub-header. */ - memcpy(temp_b, cdrom_sector_buffer.cdrom_sector.data.m2_data.sub_header, 8); - cdrom_sector_size += 8; - temp_b += 8; - } - memcpy(temp_b, cdrom_sector_buffer.cdrom_sector.data.m2_data.user_data, 2040); - cdrom_sector_size += 2040; - temp_b += 2040; - } - if (cdrom_sector_flags & 0x08) /* EDC/ECC */ - { - memcpy(temp_b, cdrom_sector_buffer.cdrom_sector.data.m2_data.user_data + 2040, 288); - cdrom_sector_size += 288; - temp_b += 288; - } } - else if (cdrom_sector_type == 5) + if (cdrom_sector_flags & 0x10) /* User data */ { - /* Mode 2 sector, XA Form 2 mode */ - if ((cdrom_sector_flags & 0xf0) == 0x30) - { - return 0; - } - if (((cdrom_sector_flags & 0xf8) >= 0xa8) || ((cdrom_sector_flags & 0xf8) <= 0xd8)) - { - return 0; - } - /* Mode 2 sector, XA Form 1 mode */ - if (cdrom_sector_flags & 0x40) /* Sub-header */ - { - memcpy(temp_b, cdrom_sector_buffer.cdrom_sector.data.m2_data.sub_header, 8); - cdrom_sector_size += 8; - temp_b += 8; - } - if (cdrom_sector_flags & 0x10) /* User data */ - { - memcpy(temp_b, cdrom_sector_buffer.cdrom_sector.data.m2_data.user_data, 2328); - cdrom_sector_size += 2328; - temp_b += 2328; - } + memcpy(temp_b, cdrom_sector_buffer.cdrom_sector.data.m2_data.sub_header, 2328); + cdrom_sector_size += 8; + temp_b += 8; + memcpy(temp_b, cdrom_sector_buffer.cdrom_sector.data.m2_data.user_data, 2328); + cdrom_sector_size += 2328; + temp_b += 2328; } - else + } + else if (real_sector_type == 4) + { + /* Mode 2 sector, XA Form 1 mode */ + if ((cdrom_sector_flags & 0xf0) == 0x30) { return 0; } + if (((cdrom_sector_flags & 0xf8) >= 0xa8) && ((cdrom_sector_flags & 0xf8) <= 0xd8)) + { + return 0; + } + if (cdrom_sector_flags & 0x40) /* Sub-header */ + { + memcpy(temp_b, cdrom_sector_buffer.cdrom_sector.data.m2_data.sub_header, 8); + cdrom_sector_size += 8; + temp_b += 8; + } + if (cdrom_sector_flags & 0x10) /* User data */ + { + if ((cdrom_sector_flags & 0xf0) == 0x10) + { + /* The data is alone, include sub-header. */ + memcpy(temp_b, cdrom_sector_buffer.cdrom_sector.data.m2_data.sub_header, 8); + cdrom_sector_size += 8; + temp_b += 8; + } + memcpy(temp_b, cdrom_sector_buffer.cdrom_sector.data.m2_data.user_data, 2040); + cdrom_sector_size += 2040; + temp_b += 2040; + } + if (cdrom_sector_flags & 0x08) /* EDC/ECC */ + { + memcpy(temp_b, cdrom_sector_buffer.cdrom_sector.data.m2_data.user_data + 2040, 288); + cdrom_sector_size += 288; + temp_b += 288; + } + } + else if (real_sector_type == 5) + { + /* Mode 2 sector, XA Form 2 mode */ + if ((cdrom_sector_flags & 0xf0) == 0x30) + { + return 0; + } + if (((cdrom_sector_flags & 0xf8) >= 0xa8) || ((cdrom_sector_flags & 0xf8) <= 0xd8)) + { + return 0; + } + /* Mode 2 sector, XA Form 1 mode */ + if (cdrom_sector_flags & 0x40) /* Sub-header */ + { + memcpy(temp_b, cdrom_sector_buffer.cdrom_sector.data.m2_data.sub_header, 8); + cdrom_sector_size += 8; + temp_b += 8; + } + if (cdrom_sector_flags & 0x10) /* User data */ + { + memcpy(temp_b, cdrom_sector_buffer.cdrom_sector.data.m2_data.user_data, 2328); + cdrom_sector_size += 2328; + temp_b += 2328; + } } else { @@ -695,77 +636,52 @@ static int SCSICDROMReadData(SCSI *Scsi, uint8_t *buffer) return cdrom_add_error_and_subchannel(b, real_sector_type); } -void SCSIClearSense(uint8_t Command) +static void SCSIClearSense(uint8_t Command, uint8_t IgnoreUA) { - if ((SCSISense.SenseKey == SENSE_UNIT_ATTENTION)) + if ((SCSISense.SenseKey == SENSE_UNIT_ATTENTION) || IgnoreUA) { ScsiPrev=Command; SCSISenseCodeOk(); - ScsiStatus = SCSI_STATUS_OK; } } -static void SCSICDROM_CommandInit(SCSI *Scsi, uint8_t command, int req_length, int alloc_length) +struct { - if (Scsi->BufferLength == 0xffff) - Scsi->BufferLength = 0xfffe; - - if ((Scsi->BufferLength & 1) && !(alloc_length <= Scsi->BufferLength)) - { - pclog("Odd byte count (0x%04x) to SCSI command 0x%02x, using 0x%04x\n", Scsi->SegmentData.Length, command, Scsi->BufferLength - 1); - Scsi->BufferLength--; - } - - if (alloc_length < 0) - fatal("Allocation length < 0\n"); - if (alloc_length == 0) - alloc_length = Scsi->BufferLength; - - if ((Scsi->BufferLength > req_length) || (Scsi->BufferLength == 0)) - Scsi->BufferLength = req_length; - if (Scsi->BufferLength > alloc_length) - Scsi->BufferLength = alloc_length; -} - -static void SCSICDROM_CommandReady(SCSI *Scsi, uint8_t Id, int packlen) + uint8_t opcode; + uint8_t polled; + uint8_t reserved2[2]; + uint8_t class; + uint8_t reserved3[2]; + uint16_t len; + uint8_t control; +} *gesn_cdb; + +struct { - ScsiCallback[Id]=60*SCSI_TIME; - Scsi->SegmentData.Length=packlen; - SegmentBufferCopyFromBuf(&Scsi->SegmentBuffer, Scsi->SegmentData.Address, Scsi->SegmentData.Length); - SCSIReadTransfer(Scsi, Id); -} + uint16_t len; + uint8_t notification_class; + uint8_t supported_events; +} *gesn_event_header; -void SCSICDROM_RunCommand(SCSI *Scsi, uint8_t Id, uint8_t *Cdb, uint8_t *SenseBufferPointer, uint8_t SenseBufferLength, int len) +static int SCSICDROM_TOC(uint8_t id, uint8_t *cdb) { - int pos; - int temp_command; - int alloc_length; - int ret; - uint8_t RCdMode = 0; - int c; - int Msf; - unsigned char Temp; - uint32_t Size; - uint8_t PageCode; - unsigned Idx = 0; - unsigned SizeIndex; - unsigned PreambleLen; int TocFormat; - uint8_t Index = 0; - int max_len; - int Media; - int Format; - int DVDRet; - memcpy(Scsi->Cdb, Cdb, 32); + TocFormat = cdb[2] & 0xf; + if (TocFormat == 0) + TocFormat = (cdb[9]>>6) & 3; - Msf = Scsi->Cdb[1]&2; + return TocFormat; +} +void SCSICDROM_Command(uint8_t id, uint8_t *cdb) +{ if (cdrom->medium_changed()) { + pclog("Media changed\n"); SCSICDROM_Insert(); } - + if (!cdrom->ready() && SCSISense.UnitAttention) { /* If the drive is not ready, there is no reason to keep the @@ -776,32 +692,29 @@ void SCSICDROM_RunCommand(SCSI *Scsi, uint8_t Id, uint8_t *Cdb, uint8_t *SenseBu /* If the UNIT ATTENTION condition is set and the command does not allow execution under it, error out and report the condition. */ - if (!(SCSICommandTable[Scsi->Cdb[0]] & ALLOW_UA) && SCSISense.UnitAttention) + if (!(SCSICommandTable[cdb[0]] & ALLOW_UA) && SCSISense.UnitAttention) { pclog("UNIT ATTENTION: Command not allowed to pass through\n"); SCSISenseCodeError(SENSE_UNIT_ATTENTION, ASC_MEDIUM_MAY_HAVE_CHANGED, 0); - ScsiStatus = SCSI_STATUS_CHECK_CONDITION; + SCSIStatus = SCSI_STATUS_CHECK_CONDITION; + SCSICallback[id]=50*SCSI_TIME; return; } - if (Scsi->Cdb[0] == GPCMD_READ_TOC_PMA_ATIP) - { - SCSISense.UnitAttention = 0; - } - /* Unless the command is REQUEST SENSE, clear the sense. This will *NOT* clear the UNIT ATTENTION condition if it's set. */ - if (Scsi->Cdb[0]!=GPCMD_REQUEST_SENSE) + if (cdb[0]!=GPCMD_REQUEST_SENSE) { - SCSIClearSense(Scsi->Cdb[0]); + SCSIClearSense(cdb[0], 1); } /* Next it's time for NOT READY. */ - if ((SCSICommandTable[Scsi->Cdb[0]] & CHECK_READY) && !cdrom->ready()) + if ((SCSICommandTable[cdb[0]] & CHECK_READY) && !cdrom->ready()) { pclog("Not ready\n"); SCSISenseCodeError(SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT, 0); - ScsiStatus = SCSI_STATUS_CHECK_CONDITION; + SCSIStatus = SCSI_STATUS_CHECK_CONDITION; + SCSICallback[id]=50*SCSI_TIME; return; } @@ -814,851 +727,922 @@ void SCSICDROM_RunCommand(SCSI *Scsi, uint8_t Id, uint8_t *Cdb, uint8_t *SenseBu else { SenseCompleted = 0; - } - - switch (Scsi->Cdb[0]) + } + + switch (cdb[0]) { - case GPCMD_TEST_UNIT_READY: - ScsiCallback[Id]=50*SCSI_TIME; - break; + case GPCMD_TEST_UNIT_READY: + SCSIPhase = SCSI_PHASE_STATUS; + SCSIStatus = SCSI_STATUS_OK; + SCSICallback[id]=50*SCSI_TIME; + SCSIDevices[id].CmdBufferLength = 0; + break; - case GPCMD_REQUEST_SENSE: - alloc_length = Scsi->Cdb[4]; - temp_command = Scsi->Cdb[0]; - SCSICDROM_CommandInit(Scsi, temp_command, 18, alloc_length); - - SenseBufferPointer[0]=0x80|0x70; - - if ((SCSISense.SenseKey > 0) || (cd_status < CD_STATUS_PLAYING)) + case GPCMD_REQUEST_SENSE: + SCSIPhase = SCSI_PHASE_DATAIN; + SCSIStatus = SCSI_STATUS_OK; + SCSICallback[id]=60*SCSI_TIME; + + if (cdb[4] == 0) + SCSIDevices[id].CmdBufferLength = 4; + else if (cdb[4] > 18) + SCSIDevices[id].CmdBufferLength = 18; + else + SCSIDevices[id].CmdBufferLength = cdb[4]; + + SCSIDMAResetPosition(id); + break; + + case GPCMD_READ_6: + case GPCMD_READ_10: + case GPCMD_READ_12: + cdrom_sector_ismsf = 0; + + if (cdb[0] == GPCMD_READ_6) + { + SectorLen=cdb[4]; + SectorLBA=((((uint32_t) cdb[1]) & 0x1f)<<16)|(((uint32_t) cdb[2])<<8)|((uint32_t) cdb[3]); + } + else if (cdb[0] == GPCMD_READ_10) + { + SectorLen=(cdb[7]<<8)|cdb[8]; + SectorLBA=(cdb[2]<<24)|(cdb[3]<<16)|(cdb[4]<<8)|cdb[5]; + } + else + { + SectorLen=(((uint32_t) cdb[6])<<24)|(((uint32_t) cdb[7])<<16)|(((uint32_t) cdb[8])<<8)|((uint32_t) cdb[9]); + SectorLBA=(((uint32_t) cdb[2])<<24)|(((uint32_t) cdb[3])<<16)|(((uint32_t) cdb[4])<<8)|((uint32_t) cdb[5]); + } + + if (SectorLBA > (cdrom->size() - 1)) + { + pclog("Trying to read beyond the end of disc\n"); + SCSIStatus = SCSI_STATUS_CHECK_CONDITION; + SCSISenseCodeError(SENSE_ILLEGAL_REQUEST, ASC_ILLEGAL_OPCODE, 0); + if (SCSISense.UnitAttention) { - if (SenseCompleted) - { - SenseBufferPointer[2]=SENSE_ILLEGAL_REQUEST; - SenseBufferPointer[12]=ASC_AUDIO_PLAY_OPERATION; - SenseBufferPointer[13]=ASCQ_AUDIO_PLAY_OPERATION_COMPLETED; - ScsiStatus = SCSI_STATUS_CHECK_CONDITION; - } - else - { - SenseBufferPointer[2]=SCSISense.SenseKey; - SenseBufferPointer[12]=SCSISense.Asc; - SenseBufferPointer[13]=SCSISense.Ascq; - } + SCSISenseCodeError(SENSE_UNIT_ATTENTION, ASC_MEDIUM_MAY_HAVE_CHANGED, 0); } - else if ((SCSISense.SenseKey == 0) && (cd_status >= CD_STATUS_PLAYING)) - { - SenseBufferPointer[2]=SENSE_ILLEGAL_REQUEST; - SenseBufferPointer[12]=ASC_AUDIO_PLAY_OPERATION; - SenseBufferPointer[13]=(cd_status == CD_STATUS_PLAYING) ? ASCQ_AUDIO_PLAY_OPERATION_IN_PROGRESS : ASCQ_AUDIO_PLAY_OPERATION_PAUSED; - ScsiStatus = SCSI_STATUS_CHECK_CONDITION; - } - else - { - if (SCSISense.UnitAttention) - { - SenseBufferPointer[2]=SENSE_UNIT_ATTENTION; - SenseBufferPointer[12]=ASC_MEDIUM_MAY_HAVE_CHANGED; - SenseBufferPointer[13]=0; - ScsiStatus = SCSI_STATUS_CHECK_CONDITION; - } - } - - SenseBufferPointer[7]=10; - - // pclog("REQUEST SENSE start\n"); - SCSICDROM_CommandReady(Scsi, Id, (SenseBufferLength > 0) ? SenseBufferLength : 18); - - if (SenseBufferPointer[2] == SENSE_UNIT_ATTENTION) - { - /* If the last remaining sense is unit attention, clear - that condition. */ - SCSISense.UnitAttention = 0; - } - - /* Clear the sense stuff as per the spec. */ - SCSIClearSense(temp_command); + SCSICallback[id]=50*SCSI_TIME; break; - - case GPCMD_SET_SPEED: - SCSISenseCodeOk(); - ScsiStatus = SCSI_STATUS_OK; - ScsiCallback[Id]=50*SCSI_TIME; + } + + if (!SectorLen) + { + SCSIPhase = SCSI_PHASE_STATUS; + SCSIStatus = SCSI_STATUS_OK; + SCSICallback[id]=20*SCSI_TIME; break; + } - case GPCMD_MECHANISM_STATUS: - len=(Scsi->Cdb[7]<<16)|(Scsi->Cdb[8]<<8)|Scsi->Cdb[9]; + cdrom_sector_type = 6; + cdrom_sector_flags = 0x10; - if (len == 0) - fatal("Zero allocation length to MECHANISM STATUS not impl.\n"); - - SCSICDROM_CommandInit(Scsi, Scsi->Cdb[0], 8, alloc_length); - - Scsi->SegmentData.Address[0] = 0; - Scsi->SegmentData.Address[1] = 0; - Scsi->SegmentData.Address[2] = 0; - Scsi->SegmentData.Address[3] = 0; - Scsi->SegmentData.Address[4] = 0; - Scsi->SegmentData.Address[5] = 1; - Scsi->SegmentData.Address[6] = 0; - Scsi->SegmentData.Address[7] = 0; - // len = 8; - - SCSICDROM_CommandReady(Scsi, Id, 8); - - SCSISenseCodeOk(); - ScsiStatus = SCSI_STATUS_OK; + SCSIPhase = SCSI_PHASE_DATAIN; + SCSIStatus = SCSI_STATUS_OK; + SCSICallback[id]=60*SCSI_TIME; + SCSIDevices[id].CmdBufferLength = SectorLen * 2048; + + SCSIDMAResetPosition(id); + return; + + case GPCMD_INQUIRY: + SCSIPhase = SCSI_PHASE_DATAIN; + SCSIStatus = SCSI_STATUS_OK; + SCSICallback[id]=60*SCSI_TIME; + SCSIDevices[id].CmdBufferLength = cdb[4]; + + SCSIDMAResetPosition(id); + break; + + case GPCMD_MODE_SELECT_6: + case GPCMD_MODE_SELECT_10: + SCSIPhase = SCSI_PHASE_DATAOUT; + SCSIStatus = SCSI_STATUS_OK; + SCSICallback[id]=60*SCSI_TIME; + if (cdb[0] == GPCMD_MODE_SELECT_6) + { + SCSIDevices[id].CmdBufferLength = cdb[4]; + } + else + { + SCSIDevices[id].CmdBufferLength = (cdb[7]<<8)|cdb[8]; + } + + SCSIDMAResetPosition(id); + return; + + case GPCMD_MODE_SENSE_6: + case GPCMD_MODE_SENSE_10: + SCSIPhase = SCSI_PHASE_DATAIN; + SCSIStatus = SCSI_STATUS_OK; + SCSICallback[id]=60*SCSI_TIME; + if (cdb[0] == GPCMD_MODE_SENSE_6) + { + SCSIDevices[id].CmdBufferLength = cdb[4]; + } + else + { + SCSIDevices[id].CmdBufferLength = (cdb[7]<<8)|cdb[8]; + } + + SCSIDMAResetPosition(id); + return; + + case GPCMD_START_STOP_UNIT: + if (cdb[4]!=2 && cdb[4]!=3 && cdb[4]) + { + SCSIStatus = SCSI_STATUS_CHECK_CONDITION; + SCSISenseCodeError(SENSE_ILLEGAL_REQUEST, ASC_ILLEGAL_OPCODE, 0x00); + if (SCSISense.UnitAttention) + { + SCSISenseCodeError(SENSE_UNIT_ATTENTION, ASC_MEDIUM_MAY_HAVE_CHANGED, 0); + } + SCSICallback[id]=50*SCSI_TIME; break; + } + if (!cdb[4]) cdrom->stop(); + else if (cdb[4]==2) cdrom->eject(); + else cdrom->load(); + + SCSIPhase = SCSI_PHASE_STATUS; + SCSIStatus = SCSI_STATUS_OK; + SCSICallback[id]=50*SCSI_TIME; + SCSIDevices[id].CmdBufferLength = 0; + break; + + case GPCMD_PREVENT_REMOVAL: + SCSIPhase = SCSI_PHASE_STATUS; + SCSIStatus = SCSI_STATUS_OK; + SCSICallback[id]=50*SCSI_TIME; + SCSIDevices[id].CmdBufferLength = 0; + break; + + case GPCMD_READ_CDROM_CAPACITY: + SCSIPhase = SCSI_PHASE_DATAIN; + SCSIStatus = SCSI_STATUS_OK; + SCSICallback[id]=60*SCSI_TIME; + SCSIDevices[id].CmdBufferLength = 8; + + SCSIDMAResetPosition(id); + break; + + case GPCMD_SEEK: + SectorLBA = (cdb[3]<<16)|(cdb[4]<<8)|cdb[5]; + cdrom->seek(SectorLBA); + + SCSIPhase = SCSI_PHASE_STATUS; + SCSIStatus = SCSI_STATUS_OK; + SCSICallback[id]=50*SCSI_TIME; + SCSIDevices[id].CmdBufferLength = 0; + break; + + case GPCMD_READ_SUBCHANNEL: + SCSIPhase = SCSI_PHASE_DATAIN; + SCSIStatus = SCSI_STATUS_OK; + SCSICallback[id]=1000*SCSI_TIME; + SCSIDevices[id].CmdBufferLength = (cdb[7]<<8)|cdb[8]; + + if (!(cdb[2] & 0x40)) + SCSIDevices[id].CmdBufferLength = 4; + else + SCSIDevices[id].CmdBufferLength = 16; + + SCSIDMAResetPosition(id); + break; + + case GPCMD_READ_TOC_PMA_ATIP: + { + int len; - case GPCMD_READ_TOC_PMA_ATIP: - TocFormat = Scsi->Cdb[2] & 0xf; - if (TocFormat == 0) - TocFormat = (Scsi->Cdb[9]>>6) & 3; - switch (TocFormat) + switch (SCSICDROM_TOC(id, cdb)) { case 0: /*Normal*/ - len = Scsi->Cdb[8]|(Scsi->Cdb[7]<<8); - len = cdrom->readtoc(Scsi->SegmentData.Address, Scsi->Cdb[6], Msf, len, 0); + len = cdb[8]|(cdb[7]<<8); break; - + case 1: /*Multi session*/ - len = Scsi->Cdb[8]|(Scsi->Cdb[7]<<8); - len = cdrom->readtoc_session(Scsi->SegmentData.Address, Msf, len); - Scsi->SegmentData.Address[0] = 0; - Scsi->SegmentData.Address[1] = 0xA; + len = cdb[8]|(cdb[7]<<8); break; - + case 2: /*Raw*/ - len = Scsi->Cdb[8]|(Scsi->Cdb[7]<<8); - len = cdrom->readtoc_raw(Scsi->SegmentData.Address, len); + len = cdb[8]|(cdb[7]<<8); break; - + default: + SCSIStatus = SCSI_STATUS_CHECK_CONDITION; SCSISenseCodeError(SENSE_ILLEGAL_REQUEST, ASC_INV_FIELD_IN_CMD_PACKET, 0x00); - ScsiStatus = SCSI_STATUS_CHECK_CONDITION; - if (SCSISense.SenseKey == SENSE_UNIT_ATTENTION) - old_cdrom_drive = cdrom_drive; - ScsiCallback[Id]=50*SCSI_TIME; - break; - } - - Scsi->BufferLength=len; - ScsiCallback[Id]=60*SCSI_TIME; - Scsi->SegmentData.Length=len; - - SegmentBufferCopyFromBuf(&Scsi->SegmentBuffer, Scsi->SegmentData.Address, Scsi->SegmentData.Length); - - SCSISenseCodeOk(); - ScsiStatus = SCSI_STATUS_OK; - break; - - case GPCMD_READ_CD: - case GPCMD_READ_CD_MSF: - if (Scsi->Cdb[0] == GPCMD_READ_CD_MSF) - { - Scsi->SectorLba=MSFtoLBA(Scsi->Cdb[3],Scsi->Cdb[4],Scsi->Cdb[5]); - Scsi->SectorLen=MSFtoLBA(Scsi->Cdb[6],Scsi->Cdb[7],Scsi->Cdb[8]); - - Scsi->SectorLen -= Scsi->SectorLba; - Scsi->SectorLen++; - - cdrom_sector_ismsf = 1; - } - else - { - Scsi->SectorLen=(Scsi->Cdb[6]<<16)|(Scsi->Cdb[7]<<8)|Scsi->Cdb[8]; - Scsi->SectorLba=(Scsi->Cdb[2]<<24)|(Scsi->Cdb[3]<<16)|(Scsi->Cdb[4]<<8)|Scsi->Cdb[5]; - - cdrom_sector_ismsf = 0; - } - - cdrom_sector_type = (Scsi->Cdb[1] >> 2) & 7; - cdrom_sector_flags = Scsi->Cdb[9] || (((uint32_t) Scsi->Cdb[10]) << 8); - - ret = SCSICDROMReadData(Scsi, Scsi->SegmentData.Address); - - if (!ret) - { - SCSISenseCodeError(SENSE_ILLEGAL_REQUEST, ASC_ILLEGAL_OPCODE, 0); - ScsiStatus = SCSI_STATUS_CHECK_CONDITION; - if (SCSISense.SenseKey == SENSE_UNIT_ATTENTION) - old_cdrom_drive = cdrom_drive; - ScsiCallback[Id]=50*SCSI_TIME; - break; - } - - pclog("SCSI Read CD command: LBA %04X, Length %04X\n", Scsi->SectorLba, Scsi->SectorLen); - - Scsi->SectorLba++; - Scsi->SectorLen--; - - Scsi->BufferLength=cdrom_sector_size; - ScsiCallback[Id]=60*SCSI_TIME; - Scsi->SegmentData.Length=cdrom_sector_size; - - SegmentBufferCopyFromBuf(&Scsi->SegmentBuffer, Scsi->SegmentData.Address, Scsi->SegmentData.Length); - SCSIReadTransfer(Scsi, Id); - - SCSISenseCodeOk(); - ScsiStatus = SCSI_STATUS_OK; - return; - - case GPCMD_READ_6: - case GPCMD_READ_10: - case GPCMD_READ_12: - cdrom_sector_ismsf = 0; - - if (Scsi->Cdb[0] == GPCMD_READ_6) - { - Scsi->SectorLen=Scsi->Cdb[4]; - Scsi->SectorLba=((((uint32_t) Scsi->Cdb[1]) & 0x1f)<<16)|(((uint32_t) Scsi->Cdb[2])<<8)|((uint32_t) Scsi->Cdb[3]); - } - else if (Scsi->Cdb[0] == GPCMD_READ_10) - { - Scsi->SectorLen=(Scsi->Cdb[7]<<8)|Scsi->Cdb[8]; - Scsi->SectorLba=(Scsi->Cdb[2]<<24)|(Scsi->Cdb[3]<<16)|(Scsi->Cdb[4]<<8)|Scsi->Cdb[5]; - } - else - { - Scsi->SectorLen=(((uint32_t) Scsi->Cdb[6])<<24)|(((uint32_t) Scsi->Cdb[7])<<16)|(((uint32_t) Scsi->Cdb[8])<<8)|((uint32_t) Scsi->Cdb[9]); - Scsi->SectorLba=(((uint32_t) Scsi->Cdb[2])<<24)|(((uint32_t) Scsi->Cdb[3])<<16)|(((uint32_t) Scsi->Cdb[4])<<8)|((uint32_t) Scsi->Cdb[5]); - } - - if (!Scsi->SectorLen) - { - SCSISenseCodeOk(); - ScsiStatus = SCSI_STATUS_OK; - ScsiCallback[Id]=20*SCSI_TIME; - break; - } - - cdrom_sector_type = 0; - cdrom_sector_flags = 0x10; - - pclog("SCSI Read command: LBA %04X, Length %04X\n", Scsi->SectorLba, Scsi->SectorLen); - - ret = SCSICDROMReadData(Scsi, Scsi->SegmentData.Address); - - Scsi->SectorLba++; - Scsi->SectorLen--; - - Scsi->BufferLength=2048; - ScsiCallback[Id]=60*SCSI_TIME; - Scsi->SegmentData.Length=2048; - - SegmentBufferCopyFromBuf(&Scsi->SegmentBuffer, Scsi->SegmentData.Address, Scsi->SegmentData.Length); - SCSIReadTransfer(Scsi, Id); - - SCSISenseCodeOk(); - ScsiStatus = SCSI_STATUS_OK; - break; - - case GPCMD_READ_HEADER: - if (Msf) - { - SCSISenseCodeError(SENSE_ILLEGAL_REQUEST, ASC_ILLEGAL_OPCODE, 0x00); - ScsiStatus = SCSI_STATUS_CHECK_CONDITION; - if (SCSISense.SenseKey == SENSE_UNIT_ATTENTION) - old_cdrom_drive = cdrom_drive; - ScsiCallback[Id]=50*SCSI_TIME; - break; - } - for (c=0;c<4;c++) - Scsi->SegmentData.Address[c+4] = Scsi->SegmentData.Address[c+2]; - - Scsi->SegmentData.Address[0] = 1; /*2048 bytes user data*/ - Scsi->SegmentData.Address[1] = Scsi->SegmentData.Address[2] = Scsi->SegmentData.Address[3] = 0; - - Scsi->BufferLength=8; - ScsiCallback[Id]=60*SCSI_TIME; - Scsi->SegmentData.Length=8; - - SegmentBufferCopyFromBuf(&Scsi->SegmentBuffer, Scsi->SegmentData.Address, Scsi->SegmentData.Length); - SCSIReadTransfer(Scsi, Id); - - SCSISenseCodeOk(); - ScsiStatus = SCSI_STATUS_OK; - return; - - case GPCMD_MODE_SENSE_6: - case GPCMD_MODE_SENSE_10: - temp_command = Scsi->Cdb[0]; - - if (Scsi->Cdb[0] == GPCMD_MODE_SENSE_6) - { - len = Scsi->Cdb[4]; - } - else - { - len = (Scsi->Cdb[8]|(Scsi->Cdb[7]<<8)); - } - - Temp=Scsi->Cdb[2] & 0x3F; - - memset(Scsi->SegmentData.Address, 0, len); - alloc_length = len; - - if (!(mode_sense_pages[Temp] & IMPLEMENTED)) - { - SCSISenseCodeError(SENSE_ILLEGAL_REQUEST, ASC_INV_FIELD_IN_CMD_PACKET, 0x00); - ScsiStatus = SCSI_STATUS_CHECK_CONDITION; - ScsiCallback[Id]=50*SCSI_TIME; + if (SCSISense.UnitAttention) + { + SCSISenseCodeError(SENSE_UNIT_ATTENTION, ASC_MEDIUM_MAY_HAVE_CHANGED, 0); + } + SCSICallback[id]=50*SCSI_TIME; return; } - - if (Scsi->Cdb[0] == GPCMD_MODE_SENSE_6) - { - len = SCSICDROMModeSense(Scsi->SegmentData.Address, 4, Temp); - Scsi->SegmentData.Address[0] = Scsi->SegmentData.Length - 1; - Scsi->SegmentData.Address[1] = 3; /*120mm data CD-ROM*/ - } - else - { - len = SCSICDROMModeSense(Scsi->SegmentData.Address, 8, Temp); - Scsi->SegmentData.Address[0] = (Scsi->SegmentData.Length - 2)>>8; - Scsi->SegmentData.Address[1] = (Scsi->SegmentData.Length - 2)&255; - Scsi->SegmentData.Address[2] = 3; /*120mm data CD-ROM*/ - } - - SCSICDROM_CommandInit(Scsi, temp_command, len, alloc_length); - - SCSICDROM_CommandReady(Scsi, Id, len); + SCSIPhase = SCSI_PHASE_DATAIN; + SCSIStatus = SCSI_STATUS_OK; + SCSICallback[id]=60*SCSI_TIME; + SCSIDevices[id].CmdBufferLength = len; + + SCSIDMAResetPosition(id); + } + return; + + case GPCMD_READ_HEADER: + SCSIPhase = SCSI_PHASE_DATAIN; + SCSIStatus = SCSI_STATUS_OK; + SCSICallback[id]=60*SCSI_TIME; + SCSIDevices[id].CmdBufferLength = 8; - SCSISenseCodeOk(); - ScsiStatus = SCSI_STATUS_OK; - return; - - case GPCMD_MODE_SELECT_6: - case GPCMD_MODE_SELECT_10: - if (Scsi->Cdb[0] == GPCMD_MODE_SELECT_6) - { - len = Scsi->Cdb[4]; - prefix_len = 6; - } - else - { - len = (Scsi->Cdb[7]<<8)|Scsi->Cdb[8]; - prefix_len = 10; - } - page_current = Scsi->Cdb[2]; - if (page_flags[page_current] & PAGE_CHANGEABLE) - page_flags[GPMODE_CDROM_AUDIO_PAGE] |= PAGE_CHANGED; + SCSIDMAResetPosition(id); + return; + + case GPCMD_PLAY_AUDIO_10: + case GPCMD_PLAY_AUDIO_MSF: + case GPCMD_PLAY_AUDIO_12: + if (cdb[0] == GPCMD_PLAY_AUDIO_10) + { + SectorLBA = (cdb[2]<<24)|(cdb[3]<<16)|(cdb[4]<<8)|cdb[5]; + SectorLen = (cdb[7]<<8)|cdb[8]; + } + else if (cdb[0] == GPCMD_PLAY_AUDIO_MSF) + { + SectorLBA = (cdb[3]<<16)|(cdb[4]<<8)|cdb[5]; + SectorLen = (cdb[6]<<16)|(cdb[7]<<8)|cdb[8]; + } + else + { + SectorLBA = (cdb[3]<<16)|(cdb[4]<<8)|cdb[5]; + SectorLen = (cdb[7]<<16)|(cdb[8]<<8)|cdb[9]; + } - Scsi->BufferLength=len; - ScsiCallback[Id]=60*SCSI_TIME; - Scsi->SegmentData.Length=len; - - SegmentBufferCopyToBuf(&Scsi->SegmentBuffer, Scsi->SegmentData.Address, Scsi->SegmentData.Length); - SCSIWriteTransfer(Scsi, Id); - - SCSISenseCodeOk(); - ScsiStatus = SCSI_STATUS_OK; - return; - - case GPCMD_GET_CONFIGURATION: - { - temp_command = Scsi->Cdb[0]; - /* XXX: could result in alignment problems in some architectures */ - len = (Scsi->Cdb[7]<<8)|Scsi->Cdb[8]; - alloc_length = len; - - Index = 0; - - /* only feature 0 is supported */ - if (Scsi->Cdb[2] != 0 || Scsi->Cdb[3] != 0) - { - SCSISenseCodeError(SENSE_ILLEGAL_REQUEST, ASC_INV_FIELD_IN_CMD_PACKET, 0x00); - ScsiStatus = SCSI_STATUS_CHECK_CONDITION; - if (SCSISense.SenseKey == SENSE_UNIT_ATTENTION) - old_cdrom_drive = cdrom_drive; - ScsiCallback[Id]=50*SCSI_TIME; - return; - } - - /* - * XXX: avoid overflow for io_buffer if len is bigger than - * the size of that buffer (dimensioned to max number of - * sectors to transfer at once) - * - * Only a problem if the feature/profiles grow. - */ - if (alloc_length > 512) /* XXX: assume 1 sector */ - alloc_length = 512; - - memset(Scsi->SegmentData.Address, 0, alloc_length); - /* - * the number of sectors from the media tells us which profile - * to use as current. 0 means there is no media - */ - if (len > CD_MAX_SECTORS ) - { - Scsi->SegmentData.Address[6] = (MMC_PROFILE_DVD_ROM >> 8) & 0xff; - Scsi->SegmentData.Address[7] = MMC_PROFILE_DVD_ROM & 0xff; - } - else if (len <= CD_MAX_SECTORS) - { - Scsi->SegmentData.Address[6] = (MMC_PROFILE_CD_ROM >> 8) & 0xff; - Scsi->SegmentData.Address[7] = MMC_PROFILE_CD_ROM & 0xff; - } - Scsi->SegmentData.Address[10] = 0x02 | 0x01; /* persistent and current */ - alloc_length = 12; /* headers: 8 + 4 */ - alloc_length += SCSICDROMSetProfile(Scsi->SegmentData.Address, &Index, MMC_PROFILE_DVD_ROM); - alloc_length += SCSICDROMSetProfile(Scsi->SegmentData.Address, &Index, MMC_PROFILE_CD_ROM); - Scsi->SegmentData.Address[0] = ((alloc_length-4) >> 24) & 0xff; - Scsi->SegmentData.Address[1] = ((alloc_length-4) >> 16) & 0xff; - Scsi->SegmentData.Address[2] = ((alloc_length-4) >> 8) & 0xff; - Scsi->SegmentData.Address[3] = (alloc_length-4) & 0xff; - - SCSICDROM_CommandInit(Scsi, temp_command, len, alloc_length); - - SCSICDROM_CommandReady(Scsi, Id, len); - - SCSISenseCodeOk(); - ScsiStatus = SCSI_STATUS_OK; - } + if ((cdrom_drive < 1) || (cdrom_drive == 200) || (cd_status <= CD_STATUS_DATA_ONLY) || + !cdrom->is_track_audio(SectorLBA, (cdb[0] == GPCMD_PLAY_AUDIO_MSF) ? 1 : 0)) + { + SCSIStatus = SCSI_STATUS_CHECK_CONDITION; + SCSISenseCodeError(SENSE_ILLEGAL_REQUEST, ASC_ILLEGAL_MODE_FOR_THIS_TRACK, 0x00); + SCSICallback[id]=50*SCSI_TIME; break; - - case GPCMD_GET_EVENT_STATUS_NOTIFICATION: - { - struct - { - uint8_t opcode; - uint8_t polled; - uint8_t reserved2[2]; - uint8_t class; - uint8_t reserved3[2]; - uint16_t len; - uint8_t control; - } *gesn_cdb; - - struct - { - uint16_t len; - uint8_t notification_class; - uint8_t supported_events; - } *gesn_event_header; - unsigned int used_len; - - gesn_cdb = (void *)Scsi->Cdb; - gesn_event_header = (void *)Scsi->SegmentData.Address; - - /* It is fine by the MMC spec to not support async mode operations */ - if (!(gesn_cdb->polled & 0x01)) - { /* asynchronous mode */ - /* Only pollign is supported, asynchronous mode is not. */ - SCSISenseCodeError(SENSE_ILLEGAL_REQUEST, ASC_INV_FIELD_IN_CMD_PACKET, 0x00); - ScsiStatus = SCSI_STATUS_CHECK_CONDITION; - ScsiCallback[Id]=50*SCSI_TIME; - return; - } - - /* polling mode operation */ - - /* - * These are the supported events. - * - * We currently only support requests of the 'media' type. - * Notification class requests and supported event classes are bitmasks, - * but they are built from the same values as the "notification class" - * field. - */ - gesn_event_header->supported_events = 1 << GESN_MEDIA; - - /* - * We use |= below to set the class field; other bits in this byte - * are reserved now but this is useful to do if we have to use the - * reserved fields later. - */ - gesn_event_header->notification_class = 0; - - /* - * Responses to requests are to be based on request priority. The - * notification_class_request_type enum above specifies the - * priority: upper elements are higher prio than lower ones. - */ - if (gesn_cdb->class & (1 << GESN_MEDIA)) - { - gesn_event_header->notification_class |= GESN_MEDIA; - used_len = SCSICDROMEventStatus(Scsi->SegmentData.Address); - } - else - { - gesn_event_header->notification_class = 0x80; /* No event available */ - used_len = sizeof(*gesn_event_header); - } - gesn_event_header->len = used_len - sizeof(*gesn_event_header); - - SCSICDROM_CommandInit(Scsi, temp_command, len, alloc_length); - - SCSICDROM_CommandReady(Scsi, Id, len); - - SCSISenseCodeOk(); - ScsiStatus = SCSI_STATUS_OK; - } - break; - - case GPCMD_READ_DISC_INFORMATION: - Scsi->SegmentData.Address[1] = 32; - Scsi->SegmentData.Address[2] = 0xe; /* last session complete, disc finalized */ - Scsi->SegmentData.Address[3] = 1; /* first track on disc */ - Scsi->SegmentData.Address[4] = 1; /* # of sessions */ - Scsi->SegmentData.Address[5] = 1; /* first track of last session */ - Scsi->SegmentData.Address[6] = 1; /* last track of last session */ - Scsi->SegmentData.Address[7] = 0x20; /* unrestricted use */ - Scsi->SegmentData.Address[8] = 0x00; /* CD-ROM */ - - len=34; - Scsi->BufferLength=len; - ScsiCallback[Id]=60*SCSI_TIME; - Scsi->SegmentData.Length=len; + } - SegmentBufferCopyFromBuf(&Scsi->SegmentBuffer, Scsi->SegmentData.Address, Scsi->SegmentData.Length); - SCSIReadTransfer(Scsi, Id); + cdrom->playaudio(SectorLBA, SectorLen, (cdb[0] == GPCMD_PLAY_AUDIO_MSF) ? 1 : 0); + SCSIPhase = SCSI_PHASE_STATUS; + SCSIStatus = SCSI_STATUS_OK; + SCSICallback[id]=50*SCSI_TIME; + SCSIDevices[id].CmdBufferLength = 0; + break; + + case GPCMD_GET_CONFIGURATION: + SCSIPhase = SCSI_PHASE_DATAIN; + SCSIStatus = SCSI_STATUS_OK; + SCSICallback[id]=60*SCSI_TIME; + SCSIDevices[id].CmdBufferLength = (cdb[7]<<8)|cdb[8]; + + SCSIDMAResetPosition(id); + break; + + case GPCMD_GET_EVENT_STATUS_NOTIFICATION: + SCSIPhase = SCSI_PHASE_DATAIN; + SCSIStatus = SCSI_STATUS_OK; + SCSICallback[id]=60*SCSI_TIME; + SCSIDevices[id].CmdBufferLength = 8; + + SCSIDMAResetPosition(id); + break; + + case GPCMD_PAUSE_RESUME: + if (cdb[8]&1) cdrom->resume(); + else cdrom->pause(); + SCSIPhase = SCSI_PHASE_STATUS; + SCSIStatus = SCSI_STATUS_OK; + SCSICallback[id]=50*SCSI_TIME; + SCSIDevices[id].CmdBufferLength = 0; + break; + + case GPCMD_STOP_PLAY_SCAN: + cdrom->stop(); + SCSIPhase = SCSI_PHASE_STATUS; + SCSIStatus = SCSI_STATUS_OK; + SCSICallback[id]=50*SCSI_TIME; + SCSIDevices[id].CmdBufferLength = 0; + break; + + case GPCMD_READ_DISC_INFORMATION: + SCSIPhase = SCSI_PHASE_DATAIN; + SCSIStatus = SCSI_STATUS_OK; + SCSICallback[id]=60*SCSI_TIME; + SCSIDevices[id].CmdBufferLength = 34; + + SCSIDMAResetPosition(id); + break; + + case GPCMD_READ_DVD_STRUCTURE: + { + int len; - SCSISenseCodeOk(); - ScsiStatus = SCSI_STATUS_OK; - break; - - case GPCMD_PLAY_AUDIO_10: - case GPCMD_PLAY_AUDIO_12: - case GPCMD_PLAY_AUDIO_MSF: - /*This is apparently deprecated in the SCSI spec, and apparently - has been since 1995 (!). Hence I'm having to guess most of it*/ - if (Scsi->Cdb[0] == GPCMD_PLAY_AUDIO_10) - { - pos = (Scsi->Cdb[2]<<24)|(Scsi->Cdb[3]<<16)|(Scsi->Cdb[4]<<8)|Scsi->Cdb[5]; - len = (Scsi->Cdb[7]<<8)|Scsi->Cdb[8]; - } - else if (Scsi->Cdb[0] == GPCMD_PLAY_AUDIO_MSF) - { - pos = (Scsi->Cdb[3]<<16)|(Scsi->Cdb[4]<<8)|Scsi->Cdb[5]; - len = (Scsi->Cdb[6]<<16)|(Scsi->Cdb[7]<<8)|Scsi->Cdb[8]; - } - else - { - pos = (Scsi->Cdb[3]<<16)|(Scsi->Cdb[4]<<8)|Scsi->Cdb[5]; - len = (Scsi->Cdb[7]<<16)|(Scsi->Cdb[8]<<8)|Scsi->Cdb[9]; - } - - - if ((cdrom_drive < 1) || (cdrom_drive == 200) || (cd_status <= CD_STATUS_DATA_ONLY) || - !cdrom->is_track_audio(pos, (Scsi->Cdb[0] == GPCMD_PLAY_AUDIO_MSF) ? 1 : 0)) - { - SCSISenseCodeError(SENSE_ILLEGAL_REQUEST, ASC_ILLEGAL_MODE_FOR_THIS_TRACK, 0x00); - ScsiStatus = SCSI_STATUS_CHECK_CONDITION; - ScsiCallback[Id]=50*SCSI_TIME; - break; - } - - cdrom->playaudio(pos, len, (Scsi->Cdb[0] == GPCMD_PLAY_AUDIO_MSF) ? 1 : 0); + len = (cdb[6]<<24)|(cdb[7]<<16)|(cdb[8]<<8)|cdb[9]; - Scsi->PacketStatus = 3; - ScsiCallback[Id]=50*SCSI_TIME; - - SCSISenseCodeOk(); - ScsiStatus = SCSI_STATUS_OK; - break; - - case GPCMD_READ_SUBCHANNEL: - Temp = Scsi->Cdb[2] & 0x40; - if (Scsi->Cdb[3] != 1) + if (cdb[7] < 0xff) { - SCSISenseCodeError(SENSE_ILLEGAL_REQUEST, ASC_ILLEGAL_OPCODE, 0x00); - ScsiStatus = SCSI_STATUS_CHECK_CONDITION; - if (SCSISense.SenseKey == SENSE_UNIT_ATTENTION) - old_cdrom_drive = cdrom_drive; - ScsiCallback[Id]=50*SCSI_TIME; - break; - } - pos = 0; - Scsi->SegmentData.Address[pos++] = 0; - Scsi->SegmentData.Address[pos++] = 0; /*Audio status*/ - Scsi->SegmentData.Address[pos++] = 0; Scsi->SegmentData.Address[pos++] = 0; /*Subchannel length*/ - Scsi->SegmentData.Address[pos++] = 1; /*Format code*/ - Scsi->SegmentData.Address[1] = cdrom->getcurrentsubchannel(&Scsi->SegmentData.Address[5], Msf); - len = 16; - if (!Temp) - len = 4; - - Scsi->BufferLength=len; - ScsiCallback[Id]=1000*SCSI_TIME; - Scsi->SegmentData.Length=len; - - SegmentBufferCopyFromBuf(&Scsi->SegmentBuffer, Scsi->SegmentData.Address, Scsi->SegmentData.Length); - SCSIReadTransfer(Scsi, Id); - - SCSISenseCodeOk(); - ScsiStatus = SCSI_STATUS_OK; - break; - - case GPCMD_READ_DVD_STRUCTURE: - temp_command = Scsi->Cdb[0]; - Media = Scsi->Cdb[1]; - Format = Scsi->Cdb[7]; - - len = (Scsi->Cdb[6]<<24)|(Scsi->Cdb[7]<<16)|(Scsi->Cdb[8]<<8)|Scsi->Cdb[9]; - alloc_length = len; - - if (Format < 0xff) { if (len <= CD_MAX_SECTORS) { + SCSIStatus = SCSI_STATUS_CHECK_CONDITION; SCSISenseCodeError(SENSE_ILLEGAL_REQUEST, ASC_INCOMPATIBLE_FORMAT, 0x00); - ScsiStatus = SCSI_STATUS_CHECK_CONDITION; - ScsiCallback[Id]=50*SCSI_TIME; + SCSICallback[id]=50*SCSI_TIME; break; } - else + else { + SCSIStatus = SCSI_STATUS_CHECK_CONDITION; SCSISenseCodeError(SENSE_ILLEGAL_REQUEST, ASC_INV_FIELD_IN_CMD_PACKET, 0x00); - ScsiStatus = SCSI_STATUS_CHECK_CONDITION; - if (SCSISense.SenseKey == SENSE_UNIT_ATTENTION) - old_cdrom_drive = cdrom_drive; - ScsiCallback[Id]=50*SCSI_TIME; + if (SCSISense.UnitAttention) + { + SCSISenseCodeError(SENSE_UNIT_ATTENTION, ASC_MEDIUM_MAY_HAVE_CHANGED, 0); + } + SCSICallback[id]=50*SCSI_TIME; return; } - } - - memset(Scsi->SegmentData.Address, 0, alloc_length > 256 * 512 + 4 ? 256 * 512 + 4 : alloc_length); - - switch (Format) - { - case 0x00 ... 0x7f: - case 0xff: - if (Media == 0) - { - DVDRet = SCSICDROMReadDVDStructure(Format, Scsi->Cdb, Scsi->SegmentData.Address); - - if (DVDRet < 0) - { - SCSISenseCodeError(SENSE_ILLEGAL_REQUEST, -DVDRet, 0x00); - ScsiStatus = SCSI_STATUS_CHECK_CONDITION; - ScsiCallback[Id]=50*SCSI_TIME; - return; - } - else - { - SCSICDROM_CommandInit(Scsi, temp_command, len, alloc_length); - SCSICDROM_CommandReady(Scsi, Id, len); - SCSISenseCodeOk(); - ScsiStatus = SCSI_STATUS_OK; - } - break; - } - /* TODO: BD support, fall through for now */ - - /* Generic disk structures */ - case 0x80: /* TODO: AACS volume identifier */ - case 0x81: /* TODO: AACS media serial number */ - case 0x82: /* TODO: AACS media identifier */ - case 0x83: /* TODO: AACS media key block */ - case 0x90: /* TODO: List of recognized format layers */ - case 0xc0: /* TODO: Write protection status */ - default: - SCSISenseCodeError(SENSE_ILLEGAL_REQUEST, ASC_INV_FIELD_IN_CMD_PACKET, 0x00); - ScsiStatus = SCSI_STATUS_CHECK_CONDITION; - if (SCSISense.SenseKey == SENSE_UNIT_ATTENTION) - old_cdrom_drive = cdrom_drive; - ScsiCallback[Id]=50*SCSI_TIME; - return; - } - break; - - case GPCMD_START_STOP_UNIT: - if (Scsi->Cdb[4]!=2 && Scsi->Cdb[4]!=3 && Scsi->Cdb[4]) - { - SCSISenseCodeError(SENSE_ILLEGAL_REQUEST, ASC_ILLEGAL_OPCODE, 0x00); - ScsiStatus = SCSI_STATUS_CHECK_CONDITION; - if (SCSISense.SenseKey == SENSE_UNIT_ATTENTION) - old_cdrom_drive = cdrom_drive; - ScsiCallback[Id]=50*SCSI_TIME; - break; - } - if (!Scsi->Cdb[4]) cdrom->stop(); - else if (Scsi->Cdb[4]==2) cdrom->eject(); - else cdrom->load(); - ScsiCallback[Id]=50*SCSI_TIME; - SCSISenseCodeOk(); - ScsiStatus = SCSI_STATUS_OK; - break; - - case GPCMD_INQUIRY: - PageCode = Scsi->Cdb[2]; - max_len = Scsi->Cdb[4]; - alloc_length = max_len; - temp_command = Scsi->Cdb[0]; - - pclog("SCSI Inquiry Page %02X\n", Scsi->Cdb[1] & 1); - if (Scsi->Cdb[1] & 1) - { - PreambleLen = 4; - SizeIndex = 3; - - Scsi->SegmentData.Address[Idx++] = 5; - Scsi->SegmentData.Address[Idx++] = PageCode; - Scsi->SegmentData.Address[Idx++] = 0; - - Idx++; - - pclog("SCSI Inquiry Page Code %02X\n", PageCode); - switch (PageCode) - { - case 0x00: - Scsi->SegmentData.Address[Idx++] = 0x00; - Scsi->SegmentData.Address[Idx++] = 0x00; - Scsi->SegmentData.Address[Idx++] = 2; - Scsi->SegmentData.Address[Idx++] = 0x00; - Scsi->SegmentData.Address[Idx++] = 0x80; - Scsi->SegmentData.Address[Idx++] = 0x83; - break; - - case 0x83: - if (Idx + 24 > max_len) - { - SCSISenseCodeError(SENSE_ILLEGAL_REQUEST, ASC_DATA_PHASE_ERROR, 0); - ScsiStatus = SCSI_STATUS_CHECK_CONDITION; - return; - } - Scsi->SegmentData.Address[Idx++] = 0x02; - Scsi->SegmentData.Address[Idx++] = 0x00; - Scsi->SegmentData.Address[Idx++] = 0x00; - Scsi->SegmentData.Address[Idx++] = 20; - ScsiPadStr8(Scsi->SegmentData.Address + Idx, 20, "3097165"); /* Serial */ - Idx += 20; - - if (Idx + 72 > max_len) - { - goto SCSIOut; - } - Scsi->SegmentData.Address[Idx++] = 0x02; - Scsi->SegmentData.Address[Idx++] = 0x01; - Scsi->SegmentData.Address[Idx++] = 0x00; - Scsi->SegmentData.Address[Idx++] = 68; - ScsiPadStr8(Scsi->SegmentData.Address + Idx, 8, "Sony"); /* Vendor */ - Idx += 8; - ScsiPadStr8(Scsi->SegmentData.Address + Idx, 40, "CDU-76S 1.0"); /* Product */ - Idx += 40; - ScsiPadStr8(Scsi->SegmentData.Address + Idx, 20, "3097165"); /* Product */ - Idx += 20; - break; - - default: - SCSISenseCodeError(SENSE_ILLEGAL_REQUEST, ASC_INV_FIELD_IN_CMD_PACKET, 0x00); - ScsiStatus = SCSI_STATUS_CHECK_CONDITION; - return; - } - } - else - { - PreambleLen = 5; - SizeIndex = 4; - - Scsi->SegmentData.Address[0] = 5; /*CD-ROM*/ - Scsi->SegmentData.Address[1] = 0x80; /*Removable*/ - Scsi->SegmentData.Address[2] = 0; - Scsi->SegmentData.Address[3] = 0x21; - Scsi->SegmentData.Address[4] = 31; - Scsi->SegmentData.Address[5] = 0; - Scsi->SegmentData.Address[6] = 0; - Scsi->SegmentData.Address[7] = 0; - ScsiPadStr8(Scsi->SegmentData.Address + 8, 8, "Sony"); /* Vendor */ - ScsiPadStr8(Scsi->SegmentData.Address + 16, 16, "CDU-76S"); /* Product */ - ScsiPadStr8(Scsi->SegmentData.Address + 32, 4, "1.0"); /* Revision */ - - Idx = 36; - } - -SCSIOut: - Scsi->SegmentData.Address[SizeIndex] = Idx - PreambleLen; - Scsi->SegmentData.Length=Idx; - - SCSICDROM_CommandInit(Scsi, temp_command, len, alloc_length); - - SCSICDROM_CommandReady(Scsi, Id, len); + } - SCSISenseCodeOk(); - ScsiStatus = SCSI_STATUS_OK; - break; + SCSIPhase = SCSI_PHASE_DATAIN; + SCSIStatus = SCSI_STATUS_OK; + SCSICallback[id]=60*SCSI_TIME; + SCSIDevices[id].CmdBufferLength = len; - case GPCMD_PREVENT_REMOVAL: - ScsiCallback[Id]=50*SCSI_TIME; - SCSISenseCodeOk(); - ScsiStatus = SCSI_STATUS_OK; - break; + SCSIDMAResetPosition(id); + } + break; + + case GPCMD_READ_CD_MSF: + case GPCMD_READ_CD: + if (cdb[0] == GPCMD_READ_CD_MSF) + { + SectorLBA=MSFtoLBA(cdb[3],cdb[4],cdb[5]); + SectorLen=MSFtoLBA(cdb[6],cdb[7],cdb[8]); - case GPCMD_PAUSE_RESUME: - if (Scsi->Cdb[8]&1) cdrom->resume(); - else cdrom->pause(); - ScsiCallback[Id]=50*SCSI_TIME; - SCSISenseCodeOk(); - ScsiStatus = SCSI_STATUS_OK; - break; + SectorLen -= SectorLBA; + SectorLen++; + + cdrom_sector_ismsf = 1; + } + else + { + SectorLen=(cdb[6]<<16)|(cdb[7]<<8)|cdb[8]; + SectorLBA=(cdb[2]<<24)|(cdb[3]<<16)|(cdb[4]<<8)|cdb[5]; - case GPCMD_SEEK: - pos = (Scsi->Cdb[3]<<16)|(Scsi->Cdb[4]<<8)|Scsi->Cdb[5]; - cdrom->seek(pos); - ScsiCallback[Id]=50*SCSI_TIME; - SCSISenseCodeOk(); - ScsiStatus = SCSI_STATUS_OK; - break; - - case GPCMD_READ_CDROM_CAPACITY: - SCSICDROM_CommandInit(Scsi, temp_command, 8, 8); - Size = cdrom->size(); - Scsi->SegmentData.Address[0] = (Size >> 24); - Scsi->SegmentData.Address[1] = (Size >> 16); - Scsi->SegmentData.Address[2] = (Size >> 8); - Scsi->SegmentData.Address[3] = Size & 0xFF; - Scsi->SegmentData.Address[4] = (2048 >> 24); - Scsi->SegmentData.Address[5] = (2048 >> 16); - Scsi->SegmentData.Address[6] = (2048 >> 8); - Scsi->SegmentData.Address[7] = 2048 & 0xFF; - Scsi->SegmentData.Length = 8; - len=8; - SCSICDROM_CommandReady(Scsi, Id, len); - SCSISenseCodeOk(); - ScsiStatus = SCSI_STATUS_OK; + cdrom_sector_ismsf = 0; + } + + if (SectorLBA > (cdrom->size() - 1)) + { + pclog("Trying to read beyond the end of disc\n"); + SCSIStatus = SCSI_STATUS_CHECK_CONDITION; + SCSISenseCodeError(SENSE_ILLEGAL_REQUEST, ASC_ILLEGAL_OPCODE, 0); + if (SCSISense.UnitAttention) + { + SCSISenseCodeError(SENSE_UNIT_ATTENTION, ASC_MEDIUM_MAY_HAVE_CHANGED, 0); + } + SCSICallback[id]=50*SCSI_TIME; break; + } + + cdrom_sector_type = (cdb[1] >> 2) & 7; + cdrom_sector_flags = cdb[9] || ((cdb[10]) << 8); - case GPCMD_STOP_PLAY_SCAN: - cdrom->stop(); - ScsiCallback[Id]=50*SCSI_TIME; - SCSISenseCodeOk(); - ScsiStatus = SCSI_STATUS_OK; - break; - - default: - SCSISenseCodeError(SENSE_ILLEGAL_REQUEST, ASC_INV_FIELD_IN_CMD_PACKET, 0x00); - ScsiStatus = SCSI_STATUS_CHECK_CONDITION; - if (SCSISense.SenseKey == SENSE_UNIT_ATTENTION) - old_cdrom_drive = cdrom_drive; - ScsiCallback[Id]=50*SCSI_TIME; - return; + SCSIPhase = SCSI_PHASE_DATAIN; + SCSIStatus = SCSI_STATUS_OK; + SCSICallback[id]=60*SCSI_TIME; + SCSIDevices[id].CmdBufferLength = SectorLen * cdrom_sector_size; + + SCSIDMAResetPosition(id); + return; + + case GPCMD_SET_SPEED: + SCSIPhase = SCSI_PHASE_STATUS; + SCSIStatus = SCSI_STATUS_OK; + SCSICallback[id]=50*SCSI_TIME; + SCSIDevices[id].CmdBufferLength = 0; + break; + + case GPCMD_MECHANISM_STATUS: + SCSIPhase = SCSI_PHASE_DATAIN; + SCSIStatus = SCSI_STATUS_OK; + SCSICallback[id]=60*SCSI_TIME; + SCSIDevices[id].CmdBufferLength = 8; + + SCSIDMAResetPosition(id); + break; } } - -void SCSICDROM_ReadCallback(SCSI *Scsi, uint8_t Id) +void SCSICDROM_ReadData(uint8_t id, uint8_t *cdb, uint8_t *data, int datalen) { - int ret; + int DVDRet; + uint8_t Index = 0; + int real_pos; + int msf; + uint32_t Size; + unsigned Idx = 0; + unsigned SizeIndex; + unsigned PreambleLen; + unsigned char Temp; + int read_length = 0; - if (Scsi->SectorLen <= 0) + msf = cdb[1] & 2; + + switch (cdb[0]) { - SCSISenseCodeOk(); - ScsiStatus = SCSI_STATUS_OK; - return; - } - - ret = SCSICDROMReadData(Scsi, Scsi->SegmentData.Address); - pclog("SCSI Read: 0x%04X\n", Scsi->SegmentData.Address); - - Scsi->SectorLba++; - Scsi->SectorLen--; + case GPCMD_REQUEST_SENSE: + /*Will return 18 bytes of 0*/ + memset(SCSIDevices[id].CmdBuffer,0,512); - Scsi->BufferLength=cdrom_sector_size; - ScsiCallback[Id]=60*SCSI_TIME; - Scsi->SegmentData.Length=cdrom_sector_size; - - SegmentBufferCopyFromBuf(&Scsi->SegmentBuffer, Scsi->SegmentData.Address, Scsi->SegmentData.Length); - - SCSISenseCodeOk(); - ScsiStatus = SCSI_STATUS_OK; + SCSIDevices[id].CmdBuffer[0]=0x80|0x70; + + if ((SCSISense.SenseKey > 0) || (cd_status < CD_STATUS_PLAYING)) + { + if (SenseCompleted) + { + SCSIDevices[id].CmdBuffer[2]=SENSE_ILLEGAL_REQUEST; + SCSIDevices[id].CmdBuffer[12]=ASC_AUDIO_PLAY_OPERATION; + SCSIDevices[id].CmdBuffer[13]=ASCQ_AUDIO_PLAY_OPERATION_COMPLETED; + } + else + { + SCSIDevices[id].CmdBuffer[2]=SCSISense.SenseKey; + SCSIDevices[id].CmdBuffer[12]=SCSISense.Asc; + SCSIDevices[id].CmdBuffer[13]=SCSISense.Ascq; + } + } + else if ((SCSISense.SenseKey == 0) && (cd_status >= CD_STATUS_PLAYING) && (cd_status != CD_STATUS_STOPPED)) + { + SCSIDevices[id].CmdBuffer[2]=SENSE_ILLEGAL_REQUEST; + SCSIDevices[id].CmdBuffer[12]=ASC_AUDIO_PLAY_OPERATION; + SCSIDevices[id].CmdBuffer[13]=(cd_status == CD_STATUS_PLAYING) ? ASCQ_AUDIO_PLAY_OPERATION_IN_PROGRESS : ASCQ_AUDIO_PLAY_OPERATION_PAUSED; + } + else + { + if (SCSISense.UnitAttention) + { + SCSIDevices[id].CmdBuffer[2]=SENSE_UNIT_ATTENTION; + SCSIDevices[id].CmdBuffer[12]=ASC_MEDIUM_MAY_HAVE_CHANGED; + SCSIDevices[id].CmdBuffer[13]=0; + } + } + + SCSIDevices[id].CmdBuffer[7]=10; + + if (SCSIDevices[id].CmdBuffer[2] == SENSE_UNIT_ATTENTION) + { + /* If the last remaining sense is unit attention, clear + that condition. */ + SCSISense.UnitAttention = 0; + } + + /* Clear the sense stuff as per the spec. */ + SCSIClearSense(cdb[0], 0); + break; + + case GPCMD_READ_6: + case GPCMD_READ_10: + case GPCMD_READ_12: + pclog("Total data length requested: %d\n", datalen); + while (datalen > 0) + { + read_length = cdrom_read_data(data); //Fill the buffer the data it needs + if (!read_length) + { + SCSIStatus = SCSI_STATUS_CHECK_CONDITION; + SCSISenseCodeError(SENSE_ILLEGAL_REQUEST, ASC_ILLEGAL_OPCODE, 0); + SCSICallback[id]=50*SCSI_TIME; + break; + } + else + { + //Continue reading data until the sector length is 0. + data += read_length; + } + + pclog("True LBA: %d, buffer half: %d\n", SectorLBA, SectorLen * 2048); + + SectorLBA++; + SectorLen--; + + if (SectorLen == 0) + { + break; + } + } + break; + + case GPCMD_INQUIRY: + if (cdb[1] & 1) + { + PreambleLen = 4; + SizeIndex = 3; + + SCSIDevices[id].CmdBuffer[Idx++] = 05; + SCSIDevices[id].CmdBuffer[Idx++] = cdb[2]; + SCSIDevices[id].CmdBuffer[Idx++] = 0; + + Idx++; + + switch (cdb[2]) + { + case 0x00: + SCSIDevices[id].CmdBuffer[Idx++] = 0x00; + SCSIDevices[id].CmdBuffer[Idx++] = 0x83; + break; + + case 0x83: + if (Idx + 24 > SCSIDevices[id].CmdBufferLength) + { + SCSIStatus = SCSI_STATUS_CHECK_CONDITION; + SCSISenseCodeError(SENSE_ILLEGAL_REQUEST, ASC_DATA_PHASE_ERROR, 0x00); + SCSICallback[id]=50*SCSI_TIME; + return; + } + SCSIDevices[id].CmdBuffer[Idx++] = 0x02; + SCSIDevices[id].CmdBuffer[Idx++] = 0x00; + SCSIDevices[id].CmdBuffer[Idx++] = 0x00; + SCSIDevices[id].CmdBuffer[Idx++] = 20; + ScsiPadStr8(SCSIDevices[id].CmdBuffer + Idx, 20, "53R141"); /* Serial */ + Idx += 20; + + if (Idx + 72 > SCSIDevices[id].CmdBufferLength) + { + goto SCSIOut; + } + SCSIDevices[id].CmdBuffer[Idx++] = 0x02; + SCSIDevices[id].CmdBuffer[Idx++] = 0x01; + SCSIDevices[id].CmdBuffer[Idx++] = 0x00; + SCSIDevices[id].CmdBuffer[Idx++] = 68; + ScsiPadStr8(SCSIDevices[id].CmdBuffer + Idx, 8, "86Box"); /* Vendor */ + Idx += 8; + ScsiPadStr8(SCSIDevices[id].CmdBuffer + Idx, 40, "86BoxCD 1.00"); /* Product */ + Idx += 40; + ScsiPadStr8(SCSIDevices[id].CmdBuffer + Idx, 20, "53R141"); /* Product */ + Idx += 20; + break; + + default: + SCSIStatus = SCSI_STATUS_CHECK_CONDITION; + SCSISenseCodeError(SENSE_ILLEGAL_REQUEST, ASC_INV_FIELD_IN_CMD_PACKET, 0x00); + SCSICallback[id]=50*SCSI_TIME; + return; + } + } + else + { + PreambleLen = 5; + SizeIndex = 4; + + SCSIDevices[id].CmdBuffer[0] = 0x05; /*CD-ROM*/ + SCSIDevices[id].CmdBuffer[1] = 0x80; /*Removable*/ + SCSIDevices[id].CmdBuffer[2] = 0; + SCSIDevices[id].CmdBuffer[3] = 0x21; + SCSIDevices[id].CmdBuffer[4] = 31; + SCSIDevices[id].CmdBuffer[5] = 0; + SCSIDevices[id].CmdBuffer[6] = 0; + SCSIDevices[id].CmdBuffer[7] = 0; + ScsiPadStr8(SCSIDevices[id].CmdBuffer + 8, 8, "86Box"); /* Vendor */ + ScsiPadStr8(SCSIDevices[id].CmdBuffer + 16, 16, "86BoxCD"); /* Product */ + ScsiPadStr8(SCSIDevices[id].CmdBuffer + 32, 4, emulator_version); /* Revision */ + + Idx = 36; + } + +SCSIOut: + SCSIDevices[id].CmdBuffer[SizeIndex] = Idx - PreambleLen; + break; + + case GPCMD_MODE_SENSE_6: + case GPCMD_MODE_SENSE_10: + Temp = cdb[2] & 0x3f; + + memset(SCSIDevices[id].CmdBuffer, 0, datalen); + + if (!(mode_sense_pages[Temp] & IMPLEMENTED)) + { + SCSIStatus = SCSI_STATUS_CHECK_CONDITION; + SCSISenseCodeError(SENSE_ILLEGAL_REQUEST, ASC_INV_FIELD_IN_CMD_PACKET, 0x00); + SCSICallback[id]=50*SCSI_TIME; + return; + } + + if (cdb[0] == GPCMD_MODE_SENSE_6) + { + datalen = SCSICDROMModeSense(SCSIDevices[id].CmdBuffer, 4, Temp); + SCSIDevices[id].CmdBuffer[0] = datalen - 1; + SCSIDevices[id].CmdBuffer[1] = 3; /*120mm data CD-ROM*/ + } + else + { + datalen = SCSICDROMModeSense(SCSIDevices[id].CmdBuffer, 8, Temp); + SCSIDevices[id].CmdBuffer[0] = (datalen - 2)>>8; + SCSIDevices[id].CmdBuffer[1] = (datalen - 2)&255; + SCSIDevices[id].CmdBuffer[2] = 3; /*120mm data CD-ROM*/ + } + break; + + case GPCMD_READ_CDROM_CAPACITY: + if (cdrom->read_capacity) + { + cdrom->read_capacity(SCSIDevices[id].CmdBuffer); + } + else + { + Size = cdrom->size() - 1; /* IMPORTANT: What's returned is the last LBA block. */ + memset(SCSIDevices[id].CmdBuffer, 0, 8); + SCSIDevices[id].CmdBuffer[0] = (Size >> 24) & 0xff; + SCSIDevices[id].CmdBuffer[1] = (Size >> 16) & 0xff; + SCSIDevices[id].CmdBuffer[2] = (Size >> 8) & 0xff; + SCSIDevices[id].CmdBuffer[3] = Size & 0xff; + SCSIDevices[id].CmdBuffer[6] = 8; /* 2048 = 0x0800 */ + } + pclog("Sector size %04X\n", Size); + break; + + case GPCMD_READ_SUBCHANNEL: + if (cdb[3] != 1) + { + SCSIStatus = SCSI_STATUS_CHECK_CONDITION; + SCSISenseCodeError(SENSE_ILLEGAL_REQUEST, ASC_ILLEGAL_OPCODE, 0x00); + if (SCSISense.UnitAttention) + { + SCSISenseCodeError(SENSE_UNIT_ATTENTION, ASC_MEDIUM_MAY_HAVE_CHANGED, 0); + } + SCSICallback[id]=50*SCSI_TIME; + break; + } + SectorLBA = 0; + SCSIDevices[id].CmdBuffer[SectorLBA++] = 0; + SCSIDevices[id].CmdBuffer[SectorLBA++] = 0; /*Audio status*/ + SCSIDevices[id].CmdBuffer[SectorLBA++] = 0; SCSIDevices[id].CmdBuffer[SectorLBA++] = 0; /*Subchannel length*/ + SCSIDevices[id].CmdBuffer[SectorLBA++] = 1; /*Format code*/ + SCSIDevices[id].CmdBuffer[1] = cdrom->getcurrentsubchannel(&SCSIDevices[id].CmdBuffer[5], msf); + break; + + case GPCMD_READ_TOC_PMA_ATIP: + switch (SCSICDROM_TOC(id, cdb)) + { + case 0: /*Normal*/ + datalen = cdrom->readtoc(SCSIDevices[id].CmdBuffer, cdb[6], msf, datalen, 0); + break; + + case 1: /*Multi session*/ + datalen = cdrom->readtoc_session(SCSIDevices[id].CmdBuffer, msf, datalen); + SCSIDevices[id].CmdBuffer[0] = 0; + SCSIDevices[id].CmdBuffer[1] = 0xA; + break; + + case 2: /*Raw*/ + datalen = cdrom->readtoc_raw(SCSIDevices[id].CmdBuffer, datalen); + break; + } + break; + + case GPCMD_READ_HEADER: + if (cdrom->read_header) + { + cdrom->read_header(cdb, SCSIDevices[id].CmdBuffer); + } + else + { + SectorLen=(cdb[7]<<8)|cdb[8]; + SectorLBA=(cdb[2]<<24)|(cdb[3]<<16)|(cdb[4]<<8)|cdb[5]; + if (msf) + { + real_pos = cdrom_LBAtoMSF_accurate(); + } + else + { + real_pos = SectorLBA; + } + SCSIDevices[id].CmdBuffer[4] = (real_pos >> 24); + SCSIDevices[id].CmdBuffer[5] = ((real_pos >> 16) & 0xff); + SCSIDevices[id].CmdBuffer[6] = ((real_pos >> 8) & 0xff); + SCSIDevices[id].CmdBuffer[7] = real_pos & 0xff; + SCSIDevices[id].CmdBuffer[0]=1; /*2048 bytes user data*/ + SCSIDevices[id].CmdBuffer[1]=SCSIDevices[id].CmdBuffer[2]=SCSIDevices[id].CmdBuffer[3]=0; + } + break; + + case GPCMD_GET_CONFIGURATION: + Index = 0; + + /* only feature 0 is supported */ + if (cdb[2] != 0 || cdb[3] != 0) + { + SCSIStatus = SCSI_STATUS_CHECK_CONDITION; + SCSISenseCodeError(SENSE_ILLEGAL_REQUEST, ASC_INV_FIELD_IN_CMD_PACKET, 0x00); + SCSICallback[id]=50*SCSI_TIME; + return; + } + + /* + * XXX: avoid overflow for io_buffer if length is bigger than + * the size of that buffer (dimensioned to max number of + * sectors to transfer at once) + * + * Only a problem if the feature/profiles grow. + */ + if (datalen > 512) /* XXX: assume 1 sector */ + datalen = 512; + + memset(SCSIDevices[id].CmdBuffer, 0, datalen); + /* + * the number of sectors from the media tells us which profile + * to use as current. 0 means there is no media + */ + if (datalen > CD_MAX_SECTORS ) + { + SCSIDevices[id].CmdBuffer[6] = (MMC_PROFILE_DVD_ROM >> 8) & 0xff; + SCSIDevices[id].CmdBuffer[7] = MMC_PROFILE_DVD_ROM & 0xff; + } + else if (datalen <= CD_MAX_SECTORS) + { + SCSIDevices[id].CmdBuffer[6] = (MMC_PROFILE_CD_ROM >> 8) & 0xff; + SCSIDevices[id].CmdBuffer[7] = MMC_PROFILE_CD_ROM & 0xff; + } + SCSIDevices[id].CmdBuffer[10] = 0x02 | 0x01; /* persistent and current */ + datalen = 12; /* headers: 8 + 4 */ + datalen += SCSICDROMSetProfile(SCSIDevices[id].CmdBuffer, &Index, MMC_PROFILE_DVD_ROM); + datalen += SCSICDROMSetProfile(SCSIDevices[id].CmdBuffer, &Index, MMC_PROFILE_CD_ROM); + SCSIDevices[id].CmdBuffer[0] = ((datalen-4) >> 24) & 0xff; + SCSIDevices[id].CmdBuffer[1] = ((datalen-4) >> 16) & 0xff; + SCSIDevices[id].CmdBuffer[2] = ((datalen-4) >> 8) & 0xff; + SCSIDevices[id].CmdBuffer[3] = (datalen-4) & 0xff; + break; + + case GPCMD_GET_EVENT_STATUS_NOTIFICATION: + gesn_cdb = (void *)cdb; + gesn_event_header = (void *)SCSIDevices[id].CmdBuffer; + + /* It is fine by the MMC spec to not support async mode operations */ + if (!(gesn_cdb->polled & 0x01)) + { /* asynchronous mode */ + /* Only pollign is supported, asynchronous mode is not. */ + SCSIStatus = SCSI_STATUS_CHECK_CONDITION; + SCSISenseCodeError(SENSE_ILLEGAL_REQUEST, ASC_INV_FIELD_IN_CMD_PACKET, 0x00); + SCSICallback[id]=50*SCSI_TIME; + return; + } + + /* polling mode operation */ + + /* + * These are the supported events. + * + * We currently only support requests of the 'media' type. + * Notification class requests and supported event classes are bitmasks, + * but they are built from the same values as the "notification class" + * field. + */ + gesn_event_header->supported_events = 1 << GESN_MEDIA; + + /* + * We use |= below to set the class field; other bits in this byte + * are reserved now but this is useful to do if we have to use the + * reserved fields later. + */ + gesn_event_header->notification_class = 0; + + /* + * Responses to requests are to be based on request priority. The + * notification_class_request_type enum above specifies the + * priority: upper elements are higher prio than lower ones. + */ + if (gesn_cdb->class & (1 << GESN_MEDIA)) + { + gesn_event_header->notification_class |= GESN_MEDIA; + datalen = SCSICDROMEventStatus(SCSIDevices[id].CmdBuffer); + } + else + { + gesn_event_header->notification_class = 0x80; /* No event available */ + datalen = sizeof(*gesn_event_header); + } + gesn_event_header->len = datalen - sizeof(*gesn_event_header); + break; + + case GPCMD_READ_DISC_INFORMATION: + if (cdrom->read_disc_information) + { + cdrom->read_disc_information(SCSIDevices[id].CmdBuffer); + } + else + { + SCSIDevices[id].CmdBuffer[1] = 32; + SCSIDevices[id].CmdBuffer[2] = 0xe; /* last session complete, disc finalized */ + SCSIDevices[id].CmdBuffer[3] = 1; /* first track on disc */ + SCSIDevices[id].CmdBuffer[4] = 1; /* # of sessions */ + SCSIDevices[id].CmdBuffer[5] = 1; /* first track of last session */ + SCSIDevices[id].CmdBuffer[6] = 1; /* last track of last session */ + SCSIDevices[id].CmdBuffer[7] = 0x20; /* unrestricted use */ + SCSIDevices[id].CmdBuffer[8] = 0x00; /* CD-ROM */ + } + break; + + case GPCMD_READ_DVD_STRUCTURE: + memset(SCSIDevices[id].CmdBuffer, 0, datalen > 256 * 512 + 4 ? 256 * 512 + 4 : datalen); + + switch (cdb[7]) + { + case 0x00 ... 0x7f: + case 0xff: + if (cdb[1] == 0) + { + DVDRet = SCSICDROMReadDVDStructure(cdb[7], cdb, SCSIDevices[id].CmdBuffer); + + if (DVDRet < 0) + { + SCSISenseCodeError(SENSE_ILLEGAL_REQUEST, -DVDRet, 0x00); + } + break; + } + /* TODO: BD support, fall through for now */ + + /* Generic disk structures */ + case 0x80: /* TODO: AACS volume identifier */ + case 0x81: /* TODO: AACS media serial number */ + case 0x82: /* TODO: AACS media identifier */ + case 0x83: /* TODO: AACS media key block */ + case 0x90: /* TODO: List of recognized format layers */ + case 0xc0: /* TODO: Write protection status */ + default: + SCSIStatus = SCSI_STATUS_CHECK_CONDITION; + SCSISenseCodeError(SENSE_ILLEGAL_REQUEST, ASC_INV_FIELD_IN_CMD_PACKET, 0x00); + if (SCSISense.UnitAttention) + { + SCSISenseCodeError(SENSE_UNIT_ATTENTION, ASC_MEDIUM_MAY_HAVE_CHANGED, 0); + } + SCSICallback[id]=50*SCSI_TIME; + return; + } + break; + + case GPCMD_READ_CD_MSF: + case GPCMD_READ_CD: + pclog("Total data length requested: %d\n", datalen); + while (datalen > 0) + { + read_length = cdrom_read_data(data); //Fill the buffer the data it needs + if (!read_length) + { + SCSIStatus = SCSI_STATUS_CHECK_CONDITION; + SCSISenseCodeError(SENSE_ILLEGAL_REQUEST, ASC_ILLEGAL_OPCODE, 0); + SCSICallback[id]=50*SCSI_TIME; + break; + } + else + { + //Continue reading data until the sector length is 0. + data += read_length; + } + + pclog("True LBA: %d, buffer half: %d\n", SectorLBA, SectorLen * cdrom_sector_size); + + SectorLBA++; + SectorLen--; + + if (SectorLen == 0) + { + break; + } + } + break; + + case GPCMD_MECHANISM_STATUS: + SCSIDevices[id].CmdBuffer[0] = 0; + SCSIDevices[id].CmdBuffer[1] = 0; + SCSIDevices[id].CmdBuffer[2] = 0; + SCSIDevices[id].CmdBuffer[3] = 0; + SCSIDevices[id].CmdBuffer[4] = 0; + SCSIDevices[id].CmdBuffer[5] = 1; + SCSIDevices[id].CmdBuffer[6] = 0; + SCSIDevices[id].CmdBuffer[7] = 0; + break; + } +} + +void SCSICDROM_WriteData(uint8_t id, uint8_t *cdb, uint8_t *data, int datalen) +{ + switch (cdb[0]) + { + case GPCMD_MODE_SELECT_6: + case GPCMD_MODE_SELECT_10: + if (cdb[0] == GPCMD_MODE_SELECT_6) + { + prefix_len = 6; + } + else + { + prefix_len = 10; + } + + page_current = cdb[2]; + if (page_flags[page_current] & PAGE_CHANGEABLE) + page_flags[GPMODE_CDROM_AUDIO_PAGE] |= PAGE_CHANGED; + break; + } } \ No newline at end of file diff --git a/src/win.c b/src/win.c index 64f82a996..48d8a1704 100644 --- a/src/win.c +++ b/src/win.c @@ -626,7 +626,7 @@ int WINAPI WinMain (HINSTANCE hThisInstance, if (scsi_cdrom_enabled) CheckMenuItem(menu, IDM_CDROM_SCSI, MF_CHECKED); - if (aha154x_enabled) + if (buslogic_enabled) CheckMenuItem(menu, IDM_SCSI_ENABLED, MF_CHECKED); CheckMenuItem(menu, IDM_SCSI_BASE130, MF_UNCHECKED); @@ -1429,8 +1429,8 @@ LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM } pause = 1; Sleep(100); - aha154x_enabled ^= 1; - CheckMenuItem(hmenu, IDM_SCSI_ENABLED, aha154x_enabled ? MF_CHECKED : MF_UNCHECKED); + buslogic_enabled ^= 1; + CheckMenuItem(hmenu, IDM_SCSI_ENABLED, buslogic_enabled ? MF_CHECKED : MF_UNCHECKED); saveconfig(); resetpchard(); pause = 0;