Made Unknown transfers as invalid but with SCSI Status Good/Ok in the Adaptec 1540. SCSI Commands with no transfers are left with no transfer function.
1112 lines
30 KiB
C
1112 lines
30 KiB
C
/* Copyright holders: SA1988
|
|
see COPYING for more details
|
|
*/
|
|
/*Adaptec 154x SCSI emulation*/
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <stdarg.h>
|
|
|
|
#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
|
|
|
|
typedef struct MailboxInit_t
|
|
{
|
|
uint8_t Count;
|
|
addr24 Address;
|
|
} MailboxInit_t;
|
|
|
|
typedef struct MailboxInitExtended_t
|
|
{
|
|
uint8_t Count;
|
|
uint32_t Address;
|
|
} MailboxInitExtended_t;
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// 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
|
|
{
|
|
uint8_t CmdStatus;
|
|
uint32_t CCBPointer;
|
|
} 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 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;
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Scatter/Gather Segment List Definitions
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
// Adapter limits
|
|
//
|
|
|
|
#define MAX_SG_DESCRIPTORS 17
|
|
|
|
typedef struct SGE
|
|
{
|
|
addr24 Segment;
|
|
addr24 SegmentPointer;
|
|
} SGE;
|
|
|
|
typedef struct AdaptecRequests_t
|
|
{
|
|
CCB CmdBlock;
|
|
uint8_t *RequestSenseBuffer;
|
|
uint32_t CCBPointer;
|
|
} AdaptecRequests_t;
|
|
|
|
typedef struct Adaptec_t
|
|
{
|
|
AdaptecRequests_t AdaptecRequests;
|
|
uint8_t Status;
|
|
uint8_t Interrupt;
|
|
uint8_t Geometry;
|
|
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 DmaPort1, DmaData1;
|
|
int DmaPort2, DmaData2;
|
|
int BusOn;
|
|
int BusOff;
|
|
int DmaSpeed;
|
|
int ScsiBios;
|
|
} Adaptec_t;
|
|
|
|
Adaptec_t AdaptecLUN;
|
|
|
|
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 AdaptecSetDMAChannel(int DmaPort1, int DmaData1, int DmaPort2, int DmaData2)
|
|
{
|
|
dma_channel_write(DmaPort1, DmaData1);
|
|
dma_channel_write(DmaPort2, DmaData2);
|
|
}
|
|
|
|
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->MailboxOutPosCur = 0;
|
|
Adaptec->MailboxInPosCur = 0;
|
|
|
|
AdaptecClearInterrupt(Adaptec);
|
|
}
|
|
|
|
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 AdaptecInitReset(Adaptec_t *Adaptec, int Reset)
|
|
{
|
|
AdaptecReset(Adaptec);
|
|
if (Reset)
|
|
{
|
|
Adaptec->Status |= STAT_STST;
|
|
Adaptec->Status &= ~STAT_IDLE;
|
|
}
|
|
}
|
|
|
|
static void AdaptecMailboxLogInformation(Mailbox_t *Mailbox)
|
|
{
|
|
AdaptecLog("Adaptec: Mailbox Dump Log\n");
|
|
AdaptecLog("CCB Pointer=%#x\n", ADDR_TO_U32(Mailbox->CCBPointer));
|
|
AdaptecLog("Command or Status Code=%02X\n", Mailbox->CmdStatus);
|
|
}
|
|
|
|
static void AdaptecCCBLogInformation(CCB *CmdBlock)
|
|
{
|
|
pclog("Adaptec: CCB Dump Log\n");
|
|
pclog("Opcode=%#x\n", CmdBlock->Opcode);
|
|
pclog("Data Direction=%u\n", CmdBlock->ControlByte);
|
|
pclog("Cdb Length=%d\n", CmdBlock->CdbLength);
|
|
pclog("Sense Length=%u\n", CmdBlock->RequestSenseLength);
|
|
pclog("Data Length=%u\n", ADDR_TO_U32(CmdBlock->DataLength));
|
|
pclog("Data Pointer=%u\n", ADDR_TO_U32(CmdBlock->DataPointer));
|
|
pclog("Host Adapter Status=0x%02X\n", CmdBlock->HostStatus);
|
|
pclog("Target Device Status=0x%02X\n", CmdBlock->TargetStatus);
|
|
pclog("Cdb[0]=%#x\n", CmdBlock->Cdb[0]);
|
|
pclog("Cdb[1]=%#x\n", CmdBlock->Cdb[1]);
|
|
}
|
|
|
|
static void AdaptecMailboxIn(Adaptec_t *Adaptec, uint32_t CCBPointer, CCB *CmdBlock, uint8_t HostStatus, uint8_t TargetStatus, uint8_t MailboxCompletionCode)
|
|
{
|
|
Mailbox32_t Mailbox32;
|
|
Mailbox_t MailboxIn;
|
|
|
|
Mailbox32.CCBPointer = CCBPointer;
|
|
Mailbox32.CmdStatus = MailboxCompletionCode;
|
|
|
|
uint32_t Incoming = Adaptec->MailboxInAddr + (Adaptec->MailboxInPosCur * sizeof(Mailbox_t));
|
|
|
|
if (MailboxCompletionCode != MBI_NOT_FOUND)
|
|
{
|
|
CmdBlock->HostStatus = HostStatus;
|
|
CmdBlock->TargetStatus = TargetStatus;
|
|
|
|
uint32_t CCBSize = offsetof(CCB, Cdb);
|
|
const void *Data = (const void *)&CmdBlock;
|
|
uint32_t l = PageLengthReadWrite(CCBPointer, CCBSize);
|
|
//AdaptecBufferWrite(&Adaptec->AdaptecRequests, Incoming, &MailboxIn, sizeof(Mailbox_t));
|
|
memcpy(&ram[CCBPointer], Data, l);
|
|
CCBPointer += l;
|
|
Data -= l;
|
|
CCBSize += l;
|
|
}
|
|
|
|
MailboxIn.CmdStatus = Mailbox32.CmdStatus;
|
|
U32_TO_ADDR(MailboxIn.CCBPointer, Mailbox32.CCBPointer);
|
|
AdaptecLog("Adaptec: Mailbox: status code=0x%02X, CCB at 0x%08X\n", MailboxIn.CmdStatus, ADDR_TO_U32(MailboxIn.CCBPointer));
|
|
|
|
uint32_t MailboxSize = sizeof(Mailbox_t);
|
|
const void *Data = (const void *)&MailboxIn;
|
|
uint32_t l = PageLengthReadWrite(Incoming, MailboxSize);
|
|
//AdaptecBufferWrite(&Adaptec->AdaptecRequests, Incoming, &MailboxIn, sizeof(Mailbox_t));
|
|
memcpy(&ram[Incoming], Data, l);
|
|
Incoming += l;
|
|
Data -= l;
|
|
MailboxSize += l;
|
|
|
|
Adaptec->MailboxInPosCur++;
|
|
if (Adaptec->MailboxInPosCur > Adaptec->MailboxCount)
|
|
Adaptec->MailboxInPosCur = 0;
|
|
|
|
Adaptec->Interrupt = INTR_MBIF | INTR_ANY;
|
|
picint(1 << Adaptec->Irq);
|
|
}
|
|
|
|
static void AdaptecReadSGEntries(uint32_t SGList, uint32_t Entries, SGE *SG)
|
|
{
|
|
uint32_t SGSize = Entries * sizeof(SGE);
|
|
void *Data = (void *)SG;
|
|
uint32_t l = PageLengthReadWrite(SGList, SGSize);
|
|
//AdaptecBufferRead(&Adaptec->AdaptecRequests, SGList, SG, Entries * sizeof(SGE));
|
|
memcpy(Data, &ram[SGList], l);
|
|
SGList += l;
|
|
Data -= l;
|
|
SGSize += l;
|
|
}
|
|
|
|
static void AdaptecQueryDataBufferSize(Adaptec_t *Adaptec, CCB *CmdBlock, uint32_t *pBufferSize)
|
|
{
|
|
uint32_t BufferSize = 0;
|
|
|
|
DataPointer = ADDR_TO_U32(CmdBlock->DataPointer);
|
|
DataLength = ADDR_TO_U32(CmdBlock->DataLength);
|
|
|
|
if (DataLength)
|
|
{
|
|
if (CmdBlock->Opcode == SCATTER_GATHER_COMMAND ||
|
|
CmdBlock->Opcode == SCATTER_GATHER_COMMAND_RES)
|
|
{
|
|
uint32_t ScatterGatherRead;
|
|
uint32_t ScatterEntry;
|
|
SGE ScatterGatherBuffer[MAX_SG_DESCRIPTORS];
|
|
uint32_t ScatterGatherLeft = DataLength / sizeof(SGE);
|
|
uint32_t ScatterGatherAddrCurrent = DataPointer;
|
|
|
|
do
|
|
{
|
|
ScatterGatherRead = (ScatterGatherLeft < ELEMENTS(ScatterGatherBuffer))
|
|
? ScatterGatherLeft : ELEMENTS(ScatterGatherBuffer);
|
|
|
|
ScatterGatherLeft -= ScatterGatherRead;
|
|
|
|
AdaptecReadSGEntries(ScatterGatherAddrCurrent, ScatterGatherRead, ScatterGatherBuffer);
|
|
|
|
for (ScatterEntry = 0; ScatterEntry < ScatterGatherRead; ScatterEntry++)
|
|
BufferSize += ADDR_TO_U32(ScatterGatherBuffer[ScatterEntry].Segment);
|
|
|
|
ScatterGatherAddrCurrent += ScatterGatherRead * sizeof(SGE);
|
|
} while (ScatterGatherLeft > 0);
|
|
|
|
AdaptecLog("Adaptec: Data Buffer Size=%u\n", BufferSize);
|
|
}
|
|
else if (CmdBlock->Opcode == SCSI_INITIATOR_COMMAND ||
|
|
CmdBlock->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);
|
|
|
|
uint32_t SegmentSize = Segment;
|
|
void *Data = (void *)SegmentPointer;
|
|
uint32_t l = PageLengthReadWrite(Address, SegmentSize);
|
|
//AdaptecBufferRead(&Adaptec->AdaptecRequests, Address, SegmentPointer, Segment);
|
|
memcpy(Data, &ram[Address], l);
|
|
Address += l;
|
|
Data -= l;
|
|
SegmentSize += l;
|
|
|
|
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);
|
|
|
|
uint32_t SegmentSize = Segment;
|
|
const void *Data = (const void *)SegmentPointer;
|
|
uint32_t l = PageLengthReadWrite(Address, SegmentSize);
|
|
//AdaptecBufferWrite(&Adaptec->AdaptecRequests, Address, SegmentPointer, Segment);
|
|
memcpy(&ram[Address], Data, l);
|
|
Address += l;
|
|
Data -= l;
|
|
SegmentSize += l;
|
|
|
|
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;
|
|
|
|
DataPointer = ADDR_TO_U32(AdaptecRequests->CmdBlock.DataPointer);
|
|
DataLength = ADDR_TO_U32(AdaptecRequests->CmdBlock.DataLength);
|
|
|
|
AdaptecLog("Adaptec: S/G Buffer Walker\n");
|
|
AdaptecLog("Data Length=%u\n", DataLength);
|
|
AdaptecLog("Data Buffer Copy=%u\n", Copy);
|
|
|
|
if ((DataLength > 0) && (AdaptecRequests->CmdBlock.ControlByte == CCB_DATA_XFER_IN ||
|
|
AdaptecRequests->CmdBlock.ControlByte == CCB_DATA_XFER_OUT))
|
|
{
|
|
if (AdaptecRequests->CmdBlock.Opcode == SCATTER_GATHER_COMMAND ||
|
|
AdaptecRequests->CmdBlock.Opcode == SCATTER_GATHER_COMMAND_RES)
|
|
{
|
|
uint32_t ScatterGatherRead;
|
|
uint32_t ScatterEntry;
|
|
SGE ScatterGatherBuffer[MAX_SG_DESCRIPTORS];
|
|
uint32_t ScatterGatherLeft = DataLength / sizeof(SGE);
|
|
uint32_t ScatterGatherAddrCurrent = DataPointer;
|
|
|
|
do
|
|
{
|
|
ScatterGatherRead = (ScatterGatherLeft < ELEMENTS(ScatterGatherBuffer))
|
|
? ScatterGatherLeft : ELEMENTS(ScatterGatherBuffer);
|
|
|
|
ScatterGatherLeft -= ScatterGatherRead;
|
|
|
|
AdaptecReadSGEntries(ScatterGatherAddrCurrent, ScatterGatherRead, ScatterGatherBuffer);
|
|
|
|
for (ScatterEntry = 0; ScatterEntry < ScatterGatherRead; ScatterEntry++)
|
|
{
|
|
uint32_t Address;
|
|
uint32_t CopyThis;
|
|
|
|
AdaptecLog("Adaptec: Scatter Entry=%u\n", ScatterEntry);
|
|
|
|
Address = ADDR_TO_U32(ScatterGatherBuffer[ScatterEntry].SegmentPointer);
|
|
CopyThis = MIN(Copy, ADDR_TO_U32(ScatterGatherBuffer[ScatterEntry].Segment));
|
|
|
|
AdaptecLog("Adaptec: S/G Address=0x%04X, Copy=%u", 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.Opcode == SCSI_INITIATOR_COMMAND ||
|
|
AdaptecRequests->CmdBlock.Opcode == SCSI_INITIATOR_COMMAND_RES)
|
|
{
|
|
uint32_t Address = DataPointer;
|
|
|
|
AdaptecLog("Adaptec: Non-scattered buffer\n");
|
|
pclog("Data Pointer=%#x\n", DataPointer);
|
|
pclog("Data Length=%u\n", DataLength);
|
|
AdaptecLog("Pointer Address=%#x\n", Address);
|
|
|
|
IoCopyWorker(Adaptec, Address, SegmentBuffer, MIN(DataLength, Copy), &Skip);
|
|
Copied += MIN(DataLength, Copy);
|
|
}
|
|
}
|
|
|
|
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;
|
|
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;
|
|
if (Adaptec->ScsiBios)
|
|
{
|
|
Adaptec->Interrupt = INTR_MBIF | INTR_ANY;
|
|
picint(1 << Adaptec->Irq);
|
|
}
|
|
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;
|
|
AdaptecLog("Adaptec: Write Port 0x%02X, Value %02X\n", Port, Val);
|
|
|
|
switch (Port & 3)
|
|
{
|
|
case 0:
|
|
if ((Val & CTRL_HRST) || (Val & CTRL_SRST))
|
|
{
|
|
int HardReset = !!(Val & CTRL_HRST);
|
|
|
|
AdaptecLog("Adaptec: %s reset\n", HardReset ? "hard" : "soft");
|
|
AdaptecInitReset(Adaptec, HardReset);
|
|
break;
|
|
}
|
|
|
|
if (Val & CTRL_IRST)
|
|
AdaptecClearInterrupt(Adaptec);
|
|
break;
|
|
|
|
case 1:
|
|
if ((Val == 0x02) && (Adaptec->Command == 0xFF))
|
|
{
|
|
if (Adaptec->MailboxCount)
|
|
{
|
|
ScsiCallback[scsi_cdrom_id] = 1;
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (Adaptec->Command == 0xFF)
|
|
{
|
|
Adaptec->Command = Val;
|
|
Adaptec->CmdParam = 0;
|
|
|
|
Adaptec->Status &= ~(STAT_INVCMD | STAT_IDLE);
|
|
AdaptecLog("Adaptec: Operation Code 0x%02X\n", Val);
|
|
switch (Adaptec->Command)
|
|
{
|
|
case 0x03:
|
|
case 0x00:
|
|
case 0x04:
|
|
case 0x84:
|
|
case 0x85:
|
|
case 0x0A:
|
|
case 0x0B:
|
|
Adaptec->CmdParamLeft = 0;
|
|
break;
|
|
|
|
case 0x07:
|
|
case 0x08:
|
|
case 0x09:
|
|
case 0x0D:
|
|
case 0x1F:
|
|
Adaptec->CmdParamLeft = 1;
|
|
break;
|
|
|
|
case 0x06:
|
|
Adaptec->CmdParamLeft = 4;
|
|
break;
|
|
|
|
case 0x01:
|
|
Adaptec->CmdParamLeft = sizeof(MailboxInit_t);
|
|
break;
|
|
|
|
case 0x28:
|
|
case 0x29:
|
|
Adaptec->CmdParamLeft = 0;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Adaptec->CmdBuf[Adaptec->CmdParam] = Val;
|
|
Adaptec->CmdParam++;
|
|
Adaptec->CmdParamLeft--;
|
|
}
|
|
|
|
if (!Adaptec->CmdParamLeft)
|
|
{
|
|
switch (Adaptec->Command)
|
|
{
|
|
case 0x00:
|
|
Adaptec->DataReplyLeft = 0;
|
|
break;
|
|
|
|
case 0x01:
|
|
{
|
|
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);
|
|
AdaptecLog("Initialized Mailbox, %d entries at 0x%08X\n", MailboxInit->Count, ADDR_TO_U32(MailboxInit->Address));
|
|
|
|
Adaptec->Status &= ~STAT_INIT;
|
|
Adaptec->DataReplyLeft = 0;
|
|
}
|
|
break;
|
|
|
|
case 0x03:
|
|
break;
|
|
|
|
case 0x04:
|
|
Adaptec->DataBuf[0] = 'A';
|
|
Adaptec->DataBuf[1] = '0';
|
|
Adaptec->DataBuf[2] = '3';
|
|
Adaptec->DataBuf[3] = '1';
|
|
Adaptec->DataReplyLeft = 4;
|
|
break;
|
|
|
|
case 0x84:
|
|
Adaptec->DataBuf[0] = '0';
|
|
Adaptec->DataReplyLeft = 1;
|
|
break;
|
|
|
|
case 0x85:
|
|
Adaptec->DataBuf[0] = 'A';
|
|
Adaptec->DataReplyLeft = 1;
|
|
break;
|
|
|
|
case 0x06:
|
|
Adaptec->DataReplyLeft = 0;
|
|
break;
|
|
|
|
case 0x07:
|
|
Adaptec->BusOn = Adaptec->CmdBuf[0];
|
|
Adaptec->DataReplyLeft = 0;
|
|
break;
|
|
|
|
case 0x08:
|
|
Adaptec->BusOff = Adaptec->CmdBuf[0];
|
|
Adaptec->DataReplyLeft = 0;
|
|
break;
|
|
|
|
case 0x09:
|
|
Adaptec->DmaSpeed = Adaptec->CmdBuf[0];
|
|
Adaptec->DataReplyLeft = 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);
|
|
|
|
if (Adaptec->DmaChannel >= 0)
|
|
AdaptecSetDMAChannel(Adaptec->DmaPort1, Adaptec->DmaData1,
|
|
Adaptec->DmaPort2, Adaptec->DmaData2);
|
|
|
|
Adaptec->DataBuf[1] = (1 << (Adaptec->Irq - 9));
|
|
Adaptec->DataBuf[2] = 7;
|
|
Adaptec->DataReplyLeft = 3;
|
|
break;
|
|
|
|
case 0x0D:
|
|
Adaptec->DataReplyLeft = Adaptec->CmdBuf[0];
|
|
Adaptec->DataBuf[1] = Adaptec->DmaSpeed;
|
|
Adaptec->DataBuf[2] = Adaptec->BusOn;
|
|
Adaptec->DataBuf[3] = Adaptec->BusOff;
|
|
Adaptec->DataBuf[4] = Adaptec->MailboxCount;
|
|
Adaptec->DataBuf[5] = Adaptec->MailboxOutAddr&0xFF;
|
|
Adaptec->DataBuf[6] = (Adaptec->MailboxOutAddr>>8);
|
|
Adaptec->DataBuf[7] = (Adaptec->MailboxOutAddr>>16);
|
|
Adaptec->DataBuf[8+scsi_cdrom_id] = 1;
|
|
break;
|
|
|
|
case 0x1F:
|
|
Adaptec->DataBuf[0] = Adaptec->CmdBuf[0];
|
|
Adaptec->DataReplyLeft = 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:
|
|
break;
|
|
|
|
case 3:
|
|
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.RequestSenseLength);
|
|
|
|
AdaptecRequests->RequestSenseBuffer = malloc(SenseLength);
|
|
}
|
|
|
|
static void AdaptecSenseBufferFree(AdaptecRequests_t *AdaptecRequests, int Copy)
|
|
{
|
|
uint8_t SenseLength = AdaptecConvertSenseLength(AdaptecRequests->CmdBlock.RequestSenseLength);
|
|
|
|
if (Copy && SenseLength)
|
|
{
|
|
uint32_t SenseBufferAddress;
|
|
|
|
SenseBufferAddress = AdaptecRequests->CCBPointer;
|
|
SenseBufferAddress += AdaptecRequests->CmdBlock.CdbLength + offsetof(CCB, Cdb);
|
|
|
|
uint32_t SenseSize = SenseLength;
|
|
const void *Data = (const void *)AdaptecRequests->RequestSenseBuffer;
|
|
uint32_t l = PageLengthReadWrite(SenseBufferAddress, SenseSize);
|
|
//AdaptecBufferWrite(AdaptecRequests, SenseBufferAddress, AdaptecRequests->RequestSenseBuffer, SenseLength);
|
|
memcpy(&ram[SenseBufferAddress], Data, l);
|
|
SenseBufferAddress += l;
|
|
Data -= l;
|
|
SenseSize += l;
|
|
}
|
|
free(AdaptecRequests->RequestSenseBuffer);
|
|
}
|
|
|
|
static void AdaptecRequestComplete(SCSI *Scsi, Adaptec_t *Adaptec,
|
|
AdaptecRequests_t *AdaptecRequests)
|
|
{
|
|
if (AdaptecRequests->RequestSenseBuffer)
|
|
AdaptecSenseBufferFree(AdaptecRequests, (ScsiStatus != SCSI_STATUS_OK));
|
|
|
|
if (AdaptecRequests->CmdBlock.Opcode == SCSI_INITIATOR_COMMAND_RES ||
|
|
AdaptecRequests->CmdBlock.Opcode == SCATTER_GATHER_COMMAND_RES)
|
|
{
|
|
uint32_t Residual = 0;
|
|
SCSIQueryResidual(Scsi, &Residual);
|
|
U32_TO_ADDR(AdaptecRequests->CmdBlock.DataLength, Residual);
|
|
}
|
|
|
|
uint8_t Status = ScsiStatus;
|
|
uint32_t CCBPointer = AdaptecRequests->CCBPointer;
|
|
CCB CmdBlock;
|
|
memcpy(&CmdBlock, &AdaptecRequests->CmdBlock, sizeof(CCB));
|
|
|
|
if (Status == SCSI_STATUS_OK)
|
|
AdaptecMailboxIn(Adaptec, CCBPointer, &CmdBlock, CCB_COMPLETE, SCSI_STATUS_OK,
|
|
MBI_SUCCESS);
|
|
else if (Status == SCSI_STATUS_CHECK_CONDITION)
|
|
AdaptecMailboxIn(Adaptec, CCBPointer, &CmdBlock, CCB_COMPLETE, SCSI_STATUS_CHECK_CONDITION,
|
|
MBI_ERROR);
|
|
}
|
|
|
|
uint32_t AdaptecIoRequestCopyFromBuffer(uint32_t OffDst, SGBUF *SegmentBuffer, uint32_t Copy)
|
|
{
|
|
Adaptec_t *Adaptec = &AdaptecLUN;
|
|
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;
|
|
uint32_t Copied = 0;
|
|
|
|
Copied = AdaptecCopySegmentBufferFromGuest(Adaptec, &Adaptec->AdaptecRequests, SegmentBuffer, OffSrc, Copy);
|
|
|
|
return Copied;
|
|
}
|
|
|
|
static void AdaptecSCSIRequestSetup(Adaptec_t *Adaptec, uint32_t CCBPointer)
|
|
{
|
|
AdaptecRequests_t *AdaptecRequests = &Adaptec->AdaptecRequests;
|
|
CCB CmdBlock;
|
|
|
|
uint32_t CCBUSize = sizeof(CCB);
|
|
void *Data = (void *)&CmdBlock;
|
|
uint32_t l = PageLengthReadWrite(CCBPointer, CCBUSize);
|
|
//AdaptecBufferRead(&Adaptec->AdaptecRequests, CCBPointer, &CmdBlock, sizeof(CCBU));
|
|
memcpy(Data, &ram[CCBPointer], l);
|
|
CCBPointer += l;
|
|
Data -= l;
|
|
CCBUSize += l;
|
|
|
|
pclog("Scanning SCSI Target ID %d\n", CmdBlock.Id);
|
|
|
|
if (CmdBlock.Id == scsi_cdrom_id && CmdBlock.Lun == 0)
|
|
{
|
|
pclog("SCSI Target ID %d detected and working\n", CmdBlock.Id);
|
|
|
|
SCSI *Scsi = &ScsiDrives[CmdBlock.Id];
|
|
|
|
AdaptecRequests->CCBPointer = CCBPointer - 30;
|
|
|
|
memcpy(&AdaptecRequests->CmdBlock, &CmdBlock, sizeof(CmdBlock));
|
|
|
|
AdaptecSenseBufferAllocate(AdaptecRequests);
|
|
|
|
uint32_t BufferSize = 0;
|
|
AdaptecQueryDataBufferSize(Adaptec, &CmdBlock, &BufferSize);
|
|
|
|
uint8_t SenseLength = AdaptecConvertSenseLength(CmdBlock.RequestSenseLength);
|
|
|
|
pclog("Control Byte Transfer Direction %02X\n", CmdBlock.ControlByte);
|
|
|
|
if (CmdBlock.ControlByte == CCB_DATA_XFER_OUT)
|
|
{
|
|
pclog("Adaptec Write Transfer\n");
|
|
SCSIWriteTransfer(Scsi, CmdBlock.Id);
|
|
}
|
|
else if (CmdBlock.ControlByte == CCB_DATA_XFER_IN)
|
|
{
|
|
pclog("Adaptec Read Transfer\n");
|
|
SCSIReadTransfer(Scsi, CmdBlock.Id);
|
|
}
|
|
else
|
|
{
|
|
AdaptecMailboxIn(Adaptec, AdaptecRequests->CCBPointer, &CmdBlock, CCB_INVALID_DIRECTION, SCSI_STATUS_OK,
|
|
MBI_ERROR);
|
|
}
|
|
|
|
SCSISendCommand(Scsi, CmdBlock.Id, CmdBlock.Cdb, CmdBlock.CdbLength, BufferSize, AdaptecRequests->RequestSenseBuffer, SenseLength);
|
|
|
|
AdaptecRequestComplete(Scsi, Adaptec, AdaptecRequests);
|
|
}
|
|
else
|
|
{
|
|
CmdBlock.Id++;
|
|
}
|
|
}
|
|
|
|
static uint32_t AdaptecMailboxOut(Adaptec_t *Adaptec, Mailbox32_t *Mailbox32)
|
|
{
|
|
Mailbox_t MailboxOut;
|
|
uint32_t Outgoing;
|
|
|
|
Outgoing = Adaptec->MailboxOutAddr + (Adaptec->MailboxOutPosCur * sizeof(Mailbox_t));
|
|
uint32_t MailboxSize = sizeof(Mailbox_t);
|
|
void *Data = (void *)&MailboxOut;
|
|
uint32_t l = PageLengthReadWrite(Outgoing, MailboxSize);
|
|
//AdaptecBufferRead(&Adaptec->AdaptecRequests, Outgoing, &MailboxOut, sizeof(Mailbox_t));
|
|
memcpy(Data, &ram[Outgoing], l);
|
|
Outgoing += l;
|
|
Data -= l;
|
|
MailboxSize += l;
|
|
|
|
Mailbox32->CCBPointer = ADDR_TO_U32(MailboxOut.CCBPointer);
|
|
Mailbox32->CmdStatus = MailboxOut.CmdStatus;
|
|
|
|
return Outgoing;
|
|
}
|
|
|
|
static void AdaptecStartMailbox(Adaptec_t *Adaptec)
|
|
{
|
|
Mailbox32_t Mailbox32;
|
|
Mailbox_t MailboxOut;
|
|
uint32_t Outgoing;
|
|
|
|
uint8_t MailboxPosCur = Adaptec->MailboxOutPosCur;
|
|
|
|
do
|
|
{
|
|
Outgoing = AdaptecMailboxOut(Adaptec, &Mailbox32);
|
|
Adaptec->MailboxOutPosCur = (Adaptec->MailboxOutPosCur + 1) % Adaptec->MailboxCount;
|
|
|
|
} while ((MailboxPosCur != Adaptec->MailboxOutPosCur) && (Mailbox32.CmdStatus == MBO_FREE));
|
|
|
|
AdaptecLog("Adaptec: Got loaded mailbox at slot %u, CCB phys 0x%08X\n", Adaptec->MailboxOutPosCur, Mailbox32.CCBPointer);
|
|
|
|
uint8_t CmdStatus = MBO_FREE;
|
|
unsigned CodeOffset = offsetof(Mailbox_t, CmdStatus);
|
|
|
|
uint32_t MailboxOffset = Outgoing + CodeOffset;
|
|
uint32_t CmdStatusSize = sizeof(CmdStatus);
|
|
const void *Data = (const void *)&CmdStatus;
|
|
uint32_t l = PageLengthReadWrite(MailboxOffset, CmdStatusSize);
|
|
//AdaptecBufferRead(&Adaptec->AdaptecRequests, Outgoing, &MailboxOut, sizeof(Mailbox_t));
|
|
memcpy(&ram[MailboxOffset], Data, l);
|
|
MailboxOffset += l;
|
|
Data -= l;
|
|
CmdStatusSize += l;
|
|
|
|
Mailbox32.CmdStatus = MBO_START;
|
|
AdaptecSCSIRequestSetup(Adaptec, Mailbox32.CCBPointer);
|
|
}
|
|
|
|
void AdaptecCallback(void *p)
|
|
{
|
|
Adaptec_t *Adaptec = &AdaptecLUN;
|
|
|
|
ScsiCallback[scsi_cdrom_id] = 0;
|
|
|
|
if (Adaptec->MailboxCount)
|
|
{
|
|
AdaptecStartMailbox(Adaptec);
|
|
}
|
|
}
|
|
|
|
void AdaptecInit(uint8_t Id)
|
|
{
|
|
AdaptecLUN.Irq = 11;
|
|
AdaptecLUN.DmaChannel = 6;
|
|
|
|
AdaptecLUN.DmaPort1 = 0xD6;
|
|
AdaptecLUN.DmaData1 = 0xD4;
|
|
AdaptecLUN.DmaPort2 = 0xC2;
|
|
AdaptecLUN.DmaData2 = 0x02;
|
|
|
|
pfnIoRequestCopyFromBuffer = AdaptecIoRequestCopyFromBuffer;
|
|
pfnIoRequestCopyToBuffer = AdaptecIoRequestCopyToBuffer;
|
|
|
|
io_sethandler(0x0334, 0x0004, AdaptecRead, NULL, NULL, AdaptecWrite, NULL, NULL, NULL);
|
|
timer_add(AdaptecCallback, &ScsiCallback[Id], &ScsiCallback[Id], NULL);
|
|
|
|
AdaptecReset(&AdaptecLUN);
|
|
}
|