From abf009e5419377aae654028bbebb24afcaa2e83c Mon Sep 17 00:00:00 2001 From: TC1995 Date: Fri, 23 Dec 2016 17:11:59 +0100 Subject: [PATCH] Renamed Adaptec 154x adapter source to Buslogic as now it emulates the Buslogic BT-540B SCSI adapter. Moved CD-ROM read data buffer declaration and definitions to SCSI source files and headers, but still applying to IDE when needed. SCSI Read commands now return the correct sectors on callback. DMA bug fixes. --- src/Makefile.mingw | 4 +- src/Makefile.mingw64 | 4 +- src/aha154x.c | 1302 -------------------------- src/aha154x.h | 1 - src/buslogic.c | 1573 +++++++++++++++++++++++++++++++ src/buslogic.h | 1 + src/dma.c | 12 +- src/dma.h | 4 +- src/ibm.h | 2 +- src/ide.c | 368 +------- src/pc.c | 20 +- src/scsi.c | 149 +-- src/scsi.h | 127 ++- src/scsi_cdrom.c | 2082 +++++++++++++++++++++--------------------- src/win.c | 6 +- 15 files changed, 2824 insertions(+), 2831 deletions(-) delete mode 100644 src/aha154x.c delete mode 100644 src/aha154x.h create mode 100644 src/buslogic.c create mode 100644 src/buslogic.h 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;