From 4484ce95978df6a37c29420c30c4d40669c8cc21 Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 11 Oct 2017 01:17:41 +0200 Subject: [PATCH] Two-phased SCSI write-direction commands on the AHA and BusLogic SCSI controllers, fixes residual lengths for such commands; Cleaned up the handlers for the BusLogic Execute SCSI Command command; Made the AHA-1542CF use version 2.01 of the BIOS; The CD-ROM GET EVENT STATUS NOTIFICATION fix is back. --- src/cdrom/cdrom.c | 97 ++-- src/scsi/scsi.c | 2 +- src/scsi/scsi_aha154x.c | 290 ++++++----- src/scsi/scsi_bios_command.c | 30 +- src/scsi/scsi_buslogic.c | 937 +++++++++++++++++------------------ src/scsi/scsi_device.c | 16 +- src/scsi/scsi_device.h | 2 +- src/scsi/scsi_disk.c | 18 +- src/win/win_settings.c | 25 +- 9 files changed, 713 insertions(+), 704 deletions(-) diff --git a/src/cdrom/cdrom.c b/src/cdrom/cdrom.c index 6fb07fba5..5606cb9e5 100644 --- a/src/cdrom/cdrom.c +++ b/src/cdrom/cdrom.c @@ -9,7 +9,7 @@ * Implementation of the CD-ROM drive with SCSI(-like) * commands, for both ATAPI and SCSI usage. * - * Version: @(#)cdrom.c 1.0.14 2017/10/09 + * Version: @(#)cdrom.c 1.0.15 2017/10/10 * * Author: Miran Grca, * @@ -2016,47 +2016,6 @@ static int cdrom_read_dvd_structure(uint8_t id, int format, const uint8_t *packe } } -/*SCSI Get Event Status Notification*/ -static uint32_t cdrom_get_event_status(uint8_t id, uint8_t *buffer) -{ - uint8_t event_code, media_status = 0; - - if (buffer[5]) - { - media_status = MS_TRAY_OPEN; - if (cdrom_drives[id].handler->stop) - { - cdrom_drives[id].handler->stop(id); - } - } - else - { - media_status = MS_MEDIA_PRESENT; - } - - event_code = MEC_NO_CHANGE; - if (media_status != MS_TRAY_OPEN) - { - if (!buffer[4]) - { - event_code = MEC_NEW_MEDIA; - cdrom_drives[id].handler->load(id); - } - else if (buffer[4]==2) - { - event_code = MEC_EJECT_REQUESTED; - cdrom_drives[id].handler->eject(id); - } - } - - buffer[4] = event_code; - buffer[5] = media_status; - buffer[6] = 0; - buffer[7] = 0; - - return 8; -} - void cdrom_insert(uint8_t id) { cdrom[id].unit_attention = 1; @@ -2160,6 +2119,15 @@ skip_ready_check: } /* Next it's time for NOT READY. */ + if (!ready) + { + cdrom[id].media_status = MEC_MEDIA_REMOVAL; + } + else + { + cdrom[id].media_status = (cdrom[id].unit_attention) ? MEC_NEW_MEDIA : MEC_NO_CHANGE; + } + if ((cdrom_command_flags[cdb[0]] & CHECK_READY) && !ready) { cdrom_log("CD-ROM %i: Not ready (%02X)\n", id, cdb[0]); @@ -2396,7 +2364,7 @@ void cdrom_command(uint8_t id, uint8_t *cdb) SCSIPhase = SCSI_PHASE_DATA_IN; if (cdrom_drives[id].bus_type == CDROM_BUS_SCSI) { - if (SCSI_BufferLength == -1) + if ((SCSI_BufferLength == -1) || (cdb[4] < SCSI_BufferLength)) { SCSI_BufferLength = cdb[4]; } @@ -2420,7 +2388,7 @@ void cdrom_command(uint8_t id, uint8_t *cdb) len = (cdb[7] << 16) | (cdb[8] << 8) | cdb[9]; - if (SCSI_BufferLength == -1) + if ((SCSI_BufferLength == -1) || (len < SCSI_BufferLength)) { SCSI_BufferLength = len; } @@ -2451,7 +2419,7 @@ void cdrom_command(uint8_t id, uint8_t *cdb) } else { - if (SCSI_BufferLength == -1) + if ((SCSI_BufferLength == -1) || (len < SCSI_BufferLength)) { SCSI_BufferLength = len; } @@ -2501,7 +2469,7 @@ cdrom_readtoc_fallback: cdbufferb[1] = (len - 2) & 0xff; } - if (SCSI_BufferLength == -1) + if ((SCSI_BufferLength == -1) || (len < SCSI_BufferLength)) { SCSI_BufferLength = len; } @@ -2584,7 +2552,7 @@ cdrom_readtoc_fallback: cdrom[id].packet_len = max_len * alloc_length; - if (SCSI_BufferLength == -1) + if ((SCSI_BufferLength == -1) || (cdrom[id].packet_len < SCSI_BufferLength)) { SCSI_BufferLength = cdrom[id].packet_len; } @@ -2620,7 +2588,7 @@ cdrom_readtoc_fallback: } else { - if (SCSI_BufferLength == -1) + if ((SCSI_BufferLength == -1) || (len < SCSI_BufferLength)) { SCSI_BufferLength = len; } @@ -2648,7 +2616,7 @@ cdrom_readtoc_fallback: len = 8; } - if (SCSI_BufferLength == -1) + if ((SCSI_BufferLength == -1) || (len < SCSI_BufferLength)) { SCSI_BufferLength = len; } @@ -2729,7 +2697,7 @@ cdrom_readtoc_fallback: alloc_length = len; } - if (SCSI_BufferLength == -1) + if ((SCSI_BufferLength == -1) || (alloc_length < SCSI_BufferLength)) { SCSI_BufferLength = alloc_length; } @@ -2752,7 +2720,7 @@ cdrom_readtoc_fallback: len = (cdb[7] << 8) | cdb[8]; } - if (SCSI_BufferLength == -1) + if ((SCSI_BufferLength == -1) || (len < SCSI_BufferLength)) { SCSI_BufferLength = len; } @@ -2814,7 +2782,7 @@ cdrom_readtoc_fallback: cdbufferb[2] = ((alloc_length - 4) >> 8) & 0xff; cdbufferb[3] = (alloc_length - 4) & 0xff; - if (SCSI_BufferLength == -1) + if ((SCSI_BufferLength == -1) || (len < SCSI_BufferLength)) { SCSI_BufferLength = len; } @@ -2864,7 +2832,12 @@ cdrom_readtoc_fallback: if (gesn_cdb->class & (1 << GESN_MEDIA)) { gesn_event_header->notification_class |= GESN_MEDIA; - used_len = cdrom_get_event_status(id, cdbufferb); + + cdbufferb[4] = cdrom[id].media_status; /* Bits 7-4 = Reserved, Bits 4-1 = Media Status */ + cdbufferb[5] = 1; /* Power Status (1 = Active) */ + cdbufferb[6] = 0; + cdbufferb[7] = 0; + used_len = 8; } else { @@ -2873,7 +2846,9 @@ cdrom_readtoc_fallback: } gesn_event_header->len = used_len - sizeof(*gesn_event_header); - if (SCSI_BufferLength == -1) + memcpy(cdbufferb, gesn_event_header, 4); + + if ((SCSI_BufferLength == -1) || (used_len < SCSI_BufferLength)) { SCSI_BufferLength = used_len; } @@ -2917,7 +2892,7 @@ cdrom_readtoc_fallback: len=34; } - if (SCSI_BufferLength == -1) + if ((SCSI_BufferLength == -1) || (len < SCSI_BufferLength)) { SCSI_BufferLength = len; } @@ -2985,7 +2960,7 @@ cdrom_readtoc_fallback: } } - if (SCSI_BufferLength == -1) + if ((SCSI_BufferLength == -1) || (len < SCSI_BufferLength)) { SCSI_BufferLength = len; } @@ -3154,7 +3129,7 @@ cdrom_readtoc_fallback: } } - if (SCSI_BufferLength == -1) + if ((SCSI_BufferLength == -1) || (len < SCSI_BufferLength)) { SCSI_BufferLength = len; } @@ -3174,7 +3149,7 @@ cdrom_readtoc_fallback: } else { - if (SCSI_BufferLength == -1) + if ((SCSI_BufferLength == -1) || (len < SCSI_BufferLength)) { SCSI_BufferLength = len; } @@ -3224,7 +3199,7 @@ cdrom_readtoc_fallback: { ret = cdrom_read_dvd_structure(id, format, cdb, cdbufferb); - if (SCSI_BufferLength == -1) + if ((SCSI_BufferLength == -1) || (alloc_length < SCSI_BufferLength)) { SCSI_BufferLength = alloc_length; } @@ -3361,7 +3336,7 @@ atapi_out: cdbufferb[size_idx] = idx - preamble_len; len=idx; - if (SCSI_BufferLength == -1) + if ((SCSI_BufferLength == -1) || (len < SCSI_BufferLength)) { SCSI_BufferLength = len; } @@ -3430,7 +3405,7 @@ atapi_out: return; } - if (SCSI_BufferLength == -1) + if ((SCSI_BufferLength == -1) || (len < SCSI_BufferLength)) { SCSI_BufferLength = len; } diff --git a/src/scsi/scsi.c b/src/scsi/scsi.c index b3b4d7e59..cde338459 100644 --- a/src/scsi/scsi.c +++ b/src/scsi/scsi.c @@ -59,11 +59,11 @@ static SCSI_CARD scsi_cards[] = { { "[ISA] Adaptec AHA-1540B","aha1540b", &aha1540b_device, aha_device_reset }, { "[ISA] Adaptec AHA-1542C","aha1542c", &aha1542c_device, aha_device_reset }, { "[ISA] Adaptec AHA-1542CF","aha1542cf", &aha1542cf_device, aha_device_reset }, + { "[ISA] BusLogic BT-545C", "bt545c", &buslogic_device, BuslogicDeviceReset }, { "[ISA] Longshine LCS-6821N","lcs6821n", &scsi_lcs6821n_device,NULL }, { "[ISA] Ranco RT1000B", "rt1000b", &scsi_rt1000b_device, NULL }, { "[ISA] Trantor T130B", "t130b", &scsi_t130b_device, NULL }, { "[MCA] Adaptec AHA-1640", "aha1640", &aha1640_device, aha_device_reset }, - { "[PCI] BusLogic BT-545C", "bt545c", &buslogic_device, BuslogicDeviceReset }, { "[PCI] BusLogic BT-958D", "bt958d", &buslogic_pci_device, BuslogicDeviceReset }, { "", "", NULL, NULL }, }; diff --git a/src/scsi/scsi_aha154x.c b/src/scsi/scsi_aha154x.c index da2da94ba..122e333d3 100644 --- a/src/scsi/scsi_aha154x.c +++ b/src/scsi/scsi_aha154x.c @@ -12,7 +12,7 @@ * * NOTE: THIS IS CURRENTLY A MESS, but will be cleaned up as I go. * - * Version: @(#)scsi_aha154x.c 1.0.24 2017/10/09 + * Version: @(#)scsi_aha154x.c 1.0.25 2017/10/10 * * Authors: Fred N. van Kempen, * Original Buslogic version by SA1988 and Miran Grca. @@ -390,6 +390,7 @@ typedef struct { uint16_t rom_shramsz; /* size of shared RAM */ uint16_t rom_fwhigh; /* offset in BIOS of ver ID */ rom_t bios; /* BIOS memory descriptor */ + rom_t uppersck; /* BIOS memory descriptor */ uint8_t *rom1; /* main BIOS image */ uint8_t *rom2; /* SCSI-Select image */ @@ -735,10 +736,13 @@ aha_ccb(aha_t *dev) aha_log("CCB rewritten to the CDB (pointer %08X)\n", CCBPointer); DMAPageWrite(CCBPointer, (char *)CmdBlock, 18); - dev->ToRaise = INTR_HACC | INTR_ANY; if (dev->MailboxOutInterrupts) { - dev->ToRaise |= INTR_MBOA; + dev->ToRaise = INTR_MBOA | INTR_ANY; + } + else + { + dev->ToRaise = 0; } } @@ -822,10 +826,9 @@ aha_rd_sge(int Is24bit, uint32_t SGList, uint32_t Entries, SGE32 *SG) } -static void -aha_buf_alloc(Req_t *req, int Is24bit) +static int +aha_get_length(Req_t *req, int Is24bit) { - uint32_t sg_buffer_pos = 0; uint32_t DataPointer, DataLength; uint32_t SGEntryLength = (Is24bit ? sizeof(SGE) : sizeof(SGE32)); uint32_t Address; @@ -833,6 +836,7 @@ aha_buf_alloc(Req_t *req, int Is24bit) if (Is24bit) { DataPointer = ADDR_TO_U32(req->CmdBlock.old.DataPointer); DataLength = ADDR_TO_U32(req->CmdBlock.old.DataLength); + aha_log("Data length: %08X\n", req->CmdBlock.old.DataLength); } else { DataPointer = req->CmdBlock.new.DataPointer; DataLength = req->CmdBlock.new.DataLength; @@ -875,15 +879,75 @@ aha_buf_alloc(Req_t *req, int Is24bit) aha_log("Data to transfer (S/G) %d\n", DataToTransfer); - SCSI_BufferLength = DataToTransfer; + return DataToTransfer; + } else if (req->CmdBlock.common.Opcode == SCSI_INITIATOR_COMMAND || + req->CmdBlock.common.Opcode == SCSI_INITIATOR_COMMAND_RES) { + return DataLength; + } else { + return 0; + } + } else { + return 0; + } +} - aha_log("Allocating buffer for Scatter/Gather (%i bytes)\n", DataToTransfer); - SCSIDevices[req->TargetID][req->LUN].CmdBuffer = (uint8_t *) malloc(DataToTransfer); - memset(SCSIDevices[req->TargetID][req->LUN].CmdBuffer, 0, DataToTransfer); +static void +aha_residual_on_error(Req_t *req, int length) +{ + if ((req->CmdBlock.common.Opcode == SCSI_INITIATOR_COMMAND_RES) || + (req->CmdBlock.common.Opcode == SCATTER_GATHER_COMMAND_RES)) { + /* Should be 0 when scatter/gather? */ + + if (req->Is24bit) { + U32_TO_ADDR(req->CmdBlock.old.DataLength, length); + aha_log("24-bit Residual data length for reading: %d\n", + ADDR_TO_U32(req->CmdBlock.old.DataLength)); + } else { + req->CmdBlock.new.DataLength = length; + aha_log("32-bit Residual data length for reading: %d\n", + req->CmdBlock.new.DataLength); + } + } +} + + +static void +aha_buf_dma_transfer(Req_t *req, int Is24bit, int TransferLength, int dir) +{ + uint32_t sg_buffer_pos = 0; + uint32_t DataPointer, DataLength; + uint32_t SGEntryLength = (Is24bit ? sizeof(SGE) : sizeof(SGE32)); + uint32_t Address; + uint32_t Residual; + /* uint32_t CCBPointer = req->CCBPointer; */ + + if (Is24bit) { + DataPointer = ADDR_TO_U32(req->CmdBlock.old.DataPointer); + DataLength = ADDR_TO_U32(req->CmdBlock.old.DataLength); + } else { + DataPointer = req->CmdBlock.new.DataPointer; + DataLength = req->CmdBlock.new.DataLength; + } + aha_log("Data Buffer %s: length %d, pointer 0x%04X\n", + dir ? "write" : "read", SCSI_BufferLength, DataPointer); + + if ((req->CmdBlock.common.ControlByte != 0x03) && DataLength) { + if (req->CmdBlock.common.Opcode == SCATTER_GATHER_COMMAND || + req->CmdBlock.common.Opcode == SCATTER_GATHER_COMMAND_RES) { + uint32_t SGRead; + uint32_t ScatterEntry; + SGE32 SGBuffer[MAX_SG_DESCRIPTORS]; + uint32_t SGLeft = DataLength / SGEntryLength; + uint32_t SGAddrCurrent = DataPointer; + uint32_t DataToTransfer = 0; + + TransferLength -= SCSI_BufferLength; + /* 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 read/write commands. */ if ((req->CmdBlock.common.ControlByte == CCB_DATA_XFER_OUT) || + (req->CmdBlock.common.ControlByte == CCB_DATA_XFER_IN) || (req->CmdBlock.common.ControlByte == 0x00)) { SGLeft = DataLength / SGEntryLength; SGAddrCurrent = DataPointer; @@ -898,17 +962,32 @@ aha_buf_alloc(Req_t *req, int Is24bit) for (ScatterEntry=0; ScatterEntryTargetID][req->LUN].CmdBuffer + sg_buffer_pos, DataToTransfer); + if (dir && ((req->CmdBlock.common.ControlByte == CCB_DATA_XFER_OUT) || (req->CmdBlock.common.ControlByte == 0x00))) + { + DMAPageRead(Address, (char *)SCSIDevices[req->TargetID][req->LUN].CmdBuffer + sg_buffer_pos, (SCSI_BufferLength < DataToTransfer) ? SCSI_BufferLength : DataToTransfer); + } + else + if (!dir && ((req->CmdBlock.common.ControlByte == CCB_DATA_XFER_IN) || (req->CmdBlock.common.ControlByte == 0x00))) + { + DMAPageWrite(Address, (char *)SCSIDevices[req->TargetID][req->LUN].CmdBuffer + sg_buffer_pos, (SCSI_BufferLength < DataToTransfer) ? SCSI_BufferLength : DataToTransfer); + } sg_buffer_pos += DataToTransfer; + SCSI_BufferLength -= DataToTransfer; } SGAddrCurrent += SGRead * (Is24bit ? sizeof(SGE) : sizeof(SGE32)); - } while (SGLeft > 0); + } while (SGLeft > 0); } } else if (req->CmdBlock.common.Opcode == SCSI_INITIATOR_COMMAND || req->CmdBlock.common.Opcode == SCSI_INITIATOR_COMMAND_RES) { @@ -916,104 +995,25 @@ aha_buf_alloc(Req_t *req, int Is24bit) SCSI_BufferLength = DataLength; - aha_log("Allocating buffer for direct transfer (%i bytes)\n", DataLength); - SCSIDevices[req->TargetID][req->LUN].CmdBuffer = (uint8_t *) malloc(DataLength); - memset(SCSIDevices[req->TargetID][req->LUN].CmdBuffer, 0, DataLength); - - if (DataLength > 0) { - DMAPageRead(Address, - (char *)SCSIDevices[req->TargetID][req->LUN].CmdBuffer, - SCSI_BufferLength); + if ((DataLength > 0) && (SCSI_BufferLength > 0)) { + if (dir && ((req->CmdBlock.common.ControlByte == CCB_DATA_XFER_OUT) || (req->CmdBlock.common.ControlByte == 0x00))) + { + DMAPageRead(Address, (char *)SCSIDevices[req->TargetID][req->LUN].CmdBuffer, (SCSI_BufferLength < DataLength) ? SCSI_BufferLength : DataLength); + } + else + if (!dir && ((req->CmdBlock.common.ControlByte == CCB_DATA_XFER_IN) || (req->CmdBlock.common.ControlByte == 0x00))) + { + DMAPageWrite(Address, (char *)SCSIDevices[req->TargetID][req->LUN].CmdBuffer, (SCSI_BufferLength < DataLength) ? SCSI_BufferLength : DataLength); + } } } } -} - - -static void -aha_buf_free(Req_t *req) -{ - SGE32 SGBuffer[MAX_SG_DESCRIPTORS]; - uint32_t DataPointer = 0; - uint32_t DataLength = 0; - uint32_t sg_buffer_pos = 0; - uint32_t SGRead; - uint32_t ScatterEntry; - uint32_t SGEntrySize; - uint32_t SGLeft; - uint32_t SGAddrCurrent; - uint32_t Address; - uint32_t Residual; - uint32_t DataToTransfer; - - if (req->Is24bit) { - DataPointer = ADDR_TO_U32(req->CmdBlock.old.DataPointer); - DataLength = ADDR_TO_U32(req->CmdBlock.old.DataLength); - } else { - DataPointer = req->CmdBlock.new.DataPointer; - DataLength = req->CmdBlock.new.DataLength; - } - - if ((DataLength != 0) && (req->CmdBlock.common.Cdb[0] == GPCMD_TEST_UNIT_READY)) { - aha_log("Data length not 0 with TEST UNIT READY: %i (%i)\n", - DataLength, SCSI_BufferLength); - } - - if (req->CmdBlock.common.Cdb[0] == GPCMD_TEST_UNIT_READY) { - DataLength = 0; - } - - aha_log("Data Buffer read: length %d, pointer 0x%04X\n", - DataLength, DataPointer); - - /* If the control byte is 0x00, it means that the transfer direction is set up by the SCSI command without - checking its length, so do this procedure for both read/write commands. */ - if ((DataLength > 0) && - ((req->CmdBlock.common.ControlByte == CCB_DATA_XFER_IN) || - (req->CmdBlock.common.ControlByte == 0x00))) { - if ((req->CmdBlock.common.Opcode == SCATTER_GATHER_COMMAND) || - (req->CmdBlock.common.Opcode == SCATTER_GATHER_COMMAND_RES)) { - SGEntrySize = (req->Is24bit ? sizeof(SGE) : sizeof(SGE32)); - SGLeft = DataLength / SGEntrySize; - SGAddrCurrent = DataPointer; - - do { - SGRead = (SGLeft < ELEMENTS(SGBuffer)) ? SGLeft : ELEMENTS(SGBuffer); - SGLeft -= SGRead; - - aha_rd_sge(req->Is24bit, SGAddrCurrent, - SGRead, SGBuffer); - - for (ScatterEntry=0; ScatterEntryTargetID][req->LUN].CmdBuffer + sg_buffer_pos, DataToTransfer); - sg_buffer_pos += DataToTransfer; - } - - SGAddrCurrent += (SGRead * SGEntrySize); - } while (SGLeft > 0); - } else if (req->CmdBlock.common.Opcode == SCSI_INITIATOR_COMMAND || - req->CmdBlock.common.Opcode == SCSI_INITIATOR_COMMAND_RES) { - Address = DataPointer; - - aha_log("DMA: Writing %i bytes at %08X\n", - DataLength, Address); - DMAPageWrite(Address, (char *)SCSIDevices[req->TargetID][req->LUN].CmdBuffer, DataLength); - } - } if ((req->CmdBlock.common.Opcode == SCSI_INITIATOR_COMMAND_RES) || (req->CmdBlock.common.Opcode == SCATTER_GATHER_COMMAND_RES)) { /* Should be 0 when scatter/gather? */ - if (DataLength >= SCSI_BufferLength) { - Residual = DataLength; - Residual -= SCSI_BufferLength; + if (TransferLength > 0) { + Residual = TransferLength; } else { Residual = 0; } @@ -1028,7 +1028,26 @@ aha_buf_free(Req_t *req) req->CmdBlock.new.DataLength); } } +} + +static void +aha_buf_alloc(Req_t *req, int length) +{ + if (SCSIDevices[req->TargetID][req->LUN].CmdBuffer != NULL) { + free(SCSIDevices[req->TargetID][req->LUN].CmdBuffer); + SCSIDevices[req->TargetID][req->LUN].CmdBuffer = NULL; + } + + aha_log("Allocating data buffer (%i bytes)\n", length); + SCSIDevices[req->TargetID][req->LUN].CmdBuffer = (uint8_t *) malloc(length); + memset(SCSIDevices[req->TargetID][req->LUN].CmdBuffer, 0, length); +} + + +static void +aha_buf_free(Req_t *req) +{ if (SCSIDevices[req->TargetID][req->LUN].CmdBuffer != NULL) { free(SCSIDevices[req->TargetID][req->LUN].CmdBuffer); SCSIDevices[req->TargetID][req->LUN].CmdBuffer = NULL; @@ -1059,7 +1078,7 @@ SenseBufferFree(Req_t *req, int Copy) uint32_t SenseBufferAddress; uint8_t temp_sense[256]; - if (SenseLength && Copy) { + if (SenseLength/* && Copy*/) { scsi_device_request_sense(req->TargetID, req->LUN, temp_sense, SenseLength); /* @@ -1093,15 +1112,20 @@ aha_scsi_cmd(aha_t *dev) uint8_t temp_cdb[12]; uint32_t i; int target_cdb_len = 12; + int target_data_len; + uint8_t bit24 = !!req->Is24bit; id = req->TargetID; lun = req->LUN; target_cdb_len = scsi_device_cdb_length(id, lun); + target_data_len = aha_get_length(req, bit24); if (!scsi_device_valid(id, lun)) fatal("SCSI target on %02i:%02i has disappeared\n", id, lun); + aha_buf_alloc(req, target_data_len); + aha_log("SCSI command being executed on ID %i, LUN %i\n", id, lun); aha_log("SCSI CDB[0]=0x%02X\n", req->CmdBlock.common.Cdb[0]); @@ -1116,7 +1140,24 @@ aha_scsi_cmd(aha_t *dev) memcpy(temp_cdb, req->CmdBlock.common.Cdb, target_cdb_len); } - scsi_device_command(id, lun, req->CmdBlock.common.CdbLength, temp_cdb); + SCSI_BufferLength = target_data_len; + scsi_device_command_phase0(id, lun, req->CmdBlock.common.CdbLength, temp_cdb); + + if (SCSIPhase == SCSI_PHASE_DATA_OUT) + { + aha_buf_dma_transfer(req, bit24, target_data_len, 1); + scsi_device_command_phase1(id, lun); + } + else if (SCSIPhase == SCSI_PHASE_DATA_IN) + { + aha_buf_dma_transfer(req, bit24, target_data_len, 0); + } + else + { + if (target_data_len) { + aha_residual_on_error(req, target_data_len); + } + } aha_buf_free(req); @@ -1132,6 +1173,8 @@ aha_scsi_cmd(aha_t *dev) CCB_COMPLETE, SCSI_STATUS_CHECK_CONDITION, MBI_ERROR); } + aha_log("SCSIStatus = %02X\n", SCSIStatus); + if (temp_cdb[0] == 0x42) { thread_wait_event(dev->evt, 10); } @@ -1158,6 +1201,7 @@ aha_req_setup(aha_t *dev, uint32_t CCBPointer, Mailbox32_t *Mailbox32) Req_t *req = &dev->Req; uint8_t id, lun; uint8_t max_id = SCSI_ID_MAX-1; + int len; /* Fetch data from the Command Control Block. */ DMAPageRead(CCBPointer, (char *)&req->CmdBlock, sizeof(CCB32)); @@ -1182,11 +1226,12 @@ aha_req_setup(aha_t *dev, uint32_t CCBPointer, Mailbox32_t *Mailbox32) SCSIStatus = SCSI_STATUS_OK; SCSI_BufferLength = 0; - aha_buf_alloc(req, req->Is24bit); - if (! scsi_device_present(id, lun)) { aha_log("SCSI Target ID %i and LUN %i have no device attached\n",id,lun); - aha_buf_free(req); + len = aha_get_length(req, req->Is24bit); + if (len) { + aha_residual_on_error(req, len); + } SenseBufferFree(req, 0); aha_mbi_setup(dev, CCBPointer, &req->CmdBlock, CCB_SELECTION_TIMEOUT,SCSI_STATUS_OK,MBI_ERROR); @@ -1232,12 +1277,14 @@ aha_mbo(aha_t *dev, Mailbox32_t *Mailbox32) { Mailbox_t MailboxOut; uint32_t Outgoing; + uint32_t ccbp; if (dev->Mbx24bit) { Outgoing = dev->MailboxOutAddr + (dev->MailboxOutPosCur * sizeof(Mailbox_t)); DMAPageRead(Outgoing, (char *)&MailboxOut, sizeof(Mailbox_t)); - Mailbox32->CCBPointer = ADDR_TO_U32(MailboxOut.CCBPointer); + ccbp = *(uint32_t *) &MailboxOut; + Mailbox32->CCBPointer = (ccbp >> 24) | ((ccbp >> 8) & 0xff00) | ((ccbp << 8) & 0xff0000); Mailbox32->u.out.ActionCode = MailboxOut.CmdStatus; } else { Outgoing = dev->MailboxOutAddr + (dev->MailboxOutPosCur * sizeof(Mailbox32_t)); @@ -1267,8 +1314,6 @@ aha_do_mail(aha_t *dev) CodeOffset = dev->Mbx24bit ? 0 : 7; - uint8_t MailboxCur = dev->MailboxOutPosCur; - /* Search for a filled mailbox - stop if we have scanned all mailboxes. */ do { /* Fetch mailbox from guest memory. */ @@ -1276,7 +1321,7 @@ aha_do_mail(aha_t *dev) /* Check the next mailbox. */ aha_mbo_adv(dev); - } while ((mb32.u.out.ActionCode != MBO_START) && (mb32.u.out.ActionCode != MBO_ABORT) && (MailboxCur != dev->MailboxOutPosCur)); + } while ((mb32.u.out.ActionCode != MBO_START) && (dev->MailboxIsBIOS || (mb32.u.out.ActionCode != MBO_ABORT))); if (mb32.u.out.ActionCode == MBO_START) { aha_log("Start Mailbox Command\n"); @@ -1288,14 +1333,17 @@ aha_do_mail(aha_t *dev) aha_log("Invalid action code: %02X\n", mb32.u.out.ActionCode); } - if ((mb32.u.out.ActionCode == MBO_START) || (mb32.u.out.ActionCode == MBO_ABORT)) { + if ((mb32.u.out.ActionCode == MBO_START) || (!dev->MailboxIsBIOS && (mb32.u.out.ActionCode == MBO_ABORT))) { /* We got the mailbox, mark it as free in the guest. */ aha_log("aha_do_mail(): Writing %i bytes at %08X\n", sizeof(CmdStatus), Outgoing + CodeOffset); - DMAPageWrite(Outgoing + CodeOffset, (char *)&CmdStatus, sizeof(CmdStatus)); + DMAPageWrite(Outgoing + CodeOffset, (char *)&CmdStatus, 1); - raise_irq(dev, 0, dev->ToRaise); + if (dev->ToRaise) + { + raise_irq(dev, 0, dev->ToRaise); - while (dev->Interrupt) { + while (dev->Interrupt) { + } } } } @@ -1967,13 +2015,15 @@ aha_setbios(aha_t *dev) * * Start out with a fake BIOS firmware version. */ - dev->fwh = '1'; - dev->fwl = '0'; + dev->fwh = '3'; + dev->fwl = '4'; +#if 0 if (dev->rom_fwhigh != 0x0000) { /* Read firmware version from the BIOS. */ dev->fwh = dev->bios.rom[dev->rom_fwhigh] + 0x30; dev->fwl = dev->bios.rom[dev->rom_fwhigh+1] + 0x30; } +#endif } @@ -2081,7 +2131,7 @@ aha_init(device_t *info) case AHA_154xCF: strcpy(dev->name, "AHA-154xCF"); - dev->bios_path = L"roms/scsi/adaptec/aha1542cf211.bin"; + dev->bios_path = L"roms/scsi/adaptec/aha1542cf201.bin"; dev->nvr_path = L"aha1542cf.nvr"; dev->bid = 'E'; dev->rom_shram = 0x3F80; /* shadow RAM address base */ diff --git a/src/scsi/scsi_bios_command.c b/src/scsi/scsi_bios_command.c index 24cfe95f7..694662389 100644 --- a/src/scsi/scsi_bios_command.c +++ b/src/scsi/scsi_bios_command.c @@ -273,7 +273,7 @@ scsi_bios_command(uint8_t max_id, BIOSCMD *cmd, int8_t islba) cmd_log("BIOS CMD(READ, %08lx, %d)\n", lba, cmd->secount); #endif - scsi_device_command(cmd->id, cmd->lun, 12, cdb); + scsi_device_command_phase0(cmd->id, cmd->lun, 12, cdb); if (sector_len > 0) { cmd_log("BIOS DMA: Reading %i bytes at %08X\n", SCSI_BufferLength, dma_address); @@ -295,13 +295,6 @@ scsi_bios_command(uint8_t max_id, BIOSCMD *cmd, int8_t islba) dev->CmdBuffer = (uint8_t *)malloc(SCSI_BufferLength); memset(dev->CmdBuffer, 0x00, SCSI_BufferLength); - if (sector_len > 0) { - cmd_log("BIOS DMA: Reading %i bytes at %08X\n", - SCSI_BufferLength, dma_address); - DMAPageRead(dma_address, - (char *)dev->CmdBuffer, SCSI_BufferLength); - } - cdb[0] = GPCMD_WRITE_10; cdb[1] = (cmd->lun & 7) << 5; cdb[2] = (lba >> 24) & 0xff; @@ -314,7 +307,16 @@ scsi_bios_command(uint8_t max_id, BIOSCMD *cmd, int8_t islba) cmd_log("BIOS CMD(WRITE, %08lx, %d)\n", lba, cmd->secount); #endif - scsi_device_command(cmd->id, cmd->lun, 12, cdb); + scsi_device_command_phase0(cmd->id, cmd->lun, 12, cdb); + + if (sector_len > 0) { + cmd_log("BIOS DMA: Reading %i bytes at %08X\n", + SCSI_BufferLength, dma_address); + DMAPageRead(dma_address, + (char *)dev->CmdBuffer, SCSI_BufferLength); + } + + scsi_device_command_phase1(cmd->id, cmd->lun); if (dev->CmdBuffer != NULL) { free(dev->CmdBuffer); @@ -335,7 +337,7 @@ scsi_bios_command(uint8_t max_id, BIOSCMD *cmd, int8_t islba) cdb[7] = (sector_len >> 8) & 0xff; cdb[8] = sector_len & 0xff; - scsi_device_command(cmd->id, cmd->lun, 12, cdb); + scsi_device_command_phase0(cmd->id, cmd->lun, 12, cdb); return(completion_code(scsi_device_sense(cmd->id, cmd->lun))); @@ -353,7 +355,7 @@ scsi_bios_command(uint8_t max_id, BIOSCMD *cmd, int8_t islba) cdb[0] = GPCMD_FORMAT_UNIT; cdb[1] = (cmd->lun & 7) << 5; - scsi_device_command(cmd->id, cmd->lun, 12, cdb); + scsi_device_command_phase0(cmd->id, cmd->lun, 12, cdb); return(completion_code(scsi_device_sense(cmd->id, cmd->lun))); @@ -394,7 +396,7 @@ scsi_bios_command(uint8_t max_id, BIOSCMD *cmd, int8_t islba) cdb[4] = (lba >> 8) & 0xff; cdb[5] = lba & 0xff; - scsi_device_command(cmd->id, cmd->lun, 12, cdb); + scsi_device_command_phase0(cmd->id, cmd->lun, 12, cdb); return((SCSIStatus == SCSI_STATUS_OK) ? 1 : 0); @@ -408,7 +410,7 @@ scsi_bios_command(uint8_t max_id, BIOSCMD *cmd, int8_t islba) cdb[0] = GPCMD_TEST_UNIT_READY; cdb[1] = (cmd->lun & 7) << 5; - scsi_device_command(cmd->id, cmd->lun, 12, cdb); + scsi_device_command_phase0(cmd->id, cmd->lun, 12, cdb); return(completion_code(scsi_device_sense(cmd->id, cmd->lun))); @@ -418,7 +420,7 @@ scsi_bios_command(uint8_t max_id, BIOSCMD *cmd, int8_t islba) cdb[0] = GPCMD_REZERO_UNIT; cdb[1] = (cmd->lun & 7) << 5; - scsi_device_command(cmd->id, cmd->lun, 12, cdb); + scsi_device_command_phase0(cmd->id, cmd->lun, 12, cdb); return(completion_code(scsi_device_sense(cmd->id, cmd->lun))); diff --git a/src/scsi/scsi_buslogic.c b/src/scsi/scsi_buslogic.c index 0950f7d58..9745bf26f 100644 --- a/src/scsi/scsi_buslogic.c +++ b/src/scsi/scsi_buslogic.c @@ -10,12 +10,11 @@ * 0 - BT-545C ISA; * 1 - BT-958D PCI (but BT-545C ISA on non-PCI machines) * - * Version: @(#)scsi_buslogic.c 1.0.19 2017/10/09 + * Version: @(#)scsi_buslogic.c 1.0.20 2017/10/10 * * Authors: TheCollector1995, * Miran Grca, * Fred N. van Kempen, - * * Copyright 2016,2017 Miran Grca. * Copyright 2017 Fred N. van Kempen. */ @@ -531,8 +530,9 @@ enum { CHIP_BUSLOGIC_PCI }; -/* #define ENABLE_BUSLOGIC_LOG 0 */ -int buslogic_do_log = 0; +#if ENABLE_BUSLOGIC_LOG +int buslogic_do_log = ENABLE_BUSLOGIC_LOG; +#endif static void BuslogicLog(const char *format, ...) @@ -883,7 +883,7 @@ BuslogicMailboxInSetup(Buslogic_t *bl, uint32_t CCBPointer, CCBU *CmdBlock, req->TargetStatus = TargetStatus; req->MailboxCompletionCode = MailboxCompletionCode; - pclog("Mailbox in setup\n"); + BuslogicLog("BuslogicMailboxInSetup(): Request set up\n"); } @@ -912,27 +912,26 @@ BuslogicMailboxIn(Buslogic_t *bl) CmdBlock->common.TargetStatus = TargetStatus; /* Rewrite the CCB up to the CDB. */ - pclog("CCB rewritten to the CDB (pointer %08X, length 18)\n", CCBPointer); + BuslogicLog("BuslogicMailboxIn(): CCB rewritten to the CDB (pointer %08X)\n", CCBPointer); DMAPageWrite(CCBPointer, (char *)CmdBlock, 18); } else { - pclog("Mailbox not found!\n"); + BuslogicLog("BuslogicMailboxIn(): Mailbox not found!\n"); } - pclog("Host Status 0x%02X, Target Status 0x%02X\n", - HostStatus, TargetStatus); - + BuslogicLog("BuslogicMailboxIn(): Host Status 0x%02X, Target Status 0x%02X\n",HostStatus,TargetStatus); + if (bl->Mbx24bit) { MailboxIn.CmdStatus = Mailbox32.u.in.CompletionCode; U32_TO_ADDR(MailboxIn.CCBPointer, Mailbox32.CCBPointer); - pclog("Mailbox 24-bit: Status=0x%02X, CCB at 0x%04X\n", MailboxIn.CmdStatus, ADDR_TO_U32(MailboxIn.CCBPointer)); + BuslogicLog("BuslogicMailboxIn(): Mailbox 24-bit: Status=0x%02X, CCB at 0x%04X\n", MailboxIn.CmdStatus, ADDR_TO_U32(MailboxIn.CCBPointer)); DMAPageWrite(Incoming, (char *)&MailboxIn, sizeof(Mailbox_t)); - pclog("%i bytes of 24-bit mailbox written to: %08X\n", sizeof(Mailbox_t), Incoming); + BuslogicLog("BuslogicMailboxIn(): %i bytes of 24-bit mailbox written to: %08X\n", sizeof(Mailbox_t), Incoming); } else { - pclog("Mailbox 32-bit: Status=0x%02X, CCB at 0x%04X\n", Mailbox32.u.in.CompletionCode, Mailbox32.CCBPointer); + BuslogicLog("BuslogicMailboxIn(): Mailbox 32-bit: Status=0x%02X, CCB at 0x%04X\n", Mailbox32.u.in.CompletionCode, Mailbox32.CCBPointer); DMAPageWrite(Incoming, (char *)&Mailbox32, sizeof(Mailbox32_t)); - pclog("%i bytes of 32-bit mailbox written to: %08X\n", sizeof(Mailbox32_t), Incoming); + BuslogicLog("BuslogicMailboxIn(): %i bytes of 32-bit mailbox written to: %08X\n", sizeof(Mailbox32_t), Incoming); } bl->MailboxInPosCur++; @@ -940,7 +939,8 @@ BuslogicMailboxIn(Buslogic_t *bl) bl->MailboxInPosCur = 0; bl->ToRaise = INTR_MBIF | INTR_ANY; - if (bl->MailboxOutInterrupts) { + if (bl->MailboxOutInterrupts) + { bl->ToRaise |= INTR_MBOA; } } @@ -966,25 +966,25 @@ BuslogicReadSGEntries(int Is24bit, uint32_t SGList, uint32_t Entries, SGE32 *SG) } -static void -BuslogicDataBufferAllocate(Req_t *req, int Is24bit) +static int +BuslogicDataBufferLength(Req_t *req, int Is24bit) { - uint32_t sg_buffer_pos = 0; uint32_t DataPointer, DataLength; uint32_t SGEntryLength = (Is24bit ? sizeof(SGE) : sizeof(SGE32)); + uint32_t Address; if (Is24bit) { DataPointer = ADDR_TO_U32(req->CmdBlock.old.DataPointer); DataLength = ADDR_TO_U32(req->CmdBlock.old.DataLength); + pclog("Data length: %08X\n", req->CmdBlock.old.DataLength); } else { DataPointer = req->CmdBlock.new.DataPointer; DataLength = req->CmdBlock.new.DataLength; } - pclog("Data Buffer write: length %d, pointer 0x%04X\n", + BuslogicLog("BuslogicDataBufferLength(): Data Buffer write: length %d, pointer 0x%04X\n", DataLength, DataPointer); - if (SCSIDevices[req->TargetID][req->LUN].CmdBuffer != NULL) - { + if (SCSIDevices[req->TargetID][req->LUN].CmdBuffer != NULL) { free(SCSIDevices[req->TargetID][req->LUN].CmdBuffer); SCSIDevices[req->TargetID][req->LUN].CmdBuffer = NULL; } @@ -1005,30 +1005,89 @@ BuslogicDataBufferAllocate(Req_t *req, int Is24bit) BuslogicReadSGEntries(Is24bit, SGAddrCurrent, SGRead, SGBuffer); - for (ScatterEntry = 0; ScatterEntry < SGRead; ScatterEntry++) { - uint32_t Address; - - pclog("BusLogic S/G Write: ScatterEntry=%u\n", ScatterEntry); + for (ScatterEntry=0; ScatterEntry 0); - pclog("Data to transfer (S/G) %d\n", DataToTransfer); + BuslogicLog("BuslogicDataBufferLength(): Data to transfer (S/G) %d\n", DataToTransfer); - SCSI_BufferLength = DataToTransfer; + return DataToTransfer; + } else if (req->CmdBlock.common.Opcode == SCSI_INITIATOR_COMMAND || + req->CmdBlock.common.Opcode == SCSI_INITIATOR_COMMAND_RES) { + return DataLength; + } else { + return 0; + } + } else { + return 0; + } +} - SCSIDevices[req->TargetID][req->LUN].CmdBuffer = (uint8_t *) malloc(DataToTransfer); - memset(SCSIDevices[req->TargetID][req->LUN].CmdBuffer, 0, DataToTransfer); +static void +BuslogicResidualOnError(Req_t *req, int length) +{ + if ((req->CmdBlock.common.Opcode == SCSI_INITIATOR_COMMAND_RES) || + (req->CmdBlock.common.Opcode == SCATTER_GATHER_COMMAND_RES)) { + /* Should be 0 when scatter/gather? */ + + if (req->Is24bit) { + U32_TO_ADDR(req->CmdBlock.old.DataLength, length); + BuslogicLog("BuslogicResidualOnError(): 24-bit Residual data length for reading: %d\n", + ADDR_TO_U32(req->CmdBlock.old.DataLength)); + } else { + req->CmdBlock.new.DataLength = length; + BuslogicLog("BuslogicResidualOnError(): 32-bit Residual data length for reading: %d\n", + req->CmdBlock.new.DataLength); + } + } +} + + +static void +BuslogicDMATransfer(Req_t *req, int Is24bit, int TransferLength, int dir) +{ + uint32_t sg_buffer_pos = 0; + uint32_t DataPointer, DataLength; + uint32_t SGEntryLength = (Is24bit ? sizeof(SGE) : sizeof(SGE32)); + uint32_t Address; + uint32_t Residual; + /* uint32_t CCBPointer = req->CCBPointer; */ + + if (Is24bit) { + DataPointer = ADDR_TO_U32(req->CmdBlock.old.DataPointer); + DataLength = ADDR_TO_U32(req->CmdBlock.old.DataLength); + } else { + DataPointer = req->CmdBlock.new.DataPointer; + DataLength = req->CmdBlock.new.DataLength; + } + BuslogicLog("BuslogicDMATransfer(): Data Buffer %s: length %d, pointer 0x%04X\n", + dir ? "write" : "read", SCSI_BufferLength, DataPointer); + + if ((req->CmdBlock.common.ControlByte != 0x03) && DataLength) { + if (req->CmdBlock.common.Opcode == SCATTER_GATHER_COMMAND || + req->CmdBlock.common.Opcode == SCATTER_GATHER_COMMAND_RES) { + uint32_t SGRead; + uint32_t ScatterEntry; + SGE32 SGBuffer[MAX_SG_DESCRIPTORS]; + uint32_t SGLeft = DataLength / SGEntryLength; + uint32_t SGAddrCurrent = DataPointer; + uint32_t DataToTransfer = 0; + + TransferLength -= SCSI_BufferLength; + /* 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 read/write commands. */ if ((req->CmdBlock.common.ControlByte == CCB_DATA_XFER_OUT) || + (req->CmdBlock.common.ControlByte == CCB_DATA_XFER_IN) || (req->CmdBlock.common.ControlByte == 0x00)) { SGLeft = DataLength / SGEntryLength; SGAddrCurrent = DataPointer; @@ -1040,210 +1099,411 @@ BuslogicDataBufferAllocate(Req_t *req, int Is24bit) BuslogicReadSGEntries(Is24bit, SGAddrCurrent, SGRead, SGBuffer); - for (ScatterEntry = 0; ScatterEntry < SGRead; ScatterEntry++) { - uint32_t Address; + for (ScatterEntry=0; ScatterEntryTargetID][req->LUN].CmdBuffer + sg_buffer_pos, DataToTransfer); + if (dir && ((req->CmdBlock.common.ControlByte == CCB_DATA_XFER_OUT) || (req->CmdBlock.common.ControlByte == 0x00))) + { + BuslogicLog("BuslogicDMATransfer(): S/G Read: Address=%08X DatatoTransfer=%u\n", Address, (SCSI_BufferLength < DataToTransfer) ? SCSI_BufferLength : DataToTransfer); + DMAPageRead(Address, (char *)SCSIDevices[req->TargetID][req->LUN].CmdBuffer + sg_buffer_pos, (SCSI_BufferLength < DataToTransfer) ? SCSI_BufferLength : DataToTransfer); + } + else + if (!dir && ((req->CmdBlock.common.ControlByte == CCB_DATA_XFER_IN) || (req->CmdBlock.common.ControlByte == 0x00))) + { + BuslogicLog("BuslogicDMATransfer(): S/G Write: Address=%08X DatatoTransfer=%u\n", Address, (SCSI_BufferLength < DataToTransfer) ? SCSI_BufferLength : DataToTransfer); + DMAPageWrite(Address, (char *)SCSIDevices[req->TargetID][req->LUN].CmdBuffer + sg_buffer_pos, (SCSI_BufferLength < DataToTransfer) ? SCSI_BufferLength : DataToTransfer); + } sg_buffer_pos += DataToTransfer; + SCSI_BufferLength -= DataToTransfer; } SGAddrCurrent += SGRead * (Is24bit ? sizeof(SGE) : sizeof(SGE32)); - } while (SGLeft > 0); + } while (SGLeft > 0); } } else if (req->CmdBlock.common.Opcode == SCSI_INITIATOR_COMMAND || req->CmdBlock.common.Opcode == SCSI_INITIATOR_COMMAND_RES) { - uint32_t Address = DataPointer; + Address = DataPointer; SCSI_BufferLength = DataLength; - SCSIDevices[req->TargetID][req->LUN].CmdBuffer = (uint8_t *) malloc(DataLength); - memset(SCSIDevices[req->TargetID][req->LUN].CmdBuffer, 0, DataLength); - - if (DataLength > 0) { - DMAPageRead(Address, - (char *)SCSIDevices[req->TargetID][req->LUN].CmdBuffer, - SCSI_BufferLength); + if ((DataLength > 0) && (SCSI_BufferLength > 0)) { + if (dir && ((req->CmdBlock.common.ControlByte == CCB_DATA_XFER_OUT) || (req->CmdBlock.common.ControlByte == 0x00))) + { + BuslogicLog("BuslogicDMATransfer(): Read: Address=%08X DatatoTransfer=%u\n", Address, (SCSI_BufferLength < DataLength) ? SCSI_BufferLength : DataLength); + DMAPageRead(Address, (char *)SCSIDevices[req->TargetID][req->LUN].CmdBuffer, (SCSI_BufferLength < DataLength) ? SCSI_BufferLength : DataLength); + } + else + if (!dir && ((req->CmdBlock.common.ControlByte == CCB_DATA_XFER_IN) || (req->CmdBlock.common.ControlByte == 0x00))) + { + BuslogicLog("BuslogicDMATransfer(): Write: Address=%08X DatatoTransfer=%u\n", Address, (SCSI_BufferLength < DataLength) ? SCSI_BufferLength : DataLength); + DMAPageWrite(Address, (char *)SCSIDevices[req->TargetID][req->LUN].CmdBuffer, (SCSI_BufferLength < DataLength) ? SCSI_BufferLength : DataLength); + } } } } -} - - -static void -BuslogicDataBufferFree(Req_t *req) -{ - uint32_t DataPointer = 0; - uint32_t DataLength = 0; - uint32_t sg_buffer_pos = 0; - uint32_t SGRead; - uint32_t ScatterEntry; - SGE32 SGBuffer[MAX_SG_DESCRIPTORS]; - uint32_t SGEntrySize; - uint32_t SGLeft; - uint32_t SGAddrCurrent; - uint32_t Address; - uint32_t Residual; - - if (req->Is24bit) { - DataPointer = ADDR_TO_U32(req->CmdBlock.old.DataPointer); - DataLength = ADDR_TO_U32(req->CmdBlock.old.DataLength); - } else { - DataPointer = req->CmdBlock.new.DataPointer; - DataLength = req->CmdBlock.new.DataLength; - } - - if ((DataLength != 0) && (req->CmdBlock.common.Cdb[0] == GPCMD_TEST_UNIT_READY)) { - pclog("Data length not 0 with TEST UNIT READY: %i (%i)\n", - DataLength, SCSI_BufferLength); - } - - if (req->CmdBlock.common.Cdb[0] == GPCMD_TEST_UNIT_READY) { - DataLength = 0; - } - - pclog("Data Buffer read: length %d, pointer 0x%04X\n", - DataLength, DataPointer); - - /* If the control byte is 0x00, it means that the transfer direction is set up by the SCSI command without - checking its length, so do this procedure for both read/write commands. */ - if ((DataLength > 0) && - ((req->CmdBlock.common.ControlByte == CCB_DATA_XFER_IN) || - (req->CmdBlock.common.ControlByte == 0x00))) { - if ((req->CmdBlock.common.Opcode == SCATTER_GATHER_COMMAND) || - (req->CmdBlock.common.Opcode == SCATTER_GATHER_COMMAND_RES)) { - SGEntrySize = (req->Is24bit ? sizeof(SGE) : sizeof(SGE32)); - SGLeft = DataLength / SGEntrySize; - SGAddrCurrent = DataPointer; - - do { - SGRead = (SGLeft < ELEMENTS(SGBuffer)) ? SGLeft : ELEMENTS(SGBuffer); - SGLeft -= SGRead; - - BuslogicReadSGEntries(req->Is24bit, SGAddrCurrent, - SGRead, SGBuffer); - - for (ScatterEntry = 0; ScatterEntry < SGRead; ScatterEntry++) { - uint32_t Address; - uint32_t DataToTransfer; - - pclog("BusLogic S/G: ScatterEntry=%u\n", ScatterEntry); - - Address = SGBuffer[ScatterEntry].SegmentPointer; - DataToTransfer = SGBuffer[ScatterEntry].Segment; - - pclog("BusLogic S/G: Writing %i bytes at %08X\n", DataToTransfer, Address); - - DMAPageWrite(Address, (char *)SCSIDevices[req->TargetID][req->LUN].CmdBuffer + sg_buffer_pos, DataToTransfer); - sg_buffer_pos += DataToTransfer; - } - - SGAddrCurrent += (SGRead * SGEntrySize); - } while (SGLeft > 0); - } else if (req->CmdBlock.common.Opcode == SCSI_INITIATOR_COMMAND || - req->CmdBlock.common.Opcode == SCSI_INITIATOR_COMMAND_RES) { - Address = DataPointer; - - pclog("BusLogic DMA: Writing %i bytes at %08X\n", DataLength, Address); - DMAPageWrite(Address, (char *)SCSIDevices[req->TargetID][req->LUN].CmdBuffer, DataLength); - } - } if ((req->CmdBlock.common.Opcode == SCSI_INITIATOR_COMMAND_RES) || (req->CmdBlock.common.Opcode == SCATTER_GATHER_COMMAND_RES)) { /* Should be 0 when scatter/gather? */ - if (DataLength >= SCSI_BufferLength) { - Residual = DataLength; - Residual -= SCSI_BufferLength; + if (TransferLength > 0) { + Residual = TransferLength; } else { Residual = 0; } if (req->Is24bit) { U32_TO_ADDR(req->CmdBlock.old.DataLength, Residual); - pclog("24-bit Residual data length for reading: %d\n", + BuslogicLog("BuslogicDMATransfer(): 24-bit Residual data length for reading: %d\n", ADDR_TO_U32(req->CmdBlock.old.DataLength)); } else { req->CmdBlock.new.DataLength = Residual; - pclog("32-bit Residual data length for reading: %d\n", + BuslogicLog("BuslogicDMATransfer(): 32-bit Residual data length for reading: %d\n", req->CmdBlock.new.DataLength); } } +} - if (SCSIDevices[req->TargetID][req->LUN].CmdBuffer != NULL) - { - free(SCSIDevices[req->TargetID][req->LUN].CmdBuffer); - SCSIDevices[req->TargetID][req->LUN].CmdBuffer = NULL; + +static void +BuslogicDataBufferAllocate(uint8_t ID, uint8_t LUN, int length) +{ + if (SCSIDevices[ID][LUN].CmdBuffer != NULL) { + free(SCSIDevices[ID][LUN].CmdBuffer); + SCSIDevices[ID][LUN].CmdBuffer = NULL; + } + + BuslogicLog("BuslogicDataBufferAllocate(): Allocating data buffer (%i bytes)\n", length); + SCSIDevices[ID][LUN].CmdBuffer = (uint8_t *) malloc(length); + memset(SCSIDevices[ID][LUN].CmdBuffer, 0, length); +} + + +static void +BuslogicDataBufferFree(uint8_t ID, uint8_t LUN) +{ + if (SCSIDevices[ID][LUN].CmdBuffer != NULL) { + free(SCSIDevices[ID][LUN].CmdBuffer); + SCSIDevices[ID][LUN].CmdBuffer = NULL; } } + static uint8_t BuslogicConvertSenseLength(uint8_t RequestSenseLength) { - pclog("Unconverted Request Sense length %i\n", RequestSenseLength); + BuslogicLog("BuslogicConvertSenseLength(): Unconverted Request Sense length %i\n", RequestSenseLength); if (RequestSenseLength == 0) RequestSenseLength = 14; else if (RequestSenseLength == 1) RequestSenseLength = 0; - pclog("Request Sense length %i\n", RequestSenseLength); + BuslogicLog("BuslogicConvertSenseLength(): Request Sense length %i\n", RequestSenseLength); return(RequestSenseLength); } static void -BuslogicSCSIBIOSDataBufferAllocate(ESCMD *ESCSICmd, uint8_t TargetID, uint8_t LUN) +SenseBufferFree(Req_t *req, int Copy) { - uint32_t DataPointer, DataLength; - - DataPointer = ESCSICmd->DataPointer; - DataLength = ESCSICmd->DataLength; + uint8_t SenseLength = BuslogicConvertSenseLength(req->CmdBlock.common.RequestSenseLength); + uint32_t SenseBufferAddress; + uint8_t temp_sense[256]; - pclog("BIOS Data Buffer write: length %d, pointer 0x%04X\n", - DataLength, DataPointer); + if (SenseLength/* && Copy*/) { + scsi_device_request_sense(req->TargetID, req->LUN, temp_sense, SenseLength); - if (SCSIDevices[TargetID][LUN].CmdBuffer != NULL) - { - free(SCSIDevices[TargetID][LUN].CmdBuffer); - SCSIDevices[TargetID][LUN].CmdBuffer = NULL; - } - - if ((ESCSICmd->DataDirection != 0x03) && DataLength) - { - uint32_t Address = DataPointer; - - SCSI_BufferLength = DataLength; - - SCSIDevices[TargetID][LUN].CmdBuffer = (uint8_t *) malloc(DataLength); - memset(SCSIDevices[TargetID][LUN].CmdBuffer, 0, DataLength); - - if (DataLength > 0) { - DMAPageRead(Address, - (char *)SCSIDevices[TargetID][LUN].CmdBuffer, - SCSI_BufferLength); - } + /* + * 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 (req->Is24bit) { + SenseBufferAddress = req->CCBPointer; + SenseBufferAddress += req->CmdBlock.common.CdbLength + 18; + } else { + SenseBufferAddress = req->CmdBlock.new.SensePointer; } + + BuslogicLog("SenseBufferFree(): Request Sense address: %02X\n", SenseBufferAddress); + + BuslogicLog("SenseBufferFree(): Writing %i bytes at %08X\n", + SenseLength, SenseBufferAddress); + DMAPageWrite(SenseBufferAddress, (char *)temp_sense, SenseLength); + BuslogicLog("SenseBufferFree(): Sense data written to buffer: %02X %02X %02X\n", + temp_sense[2], temp_sense[12], temp_sense[13]); + } } + static void -BuslogicSCSIBIOSDataBufferFree(ESCMD *ESCSICmd, uint8_t TargetID, uint8_t LUN) +BuslogicSCSICommand(Buslogic_t *bl) { - uint32_t DataPointer = 0; - uint32_t DataLength = 0; + Req_t *req = &bl->Req; + uint8_t id, lun; + uint8_t temp_cdb[12]; + uint32_t i; + int target_cdb_len = 12; + int target_data_len; + uint8_t bit24 = !!req->Is24bit; + + id = req->TargetID; + lun = req->LUN; + + target_cdb_len = scsi_device_cdb_length(id, lun); + target_data_len = BuslogicDataBufferLength(req, bit24); + + if (!scsi_device_valid(id, lun)) + fatal("SCSI target on %02i:%02i has disappeared\n", id, lun); + + BuslogicDataBufferAllocate(id, lun, target_data_len); + + BuslogicLog("BuslogicSCSICommand(): SCSI command being executed on ID %i, LUN %i\n", id, lun); + + BuslogicLog("BuslogicSCSICommand(): SCSI CDB[0]=0x%02X\n", req->CmdBlock.common.Cdb[0]); + for (i=1; iCmdBlock.common.CdbLength; i++) + BuslogicLog("BuslogicSCSICommand(): SCSI CDB[%i]=%i\n", i, req->CmdBlock.common.Cdb[i]); + + memset(temp_cdb, 0x00, target_cdb_len); + if (req->CmdBlock.common.CdbLength <= target_cdb_len) { + memcpy(temp_cdb, req->CmdBlock.common.Cdb, + req->CmdBlock.common.CdbLength); + } else { + memcpy(temp_cdb, req->CmdBlock.common.Cdb, target_cdb_len); + } + + SCSI_BufferLength = target_data_len; + scsi_device_command_phase0(id, lun, req->CmdBlock.common.CdbLength, temp_cdb); + + if (SCSIPhase == SCSI_PHASE_DATA_OUT) + { + BuslogicDMATransfer(req, bit24, target_data_len, 1); + scsi_device_command_phase1(id, lun); + } + else if (SCSIPhase == SCSI_PHASE_DATA_IN) + { + BuslogicDMATransfer(req, bit24, target_data_len, 0); + } + else + { + if (target_data_len) { + BuslogicResidualOnError(req, target_data_len); + } + } + + BuslogicDataBufferFree(id, lun); + + SenseBufferFree(req, (SCSIStatus != SCSI_STATUS_OK)); + + BuslogicLog("BuslogicSCSICommand(): Request complete\n"); + + if (SCSIStatus == SCSI_STATUS_OK) { + BuslogicMailboxInSetup(bl, req->CCBPointer, &req->CmdBlock, + CCB_COMPLETE, SCSI_STATUS_OK, MBI_SUCCESS); + } else if (SCSIStatus == SCSI_STATUS_CHECK_CONDITION) { + BuslogicMailboxInSetup(bl, req->CCBPointer, &req->CmdBlock, + CCB_COMPLETE, SCSI_STATUS_CHECK_CONDITION, MBI_ERROR); + } + + BuslogicLog("BuslogicSCSICommand(): SCSIStatus = %02X\n", SCSIStatus); + + if (temp_cdb[0] == 0x42) { + thread_wait_event(bl->evt, 10); + } +} + + +static void +BuslogicSCSIRequestSetup(Buslogic_t *bl, uint32_t CCBPointer, Mailbox32_t *Mailbox32) +{ + Req_t *req = &bl->Req; + uint8_t id, lun; + uint8_t max_id = SCSI_ID_MAX-1; + int len; + + /* Fetch data from the Command Control Block. */ + DMAPageRead(CCBPointer, (char *)&req->CmdBlock, sizeof(CCB32)); + + req->Is24bit = bl->Mbx24bit; + req->CCBPointer = CCBPointer; + req->TargetID = bl->Mbx24bit ? req->CmdBlock.old.Id : req->CmdBlock.new.Id; + req->LUN = bl->Mbx24bit ? req->CmdBlock.old.Lun : req->CmdBlock.new.Lun; + + id = req->TargetID; + lun = req->LUN; + if ((id > max_id) || (lun > 7)) { + BuslogicMailboxInSetup(bl, CCBPointer, &req->CmdBlock, + CCB_INVALID_CCB, SCSI_STATUS_OK, MBI_ERROR); + BuslogicLog("BuslogicSCSIRequestSetup(): Invalid ID or LUN, send incoming mailbox\n"); + BuslogicMailboxIn(bl); + return; + } + + BuslogicLog("BuslogicSCSIRequestSetup(): Scanning SCSI Target ID %i\n", id); + + SCSIStatus = SCSI_STATUS_OK; + SCSI_BufferLength = 0; + + if (! scsi_device_present(id, lun)) { + BuslogicLog("BuslogicSCSIRequestSetup(): SCSI Target ID %i and LUN %i have no device attached\n",id,lun); + len = BuslogicDataBufferLength(req, req->Is24bit); + if (len) { + BuslogicResidualOnError(req, len); + } + SenseBufferFree(req, 0); + BuslogicMailboxInSetup(bl, CCBPointer, &req->CmdBlock, + CCB_SELECTION_TIMEOUT,SCSI_STATUS_OK,MBI_ERROR); + BuslogicLog("BuslogicSCSIRequestSetup(): Callback: Send incoming mailbox\n"); + BuslogicMailboxIn(bl); + } else { + BuslogicLog("BuslogicSCSIRequestSetup(): SCSI Target ID %i and LUN %i detected and working\n", id, lun); + + BuslogicLog("BuslogicSCSIRequestSetup(): Transfer Control %02X\n", req->CmdBlock.common.ControlByte); + BuslogicLog("BuslogicSCSIRequestSetup(): CDB Length %i\n", req->CmdBlock.common.CdbLength); + BuslogicLog("BuslogicSCSIRequestSetup(): CCB Opcode %x\n", req->CmdBlock.common.Opcode); + if (req->CmdBlock.common.ControlByte > 0x03) { + BuslogicLog("BuslogicSCSIRequestSetup(): Invalid control byte: %02X\n", + req->CmdBlock.common.ControlByte); + } + + BuslogicLog("BuslogicSCSIRequestSetup(): Callback: Process SCSI request\n"); + BuslogicSCSICommand(bl); + + BuslogicLog("BuslogicSCSIRequestSetup(): Callback: Send incoming mailbox\n"); + BuslogicMailboxIn(bl); + } +} + + +static void +BuslogicSCSIRequestAbort(Buslogic_t *bl, uint32_t CCBPointer) +{ + CCBU CmdBlock; + + /* Fetch data from the Command Control Block. */ + DMAPageRead(CCBPointer, (char *)&CmdBlock, sizeof(CCB32)); + + /* Only SCSI CD-ROMs are supported at the moment, SCSI hard disk support will come soon. */ + BuslogicMailboxInSetup(bl, CCBPointer, &CmdBlock, + 0x26, SCSI_STATUS_OK, MBI_NOT_FOUND); + + pclog("BusLogicSCSIRequestAbort(): Send incoming mailbox\n"); + BuslogicMailboxIn(bl); +} + + +static uint32_t +BuslogicMailboxOut(Buslogic_t *bl, Mailbox32_t *Mailbox32) +{ + Mailbox_t MailboxOut; + uint32_t Outgoing; + + if (bl->Mbx24bit) { + Outgoing = bl->MailboxOutAddr + (bl->MailboxOutPosCur * sizeof(Mailbox_t)); + DMAPageRead(Outgoing, (char *)&MailboxOut, sizeof(Mailbox_t)); + + Mailbox32->CCBPointer = ADDR_TO_U32(MailboxOut.CCBPointer); + Mailbox32->u.out.ActionCode = MailboxOut.CmdStatus; + } else { + Outgoing = bl->MailboxOutAddr + (bl->MailboxOutPosCur * sizeof(Mailbox32_t)); + + DMAPageRead(Outgoing, (char *)Mailbox32, sizeof(Mailbox32_t)); + } + + return Outgoing; +} + + +static void +BuslogicMailboxOutAdvance(Buslogic_t *bl) +{ + bl->MailboxOutPosCur = (bl->MailboxOutPosCur + 1) % bl->MailboxCount; +} + + +static uint8_t +BuslogicProcessMailbox(Buslogic_t *bl) +{ + Mailbox32_t mb32; + uint32_t Outgoing; + uint8_t CmdStatus = MBO_FREE; + uint32_t CodeOffset = 0; + + CodeOffset = bl->Mbx24bit ? 0 : 7; + +#if 0 + pclog("BuslogicProcessMailbox(): Operating in %s mode\n", bl->LocalRAM.structured.autoSCSIData.fAggressiveRoundRobinMode ? "aggressive" : "strict"); +#endif + + /* 0 = strict, 1 = aggressive */ + if (bl->LocalRAM.structured.autoSCSIData.fAggressiveRoundRobinMode) { + /* Search for a filled mailbox - stop if we have scanned all mailboxes. */ + do { + /* Fetch mailbox from guest memory. */ + Outgoing = BuslogicMailboxOut(bl, &mb32); + + /* Check the next mailbox. */ + BuslogicMailboxOutAdvance(bl); + } while ((mb32.u.out.ActionCode != MBO_START) && (mb32.u.out.ActionCode != MBO_ABORT)); + } else { + Outgoing = BuslogicMailboxOut(bl, &mb32); + + if (mb32.u.out.ActionCode == MBO_FREE) { + return 0; + } + } + +#if 0 + pclog("BuslogicProcessMailbox(): Outgoing mailbox action code: %i\n", mb32.u.out.ActionCode); +#endif + + if (mb32.u.out.ActionCode == MBO_START) { + pclog("Start Mailbox Command\n"); + BuslogicSCSIRequestSetup(bl, mb32.CCBPointer, &mb32); + } else if (mb32.u.out.ActionCode == MBO_ABORT) { + pclog("Abort Mailbox Command\n"); + BuslogicSCSIRequestAbort(bl, mb32.CCBPointer); + } else { + BuslogicLog("BuslogicProcessMailbox(): Invalid action code: %02X\n", mb32.u.out.ActionCode); + } + + if ((mb32.u.out.ActionCode == MBO_START) || (mb32.u.out.ActionCode == MBO_ABORT)) { + /* We got the mailbox, mark it as free in the guest. */ + BuslogicLog("BuslogicProcessMailbox(): Writing %i bytes at %08X\n", sizeof(CmdStatus), Outgoing + CodeOffset); + DMAPageWrite(Outgoing + CodeOffset, (char *)&CmdStatus, sizeof(CmdStatus)); + + BuslogicRaiseInterrupt(bl, 0, bl->ToRaise); + + while (bl->Interrupt) { + } + } + + /* Advance to the next mailbox. */ + if (! bl->LocalRAM.structured.autoSCSIData.fAggressiveRoundRobinMode) + BuslogicMailboxOutAdvance(bl); + + return 1; +} + + +static void +BuslogicSCSIBIOSDMATransfer(ESCMD *ESCSICmd, uint8_t TargetID, uint8_t LUN, int dir) +{ + uint32_t DataPointer = ESCSICmd->DataPointer; + uint32_t DataLength = ESCSICmd->DataLength; uint32_t Address; - uint32_t Residual; - - DataPointer = ESCSICmd->DataPointer; - DataLength = ESCSICmd->DataLength; +#if 0 if ((DataLength != 0) && (ESCSICmd->CDB[0] == GPCMD_TEST_UNIT_READY)) { pclog("Data length not 0 with TEST UNIT READY: %i (%i)\n", DataLength, SCSI_BufferLength); @@ -1252,41 +1512,37 @@ BuslogicSCSIBIOSDataBufferFree(ESCMD *ESCSICmd, uint8_t TargetID, uint8_t LUN) if (ESCSICmd->CDB[0] == GPCMD_TEST_UNIT_READY) { DataLength = 0; } +#endif - pclog("BIOS Data Buffer read: length %d, pointer 0x%04X\n", - DataLength, DataPointer); + if (ESCSICmd->DataDirection == 0x03) { + /* Non-data command. */ + BuslogicLog("BuslogicSCSIBIOSDMATransfer(): Non-data control byte\n"); + return; + } + + BuslogicLog("BuslogicSCSIBIOSDMATransfer(): BIOS Data Buffer read: length %d, pointer 0x%04X\n", DataLength, DataPointer); /* If the control byte is 0x00, it means that the transfer direction is set up by the SCSI command without checking its length, so do this procedure for both read/write commands. */ - if ((DataLength > 0) && - ((ESCSICmd->DataDirection == CCB_DATA_XFER_IN) || - (ESCSICmd->DataDirection == 0x00))) + if ((DataLength > 0) && (SCSI_BufferLength > 0)) { + Address = DataPointer; + + if (dir && ((ESCSICmd->DataDirection == CCB_DATA_XFER_OUT) || (ESCSICmd->DataDirection == 0x00))) + { + pclog("BusLogic BIOS DMA: Reading %i bytes from %08X\n", DataLength, Address); + DMAPageRead(Address, (char *)SCSIDevices[TargetID][LUN].CmdBuffer, DataLength); + } + else if (!dir && ((ESCSICmd->DataDirection == CCB_DATA_XFER_IN) || (ESCSICmd->DataDirection == 0x00))) { Address = DataPointer; - pclog("BusLogic BIOS DMA: Writing %i bytes at %08X\n", DataLength, Address); - DMAPageWrite(Address, (char *)SCSIDevices[TargetID][LUN].CmdBuffer, DataLength); - } - - /* Should be 0 when scatter/gather? */ - if (DataLength >= SCSI_BufferLength) { - Residual = DataLength; - Residual -= SCSI_BufferLength; - } else { - Residual = 0; + pclog("BusLogic BIOS DMA: Writing %i bytes at %08X\n", (SCSI_BufferLength < DataLength) ? SCSI_BufferLength : DataLength, Address); + DMAPageWrite(Address, (char *)SCSIDevices[TargetID][LUN].CmdBuffer, (SCSI_BufferLength < DataLength) ? SCSI_BufferLength : DataLength); } - - ESCSICmd->DataLength = Residual; - pclog("BIOS Residual data length for reading: %d\n", - ESCSICmd->DataLength); - - if (SCSIDevices[TargetID][LUN].CmdBuffer != NULL) - { - free(SCSIDevices[TargetID][LUN].CmdBuffer); - SCSIDevices[TargetID][LUN].CmdBuffer = NULL; } } + static void BuslogicSCSIBIOSRequestSetup(Buslogic_t *bl, uint8_t *CmdBuf, uint8_t *DataInBuf, uint8_t DataReply) { @@ -1309,12 +1565,8 @@ BuslogicSCSIBIOSRequestSetup(Buslogic_t *bl, uint8_t *CmdBuf, uint8_t *DataInBuf SCSIStatus = SCSI_STATUS_OK; SCSI_BufferLength = 0; - BuslogicSCSIBIOSDataBufferAllocate(ESCSICmd, ESCSICmd->TargetId, ESCSICmd->LogicalUnit); - if (!scsi_device_present(ESCSICmd->TargetId, ESCSICmd->LogicalUnit)) { pclog("SCSI Target ID %i and LUN %i have no device attached\n",ESCSICmd->TargetId,ESCSICmd->LogicalUnit); - BuslogicSCSIBIOSDataBufferFree(ESCSICmd, ESCSICmd->TargetId, ESCSICmd->LogicalUnit); - /* BuslogicSCSIBIOSSenseBufferFree(ESCSICmd, Id, Lun, 0, 0); */ DataInBuf[2] = CCB_SELECTION_TIMEOUT; DataInBuf[3] = SCSI_STATUS_OK; } else { @@ -1328,6 +1580,8 @@ BuslogicSCSIBIOSRequestSetup(Buslogic_t *bl, uint8_t *CmdBuf, uint8_t *DataInBuf } } + BuslogicDataBufferAllocate(ESCSICmd->TargetId, ESCSICmd->LogicalUnit, ESCSICmd->DataLength); + target_cdb_len = scsi_device_cdb_length(ESCSICmd->TargetId, ESCSICmd->LogicalUnit); if (!scsi_device_valid(ESCSICmd->TargetId, ESCSICmd->LogicalUnit)) fatal("SCSI target on %02i:%02i has disappeared\n", ESCSICmd->TargetId, ESCSICmd->LogicalUnit); @@ -1346,10 +1600,17 @@ BuslogicSCSIBIOSRequestSetup(Buslogic_t *bl, uint8_t *CmdBuf, uint8_t *DataInBuf memcpy(temp_cdb, ESCSICmd->CDB, target_cdb_len); } - scsi_device_command(ESCSICmd->TargetId, ESCSICmd->LogicalUnit, ESCSICmd->CDBLength, temp_cdb); + SCSI_BufferLength = ESCSICmd->DataLength; + scsi_device_command_phase0(ESCSICmd->TargetId, ESCSICmd->LogicalUnit, ESCSICmd->CDBLength, temp_cdb); - BuslogicSCSIBIOSDataBufferFree(ESCSICmd, ESCSICmd->TargetId, ESCSICmd->LogicalUnit); - /* BuslogicSCSIBIOSSenseBufferFree(ESCSICmd, Id, Lun, (SCSIStatus != SCSI_STATUS_OK), 1); */ + if (SCSIPhase == SCSI_PHASE_DATA_OUT) { + BuslogicSCSIBIOSDMATransfer(ESCSICmd, ESCSICmd->TargetId, ESCSICmd->LogicalUnit, 1); + scsi_device_command_phase1(ESCSICmd->TargetId, ESCSICmd->LogicalUnit); + } else if (SCSIPhase == SCSI_PHASE_DATA_IN) { + BuslogicSCSIBIOSDMATransfer(ESCSICmd, ESCSICmd->TargetId, ESCSICmd->LogicalUnit, 0); + } + + BuslogicDataBufferFree(ESCSICmd->TargetId, ESCSICmd->LogicalUnit); pclog("BIOS Request complete\n"); @@ -1360,10 +1621,11 @@ BuslogicSCSIBIOSRequestSetup(Buslogic_t *bl, uint8_t *CmdBuf, uint8_t *DataInBuf DataInBuf[2] = CCB_COMPLETE; DataInBuf[3] = SCSI_STATUS_CHECK_CONDITION; } - - bl->DataReplyLeft = DataReply; + + bl->DataReplyLeft = DataReply; } + static uint8_t BuslogicRead(uint16_t Port, void *p) { @@ -2280,273 +2542,6 @@ BuslogicMemWriteL(uint32_t addr, uint32_t Val, void *p) } -static void -BuslogicSenseBufferFree(Req_t *req, int Copy) -{ - uint8_t SenseLength = BuslogicConvertSenseLength(req->CmdBlock.common.RequestSenseLength); - uint32_t SenseBufferAddress; - uint8_t temp_sense[256]; - - if (SenseLength && Copy) { - scsi_device_request_sense(req->TargetID, req->LUN, temp_sense, SenseLength); - - /* - * 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 (req->Is24bit) { - SenseBufferAddress = req->CCBPointer; - SenseBufferAddress += req->CmdBlock.common.CdbLength + 18; - } else { - SenseBufferAddress = req->CmdBlock.new.SensePointer; - } - - pclog("BuslogicSenseBufferFree(): Request Sense address: %02X\n", SenseBufferAddress); - - pclog("BuslogicSenseBufferFree(): Writing %i bytes at %08X\n", - SenseLength, SenseBufferAddress); - DMAPageWrite(SenseBufferAddress, (char *)temp_sense, SenseLength); - pclog("BuslogicSenseBufferFree(): Sense data written to buffer: %02X %02X %02X\n", - temp_sense[2], temp_sense[12], temp_sense[13]); - } -} - - -static void -BuslogicSCSICommand(Buslogic_t *bl) -{ - Req_t *req = &bl->Req; - uint8_t Id, Lun; - uint8_t temp_cdb[12]; - uint32_t i; - int target_cdb_len = 12; - - Id = req->TargetID; - Lun = req->LUN; - - target_cdb_len = scsi_device_cdb_length(Id, Lun); - - if (!scsi_device_valid(Id, Lun)) fatal("BuslogicSCSICommand(): Target on %02i:%02i has disappeared\n", Id, Lun); - - pclog("BuslogicSCSICommand(): Target command being executed on: SCSI ID %i, SCSI LUN %i\n", Id, Lun); - - for (i = 0; i < req->CmdBlock.common.CdbLength; i++) { - pclog("BuslogicSCSICommand(): SCSI Cdb[%i]=%i\n", i, req->CmdBlock.common.Cdb[i]); - } - - memset(temp_cdb, 0, target_cdb_len); - if (req->CmdBlock.common.CdbLength <= target_cdb_len) { - memcpy(temp_cdb, req->CmdBlock.common.Cdb, - req->CmdBlock.common.CdbLength); - } else { - memcpy(temp_cdb, req->CmdBlock.common.Cdb, target_cdb_len); - } - - scsi_device_command(Id, Lun, req->CmdBlock.common.CdbLength, temp_cdb); - - BuslogicDataBufferFree(req); - - BuslogicSenseBufferFree(req, (SCSIStatus != SCSI_STATUS_OK)); - - pclog("BuslogicSCSICommand(): Request complete\n"); - - if (SCSIStatus == SCSI_STATUS_OK) { - BuslogicMailboxInSetup(bl, req->CCBPointer, &req->CmdBlock, - CCB_COMPLETE, SCSI_STATUS_OK, MBI_SUCCESS); - } else if (SCSIStatus == SCSI_STATUS_CHECK_CONDITION) { - BuslogicMailboxInSetup(bl, req->CCBPointer, &req->CmdBlock, - CCB_COMPLETE, SCSI_STATUS_CHECK_CONDITION, MBI_ERROR); - } - - if (temp_cdb[0] == 0x42) { - thread_wait_event(bl->evt, 10); - } -} - - -static void -BuslogicSCSIRequestSetup(Buslogic_t *bl, uint32_t CCBPointer, Mailbox32_t *Mailbox32) -{ - Req_t *req = &bl->Req; - uint8_t Id, Lun; - - /* Fetch data from the Command Control Block. */ - DMAPageRead(CCBPointer, (char *)&req->CmdBlock, sizeof(CCB32)); - - req->Is24bit = bl->Mbx24bit; - req->CCBPointer = CCBPointer; - req->TargetID = bl->Mbx24bit ? req->CmdBlock.old.Id : req->CmdBlock.new.Id; - req->LUN = bl->Mbx24bit ? req->CmdBlock.old.Lun : req->CmdBlock.new.Lun; - - if (!bl->Mbx24bit) - { - if (req->CmdBlock.new.TagQueued || req->CmdBlock.new.LegacyTagEnable) { - fatal("BuslogicSCSIRequestSetup(): Attempting to queue tags\n"); - BuslogicMailboxInSetup(bl, CCBPointer, &req->CmdBlock, - CCB_INVALID_CCB, SCSI_STATUS_OK, MBI_ERROR); - pclog("BusLogic Callback: Send incoming mailbox\n"); - BuslogicMailboxIn(bl); - return; - } - } - - Id = req->TargetID; - Lun = req->LUN; - if ((Id > 15) || (Lun > 7)) { - BuslogicMailboxInSetup(bl, CCBPointer, &req->CmdBlock, - CCB_INVALID_CCB, SCSI_STATUS_OK, MBI_ERROR); - return; - - pclog("BusLogic Callback: Send incoming mailbox\n"); - BuslogicMailboxIn(bl); - } - - pclog("BuslogicSCSIRequestSetup(): Scanning SCSI Target ID %i\n", Id); - - SCSIStatus = SCSI_STATUS_OK; - SCSI_BufferLength = 0; - - BuslogicDataBufferAllocate(req, req->Is24bit); - - if (!scsi_device_present(Id, Lun)) { - pclog("BuslogicSCSIRequestSetup(): SCSI Target ID %i and LUN %i have no device attached\n",Id,Lun); - BuslogicDataBufferFree(req); - BuslogicSenseBufferFree(req, 0); - BuslogicMailboxInSetup(bl, CCBPointer, &req->CmdBlock, - CCB_SELECTION_TIMEOUT,SCSI_STATUS_OK,MBI_ERROR); - - pclog("BusLogic Callback: Send incoming mailbox\n"); - BuslogicMailboxIn(bl); - } else { - pclog("BuslogicSCSIRequestSetup(): SCSI Target ID %i and LUN %i detected and working\n", Id, Lun); - - pclog("BuslogicSCSIRequestSetup(): Transfer Control %02X\n", req->CmdBlock.common.ControlByte); - pclog("BuslogicSCSIRequestSetup(): CDB Length %i\n", req->CmdBlock.common.CdbLength); - pclog("BuslogicSCSIRequestSetup(): CCB Opcode %x\n", req->CmdBlock.common.Opcode); - if (req->CmdBlock.common.ControlByte > 0x03) { - pclog("BuslogicSCSIRequestSetup(): Invalid control byte: %02X\n", - req->CmdBlock.common.ControlByte); - } - - pclog("BusLogic Callback: Process SCSI request\n"); - BuslogicSCSICommand(bl); - - pclog("BusLogic Callback: Send incoming mailbox\n"); - BuslogicMailboxIn(bl); - } -} - - -static void -BuslogicSCSIRequestAbort(Buslogic_t *bl, uint32_t CCBPointer) -{ - CCBU CmdBlock; - - /* Fetch data from the Command Control Block. */ - DMAPageRead(CCBPointer, (char *)&CmdBlock, sizeof(CCB32)); - - /* Only SCSI CD-ROMs are supported at the moment, SCSI hard disk support will come soon. */ - BuslogicMailboxInSetup(bl, CCBPointer, &CmdBlock, - 0x26, SCSI_STATUS_OK, MBI_NOT_FOUND); - - pclog("BusLogic Callback: Send incoming mailbox\n"); - BuslogicMailboxIn(bl); -} - - -static uint32_t -BuslogicMailboxOut(Buslogic_t *bl, Mailbox32_t *Mailbox32) -{ - Mailbox_t MailboxOut; - uint32_t Outgoing; - - if (bl->Mbx24bit) { - Outgoing = bl->MailboxOutAddr + (bl->MailboxOutPosCur * sizeof(Mailbox_t)); - DMAPageRead(Outgoing, (char *)&MailboxOut, sizeof(Mailbox_t)); - - Mailbox32->CCBPointer = ADDR_TO_U32(MailboxOut.CCBPointer); - Mailbox32->u.out.ActionCode = MailboxOut.CmdStatus; - } else { - Outgoing = bl->MailboxOutAddr + (bl->MailboxOutPosCur * sizeof(Mailbox32_t)); - - DMAPageRead(Outgoing, (char *)Mailbox32, sizeof(Mailbox32_t)); - } - - return Outgoing; -} - - -static void -BuslogicMailboxOutAdvance(Buslogic_t *bl) -{ - bl->MailboxOutPosCur = (bl->MailboxOutPosCur + 1) % bl->MailboxCount; -} - - -static uint8_t -BuslogicProcessMailbox(Buslogic_t *bl) -{ - Mailbox32_t mb32; - uint32_t Outgoing; - uint8_t CmdStatus = MBO_FREE; - uint32_t CodeOffset = 0; - - CodeOffset = bl->Mbx24bit ? 0 : 7; - -#if 0 - pclog("BuslogicProcessMailbox(): Operating in %s mode\n", bl->LocalRAM.structured.autoSCSIData.fAggressiveRoundRobinMode ? "aggressive" : "strict"); -#endif - - /* 0 = strict, 1 = aggressive */ - if (bl->LocalRAM.structured.autoSCSIData.fAggressiveRoundRobinMode) { - uint8_t MailboxCur = bl->MailboxOutPosCur; - - /* Search for a filled mailbox - stop if we have scanned all mailboxes. */ - do { - /* Fetch mailbox from guest memory. */ - Outgoing = BuslogicMailboxOut(bl, &mb32); - - /* Check the next mailbox. */ - BuslogicMailboxOutAdvance(bl); - } while ((mb32.u.out.ActionCode == MBO_FREE) && (MailboxCur != bl->MailboxOutPosCur)); - } else { - Outgoing = BuslogicMailboxOut(bl, &mb32); - } - -#if 0 - pclog("BuslogicProcessMailbox(): Outgoing mailbox action code: %i\n", mb32.u.out.ActionCode); -#endif - - if (mb32.u.out.ActionCode == MBO_START) { - pclog("Start Mailbox Command\n"); - BuslogicSCSIRequestSetup(bl, mb32.CCBPointer, &mb32); - } else if (mb32.u.out.ActionCode == MBO_ABORT) { - pclog("Abort Mailbox Command\n"); - BuslogicSCSIRequestAbort(bl, mb32.CCBPointer); - } else { - pclog("Invalid action code: %02X\n", mb32.u.out.ActionCode); - } - - if ((mb32.u.out.ActionCode == MBO_START) || (mb32.u.out.ActionCode == MBO_ABORT)) { - /* We got the mailbox, mark it as free in the guest. */ - pclog("BuslogicProcessMailbox(): Writing %i bytes at %08X\n", sizeof(CmdStatus), Outgoing + CodeOffset); - DMAPageWrite(Outgoing + CodeOffset, (char *)&CmdStatus, sizeof(CmdStatus)); - - BuslogicRaiseInterrupt(bl, 0, bl->ToRaise); - - while (bl->Interrupt) { - } - } - - /* Advance to the next mailbox. */ - if (! bl->LocalRAM.structured.autoSCSIData.fAggressiveRoundRobinMode) - BuslogicMailboxOutAdvance(bl); - - return 1; -} - - static void BuslogicResetPoll(void *p) { diff --git a/src/scsi/scsi_device.c b/src/scsi/scsi_device.c index c59cd70d6..036045d6f 100644 --- a/src/scsi/scsi_device.c +++ b/src/scsi/scsi_device.c @@ -8,7 +8,7 @@ * * The generic SCSI device command handler. * - * Version: @(#)scsi_device.c 1.0.6 2017/10/07 + * Version: @(#)scsi_device.c 1.0.7 2017/10/10 * * Authors: Miran Grca, * Fred N. van Kempen, @@ -278,7 +278,7 @@ int scsi_device_block_shift(uint8_t scsi_id, uint8_t scsi_lun) } -void scsi_device_command_common(uint8_t scsi_id, uint8_t scsi_lun, int cdb_len, uint8_t *cdb, int multi_phase) +void scsi_device_command_phase0(uint8_t scsi_id, uint8_t scsi_lun, int cdb_len, uint8_t *cdb) { uint8_t phase = 0; uint8_t lun_type = SCSIDevices[scsi_id][scsi_lun].LunType; @@ -322,7 +322,7 @@ void scsi_device_command_common(uint8_t scsi_id, uint8_t scsi_lun, int cdb_len, scsi_device_target_phase_callback(lun_type, id); } else { /* Command first phase complete - call the callback to execute the second phase. */ - if (multi_phase || (SCSIPhase != SCSI_PHASE_DATA_OUT)) + if (SCSIPhase != SCSI_PHASE_DATA_OUT) { scsi_device_target_phase_callback(lun_type, id); SCSIStatus = scsi_device_target_err_stat_to_scsi(lun_type, id); @@ -336,16 +336,6 @@ void scsi_device_command_common(uint8_t scsi_id, uint8_t scsi_lun, int cdb_len, } } -void scsi_device_command(uint8_t scsi_id, uint8_t scsi_lun, int cdb_len, uint8_t *cdb) -{ - scsi_device_command_common(scsi_id, scsi_lun, cdb_len, cdb, 1); -} - -void scsi_device_command_phase0(uint8_t scsi_id, uint8_t scsi_lun, int cdb_len, uint8_t *cdb) -{ - scsi_device_command_common(scsi_id, scsi_lun, cdb_len, cdb, 0); -} - void scsi_device_command_phase1(uint8_t scsi_id, uint8_t scsi_lun) { uint8_t lun_type = SCSIDevices[scsi_id][scsi_lun].LunType; diff --git a/src/scsi/scsi_device.h b/src/scsi/scsi_device.h index e9c272251..561a5f339 100644 --- a/src/scsi/scsi_device.h +++ b/src/scsi/scsi_device.h @@ -8,7 +8,7 @@ * * Definitions for the generic SCSI device command handler. * - * Version: @(#)scsi_device.h 1.0.3 2017/10/04 + * Version: @(#)scsi_device.h 1.0.4 2017/10/10 * * Authors: Miran Grca, * Fred N. van Kempen, diff --git a/src/scsi/scsi_disk.c b/src/scsi/scsi_disk.c index 75a9d1e99..7cd0fd599 100644 --- a/src/scsi/scsi_disk.c +++ b/src/scsi/scsi_disk.c @@ -6,7 +6,7 @@ * * Emulation of SCSI fixed and removable disks. * - * Version: @(#)scsi_disk.c 1.0.12 2017/10/09 + * Version: @(#)scsi_disk.c 1.0.13 2017/10/10 * * Author: Miran Grca, * Copyright 2017 Miran Grca. @@ -1469,7 +1469,7 @@ void scsi_hd_command(uint8_t id, uint8_t *cdb) case GPCMD_REQUEST_SENSE: /* If there's a unit attention condition and there's a buffered not ready, a standalone REQUEST SENSE should forget about the not ready, and report unit attention straight away. */ - if (SCSI_BufferLength == -1) + if ((SCSI_BufferLength == -1) || (cdb[4] < SCSI_BufferLength)) { SCSI_BufferLength = cdb[4]; } @@ -1487,7 +1487,7 @@ void scsi_hd_command(uint8_t id, uint8_t *cdb) case GPCMD_MECHANISM_STATUS: len = (cdb[7] << 16) | (cdb[8] << 8) | cdb[9]; - if (SCSI_BufferLength == -1) + if ((SCSI_BufferLength == -1) || (len < SCSI_BufferLength)) { SCSI_BufferLength = len; } @@ -1538,7 +1538,7 @@ void scsi_hd_command(uint8_t id, uint8_t *cdb) alloc_length = shdc[id].packet_len = max_len << 9; - if (SCSI_BufferLength == -1) + if ((SCSI_BufferLength == -1) || (alloc_length < SCSI_BufferLength)) { SCSI_BufferLength = alloc_length; } @@ -1640,7 +1640,7 @@ void scsi_hd_command(uint8_t id, uint8_t *cdb) alloc_length = len; } - if (SCSI_BufferLength == -1) + if ((SCSI_BufferLength == -1) || (alloc_length < SCSI_BufferLength)) { SCSI_BufferLength = alloc_length; } @@ -1663,7 +1663,7 @@ void scsi_hd_command(uint8_t id, uint8_t *cdb) len = (cdb[7] << 8) | cdb[8]; } - if (SCSI_BufferLength == -1) + if ((SCSI_BufferLength == -1) || (len < SCSI_BufferLength)) { SCSI_BufferLength = len; } @@ -1720,7 +1720,7 @@ void scsi_hd_command(uint8_t id, uint8_t *cdb) alloc_length = shdc[id].packet_len = max_len << 9; - if (SCSI_BufferLength == -1) + if ((SCSI_BufferLength == -1) || (alloc_length < SCSI_BufferLength)) { SCSI_BufferLength = alloc_length; } @@ -1865,7 +1865,7 @@ atapi_out: len = max_len; } - if (SCSI_BufferLength == -1) + if ((SCSI_BufferLength == -1) || (len < SCSI_BufferLength)) { SCSI_BufferLength = len; } @@ -1911,7 +1911,7 @@ atapi_out: return; } - if (SCSI_BufferLength == -1) + if ((SCSI_BufferLength == -1) || (len < SCSI_BufferLength)) { SCSI_BufferLength = len; } diff --git a/src/win/win_settings.c b/src/win/win_settings.c index bd56c89a3..e421d9bbd 100644 --- a/src/win/win_settings.c +++ b/src/win/win_settings.c @@ -1044,7 +1044,7 @@ static BOOL CALLBACK win_settings_sound_proc(HWND hdlg, UINT message, WPARAM wPa int c = 0; int d = 0; LPTSTR lptsTemp; - device_t *sound_dev, *midi_dev; + device_t *sound_dev/*, *midi_dev*/; char *s; switch (message) @@ -1116,22 +1116,19 @@ static BOOL CALLBACK win_settings_sound_proc(HWND hdlg, UINT message, WPARAM wPa if (midi_device_available(c)) { - midi_dev = midi_device_getdevice(c); + /* midi_dev = midi_device_getdevice(c); */ - if (midi_dev) + if (c == 0) { - if (c == 0) - { - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)plat_get_string(IDS_2152)); - } - else - { - mbstowcs(lptsTemp, s, strlen(s) + 1); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); - } - settings_list_to_midi[d] = c; - d++; + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)plat_get_string(IDS_2152)); } + else + { + mbstowcs(lptsTemp, s, strlen(s) + 1); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); + } + settings_list_to_midi[d] = c; + d++; } c++;