Lowercase all CAPS to prevent case sensitive errors in non-Windows platforms
This commit is contained in:
187
src/scsi/scsi.c
Normal file
187
src/scsi/scsi.c
Normal file
@@ -0,0 +1,187 @@
|
||||
/*
|
||||
* 86Box A hypervisor and IBM PC system emulator that specializes in
|
||||
* running old operating systems and software designed for IBM
|
||||
* PC systems and compatibles from 1981 through fairly recent
|
||||
* system designs based on the PCI bus.
|
||||
*
|
||||
* This file is part of the 86Box distribution.
|
||||
*
|
||||
* Handling of the SCSI controllers.
|
||||
*
|
||||
* Version: @(#)scsi.c 1.0.2 2017/08/23
|
||||
*
|
||||
* Authors: TheCollector1995, <mariogplayer@gmail.com>
|
||||
* Miran Grca, <mgrca8@gmail.com>
|
||||
* Fred N. van Kempen, <decwiz@yahoo.com>
|
||||
* Copyright 2008-2017 TheCollector1995.
|
||||
* Copyright 2016,2017 Miran Grca.
|
||||
* Copyright 2017 Fred N. van Kempen.
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "../86box.h"
|
||||
#include "../ibm.h"
|
||||
#include "../timer.h"
|
||||
#include "../device.h"
|
||||
#include "../cdrom.h"
|
||||
#include "scsi.h"
|
||||
#include "scsi_aha154x.h"
|
||||
#include "scsi_buslogic.h"
|
||||
|
||||
|
||||
uint8_t SCSIPhase = SCSI_PHASE_BUS_FREE;
|
||||
uint8_t SCSIStatus = SCSI_STATUS_OK;
|
||||
uint8_t scsi_cdrom_id = 3; /*common setting*/
|
||||
char scsi_fn[SCSI_NUM][512];
|
||||
uint16_t scsi_hd_location[SCSI_NUM];
|
||||
|
||||
int scsi_card_current = 0;
|
||||
int scsi_card_last = 0;
|
||||
|
||||
|
||||
typedef struct {
|
||||
char name[64];
|
||||
char internal_name[32];
|
||||
device_t *device;
|
||||
void (*reset)(void *p);
|
||||
} SCSI_CARD;
|
||||
|
||||
|
||||
static SCSI_CARD scsi_cards[] = {
|
||||
{ "None", "none", NULL, NULL },
|
||||
{ "Adaptec AHA-1540B", "aha1540b", &aha1540b_device, aha_device_reset },
|
||||
{ "Adaptec AHA-1542CF", "aha1542cf", &aha1542cf_device, aha_device_reset },
|
||||
{ "Adaptec AHA-1640", "aha1640", &aha1640_device, aha_device_reset },
|
||||
{ "BusLogic BT-545C", "bt545c", &buslogic_device, BuslogicDeviceReset },
|
||||
{ "BusLogic BT-958D PCI", "bt958d", &buslogic_pci_device, BuslogicDeviceReset },
|
||||
{ "", "", NULL, NULL },
|
||||
};
|
||||
|
||||
|
||||
int scsi_card_available(int card)
|
||||
{
|
||||
if (scsi_cards[card].device)
|
||||
return(device_available(scsi_cards[card].device));
|
||||
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
char *scsi_card_getname(int card)
|
||||
{
|
||||
return(scsi_cards[card].name);
|
||||
}
|
||||
|
||||
|
||||
device_t *scsi_card_getdevice(int card)
|
||||
{
|
||||
return(scsi_cards[card].device);
|
||||
}
|
||||
|
||||
|
||||
int scsi_card_has_config(int card)
|
||||
{
|
||||
if (! scsi_cards[card].device) return(0);
|
||||
|
||||
return(scsi_cards[card].device->config ? 1 : 0);
|
||||
}
|
||||
|
||||
|
||||
char *scsi_card_get_internal_name(int card)
|
||||
{
|
||||
return(scsi_cards[card].internal_name);
|
||||
}
|
||||
|
||||
|
||||
int scsi_card_get_from_internal_name(char *s)
|
||||
{
|
||||
int c = 0;
|
||||
|
||||
while (strlen(scsi_cards[c].internal_name)) {
|
||||
if (!strcmp(scsi_cards[c].internal_name, s))
|
||||
return(c);
|
||||
c++;
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
void scsi_card_init(void)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
pclog("Building SCSI hard disk map...\n");
|
||||
build_scsi_hd_map();
|
||||
pclog("Building SCSI CD-ROM map...\n");
|
||||
build_scsi_cdrom_map();
|
||||
|
||||
for (i=0; i<16; i++)
|
||||
{
|
||||
for (j=0; j<8; j++)
|
||||
{
|
||||
if (scsi_hard_disks[i][j] != 0xff) {
|
||||
SCSIDevices[i][j].LunType = SCSI_DISK;
|
||||
}
|
||||
else if (scsi_cdrom_drives[i][j] != 0xff) {
|
||||
SCSIDevices[i][j].LunType = SCSI_CDROM;
|
||||
}
|
||||
else
|
||||
{
|
||||
SCSIDevices[i][j].LunType = SCSI_NONE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (scsi_cards[scsi_card_current].device)
|
||||
device_add(scsi_cards[scsi_card_current].device);
|
||||
|
||||
scsi_card_last = scsi_card_current;
|
||||
}
|
||||
|
||||
|
||||
void scsi_card_reset(void)
|
||||
{
|
||||
void *p = NULL;
|
||||
|
||||
if (scsi_cards[scsi_card_current].device)
|
||||
{
|
||||
p = device_get_priv(scsi_cards[scsi_card_current].device);
|
||||
if (p)
|
||||
{
|
||||
if (scsi_cards[scsi_card_current].reset)
|
||||
{
|
||||
scsi_cards[scsi_card_current].reset(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Initialization function for the SCSI layer */
|
||||
void SCSIReset(uint8_t id, uint8_t lun)
|
||||
{
|
||||
uint8_t cdrom_id = scsi_cdrom_drives[id][lun];
|
||||
uint8_t hdc_id = scsi_hard_disks[id][lun];
|
||||
|
||||
if (hdc_id != 0xff) {
|
||||
scsi_hd_reset(cdrom_id);
|
||||
SCSIDevices[id][lun].LunType = SCSI_DISK;
|
||||
} else {
|
||||
if (cdrom_id != 0xff)
|
||||
{
|
||||
cdrom_reset(cdrom_id);
|
||||
SCSIDevices[id][lun].LunType = SCSI_CDROM;
|
||||
}
|
||||
else
|
||||
{
|
||||
SCSIDevices[id][lun].LunType = SCSI_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
if(SCSIDevices[id][lun].CmdBuffer != NULL)
|
||||
{
|
||||
free(SCSIDevices[id][lun].CmdBuffer);
|
||||
SCSIDevices[id][lun].CmdBuffer = NULL;
|
||||
}
|
||||
}
|
||||
332
src/scsi/scsi.h
Normal file
332
src/scsi/scsi.h
Normal file
@@ -0,0 +1,332 @@
|
||||
/*
|
||||
* 86Box A hypervisor and IBM PC system emulator that specializes in
|
||||
* running old operating systems and software designed for IBM
|
||||
* PC systems and compatibles from 1981 through fairly recent
|
||||
* system designs based on the PCI bus.
|
||||
*
|
||||
* This file is part of the 86Box distribution.
|
||||
*
|
||||
* SCSI controller handler header.
|
||||
*
|
||||
* Version: @(#)scsi_h 1.0.4 2017/08/26
|
||||
*
|
||||
* Authors: TheCollector1995, <mariogplayer@gmail.com>
|
||||
* Miran Grca, <mgrca8@gmail.com>
|
||||
* Fred N. van Kempen, <decwiz@yahoo.com>
|
||||
* Copyright 2016,2017 TheCollector1995.
|
||||
* Copyright 2016,2017 Miran Grca.
|
||||
* Copyright 2017 Fred N. van Kempen.
|
||||
*/
|
||||
#ifndef EMU_SCSI_H
|
||||
#define EMU_SCSI_H
|
||||
|
||||
|
||||
#ifdef WALTJE
|
||||
#define SCSI_TIME (50 * (1 << TIMER_SHIFT))
|
||||
#else
|
||||
#define SCSI_TIME (5 * 100 * (1 << TIMER_SHIFT))
|
||||
#endif
|
||||
|
||||
|
||||
/* SCSI commands. */
|
||||
#define GPCMD_TEST_UNIT_READY 0x00
|
||||
#define GPCMD_REZERO_UNIT 0x01
|
||||
#define GPCMD_REQUEST_SENSE 0x03
|
||||
#define GPCMD_FORMAT_UNIT 0x04
|
||||
#define GPCMD_READ_6 0x08
|
||||
#define GPCMD_WRITE_6 0x0a
|
||||
#define GPCMD_SEEK_6 0x0b
|
||||
#define GPCMD_INQUIRY 0x12
|
||||
#define GPCMD_VERIFY_6 0x13
|
||||
#define GPCMD_MODE_SELECT_6 0x15
|
||||
#define GPCMD_MODE_SENSE_6 0x1a
|
||||
#define GPCMD_START_STOP_UNIT 0x1b
|
||||
#define GPCMD_PREVENT_REMOVAL 0x1e
|
||||
#define GPCMD_READ_CDROM_CAPACITY 0x25
|
||||
#define GPCMD_READ_10 0x28
|
||||
#define GPCMD_WRITE_10 0x2a
|
||||
#define GPCMD_SEEK_10 0x2b
|
||||
#define GPCMD_VERIFY_10 0x2f
|
||||
#define GPCMD_READ_SUBCHANNEL 0x42
|
||||
#define GPCMD_READ_TOC_PMA_ATIP 0x43
|
||||
#define GPCMD_READ_HEADER 0x44
|
||||
#define GPCMD_PLAY_AUDIO_10 0x45
|
||||
#define GPCMD_GET_CONFIGURATION 0x46
|
||||
#define GPCMD_PLAY_AUDIO_MSF 0x47
|
||||
#define GPCMD_PLAY_AUDIO_TRACK_INDEX 0x48
|
||||
#define GPCMD_GET_EVENT_STATUS_NOTIFICATION 0x4a
|
||||
#define GPCMD_PAUSE_RESUME 0x4b
|
||||
#define GPCMD_STOP_PLAY_SCAN 0x4e
|
||||
#define GPCMD_READ_DISC_INFORMATION 0x51
|
||||
#define GPCMD_READ_TRACK_INFORMATION 0x52
|
||||
#define GPCMD_MODE_SELECT_10 0x55
|
||||
#define GPCMD_MODE_SENSE_10 0x5a
|
||||
#define GPCMD_PLAY_AUDIO_12 0xa5
|
||||
#define GPCMD_READ_12 0xa8
|
||||
#define GPCMD_WRITE_12 0xaa
|
||||
#define GPCMD_READ_DVD_STRUCTURE 0xad /* For reading. */
|
||||
#define GPCMD_VERIFY_12 0xaf
|
||||
#define GPCMD_PLAY_CD_OLD 0xb4
|
||||
#define GPCMD_READ_CD_OLD 0xb8
|
||||
#define GPCMD_READ_CD_MSF 0xb9
|
||||
#define GPCMD_SCAN 0xba
|
||||
#define GPCMD_SET_SPEED 0xbb
|
||||
#define GPCMD_PLAY_CD 0xbc
|
||||
#define GPCMD_MECHANISM_STATUS 0xbd
|
||||
#define GPCMD_READ_CD 0xbe
|
||||
#define GPCMD_SEND_DVD_STRUCTURE 0xbf /* This is for writing only, irrelevant to PCem. */
|
||||
#define GPCMD_PAUSE_RESUME_ALT 0xc2
|
||||
#define GPCMD_SCAN_ALT 0xcd /* Should be equivalent to 0xba */
|
||||
#define GPCMD_SET_SPEED_ALT 0xda /* Should be equivalent to 0xbb */
|
||||
|
||||
/* Mode page codes for mode sense/set */
|
||||
#define GPMODE_R_W_ERROR_PAGE 0x01
|
||||
#define GPMODE_CDROM_PAGE 0x0d
|
||||
#define GPMODE_CDROM_AUDIO_PAGE 0x0e
|
||||
#define GPMODE_CAPABILITIES_PAGE 0x2a
|
||||
#define GPMODE_ALL_PAGES 0x3f
|
||||
|
||||
/* SCSI Status Codes */
|
||||
#define SCSI_STATUS_OK 0
|
||||
#define SCSI_STATUS_CHECK_CONDITION 2
|
||||
|
||||
/* SCSI Sense Keys */
|
||||
#define SENSE_NONE 0
|
||||
#define SENSE_NOT_READY 2
|
||||
#define SENSE_ILLEGAL_REQUEST 5
|
||||
#define SENSE_UNIT_ATTENTION 6
|
||||
|
||||
/* SCSI Additional Sense Codes */
|
||||
#define ASC_AUDIO_PLAY_OPERATION 0x00
|
||||
#define ASC_NOT_READY 0x04
|
||||
#define ASC_ILLEGAL_OPCODE 0x20
|
||||
#define ASC_LBA_OUT_OF_RANGE 0x21
|
||||
#define ASC_INV_FIELD_IN_CMD_PACKET 0x24
|
||||
#define ASC_INV_LUN 0x25
|
||||
#define ASC_INV_FIELD_IN_PARAMETER_LIST 0x26
|
||||
#define ASC_WRITE_PROTECTED 0x27
|
||||
#define ASC_MEDIUM_MAY_HAVE_CHANGED 0x28
|
||||
#define ASC_CAPACITY_DATA_CHANGED 0x2A
|
||||
#define ASC_INCOMPATIBLE_FORMAT 0x30
|
||||
#define ASC_MEDIUM_NOT_PRESENT 0x3a
|
||||
#define ASC_DATA_PHASE_ERROR 0x4b
|
||||
#define ASC_ILLEGAL_MODE_FOR_THIS_TRACK 0x64
|
||||
|
||||
#define ASCQ_UNIT_IN_PROCESS_OF_BECOMING_READY 0x01
|
||||
#define ASCQ_INITIALIZING_COMMAND_REQUIRED 0x02
|
||||
#define ASCQ_CAPACITY_DATA_CHANGED 0x09
|
||||
#define ASCQ_AUDIO_PLAY_OPERATION_IN_PROGRESS 0x11
|
||||
#define ASCQ_AUDIO_PLAY_OPERATION_PAUSED 0x12
|
||||
#define ASCQ_AUDIO_PLAY_OPERATION_COMPLETED 0x13
|
||||
|
||||
/* Tell RISC OS that we have a 4x CD-ROM drive (600kb/sec data, 706kb/sec raw).
|
||||
Not that it means anything */
|
||||
#define CDROM_SPEED 706 /* 0x2C2 */
|
||||
|
||||
/* Some generally useful CD-ROM information */
|
||||
#define CD_MINS 75 /* max. minutes per CD */
|
||||
#define CD_SECS 60 /* seconds per minute */
|
||||
#define CD_FRAMES 75 /* frames per second */
|
||||
#define CD_FRAMESIZE 2048 /* bytes per frame, "cooked" mode */
|
||||
#define CD_MAX_BYTES (CD_MINS * CD_SECS * CD_FRAMES * CD_FRAMESIZE)
|
||||
#define CD_MAX_SECTORS (CD_MAX_BYTES / 512)
|
||||
|
||||
/* Event notification classes for GET EVENT STATUS NOTIFICATION */
|
||||
#define GESN_NO_EVENTS 0
|
||||
#define GESN_OPERATIONAL_CHANGE 1
|
||||
#define GESN_POWER_MANAGEMENT 2
|
||||
#define GESN_EXTERNAL_REQUEST 3
|
||||
#define GESN_MEDIA 4
|
||||
#define GESN_MULTIPLE_HOSTS 5
|
||||
#define GESN_DEVICE_BUSY 6
|
||||
|
||||
/* Event codes for MEDIA event status notification */
|
||||
#define MEC_NO_CHANGE 0
|
||||
#define MEC_EJECT_REQUESTED 1
|
||||
#define MEC_NEW_MEDIA 2
|
||||
#define MEC_MEDIA_REMOVAL 3 /* only for media changers */
|
||||
#define MEC_MEDIA_CHANGED 4 /* only for media changers */
|
||||
#define MEC_BG_FORMAT_COMPLETED 5 /* MRW or DVD+RW b/g format completed */
|
||||
#define MEC_BG_FORMAT_RESTARTED 6 /* MRW or DVD+RW b/g format restarted */
|
||||
#define MS_TRAY_OPEN 1
|
||||
#define MS_MEDIA_PRESENT 2
|
||||
|
||||
/*
|
||||
* The MMC values are not IDE specific and might need to be moved
|
||||
* to a common header if they are also needed for the SCSI emulation
|
||||
*/
|
||||
|
||||
/* Profile list from MMC-6 revision 1 table 91 */
|
||||
#define MMC_PROFILE_NONE 0x0000
|
||||
#define MMC_PROFILE_CD_ROM 0x0008
|
||||
#define MMC_PROFILE_CD_R 0x0009
|
||||
#define MMC_PROFILE_CD_RW 0x000A
|
||||
#define MMC_PROFILE_DVD_ROM 0x0010
|
||||
#define MMC_PROFILE_DVD_R_SR 0x0011
|
||||
#define MMC_PROFILE_DVD_RAM 0x0012
|
||||
#define MMC_PROFILE_DVD_RW_RO 0x0013
|
||||
#define MMC_PROFILE_DVD_RW_SR 0x0014
|
||||
#define MMC_PROFILE_DVD_R_DL_SR 0x0015
|
||||
#define MMC_PROFILE_DVD_R_DL_JR 0x0016
|
||||
#define MMC_PROFILE_DVD_RW_DL 0x0017
|
||||
#define MMC_PROFILE_DVD_DDR 0x0018
|
||||
#define MMC_PROFILE_DVD_PLUS_RW 0x001A
|
||||
#define MMC_PROFILE_DVD_PLUS_R 0x001B
|
||||
#define MMC_PROFILE_DVD_PLUS_RW_DL 0x002A
|
||||
#define MMC_PROFILE_DVD_PLUS_R_DL 0x002B
|
||||
#define MMC_PROFILE_BD_ROM 0x0040
|
||||
#define MMC_PROFILE_BD_R_SRM 0x0041
|
||||
#define MMC_PROFILE_BD_R_RRM 0x0042
|
||||
#define MMC_PROFILE_BD_RE 0x0043
|
||||
#define MMC_PROFILE_HDDVD_ROM 0x0050
|
||||
#define MMC_PROFILE_HDDVD_R 0x0051
|
||||
#define MMC_PROFILE_HDDVD_RAM 0x0052
|
||||
#define MMC_PROFILE_HDDVD_RW 0x0053
|
||||
#define MMC_PROFILE_HDDVD_R_DL 0x0058
|
||||
#define MMC_PROFILE_HDDVD_RW_DL 0x005A
|
||||
#define MMC_PROFILE_INVALID 0xFFFF
|
||||
|
||||
#define SCSI_ONLY 32
|
||||
#define ATAPI_ONLY 16
|
||||
#define IMPLEMENTED 8
|
||||
#define NONDATA 4
|
||||
#define CHECK_READY 2
|
||||
#define ALLOW_UA 1
|
||||
|
||||
extern uint8_t SCSICommandTable[0x100];
|
||||
|
||||
extern uint8_t mode_sense_pages[0x40];
|
||||
|
||||
extern int readcdmode;
|
||||
|
||||
/* Mode sense/select stuff. */
|
||||
extern uint8_t mode_pages_in[256][256];
|
||||
#define PAGE_CHANGEABLE 1
|
||||
#define PAGE_CHANGED 2
|
||||
|
||||
extern uint8_t page_flags[256];
|
||||
extern uint8_t prefix_len;
|
||||
extern uint8_t page_current;
|
||||
|
||||
extern uint32_t DataLength;
|
||||
extern uint32_t DataPointer;
|
||||
|
||||
extern int SectorLBA;
|
||||
extern int SectorLen;
|
||||
|
||||
extern int MediaPresent;
|
||||
|
||||
extern uint8_t SCSIStatus;
|
||||
extern uint8_t SCSIPhase;
|
||||
extern uint8_t scsi_cdrom_id;
|
||||
|
||||
struct
|
||||
{
|
||||
uint8_t SenseBuffer[18];
|
||||
uint8_t SenseLength;
|
||||
uint8_t UnitAttention;
|
||||
uint8_t SenseKey;
|
||||
uint8_t Asc;
|
||||
uint8_t Ascq;
|
||||
} SCSISense;
|
||||
|
||||
extern int cd_status;
|
||||
extern int prev_status;
|
||||
|
||||
#define SCSI_NONE 0
|
||||
#define SCSI_DISK 1
|
||||
#define SCSI_CDROM 2
|
||||
|
||||
#define MSFtoLBA(m,s,f) ((((m*60)+s)*75)+f)
|
||||
|
||||
#define SCSI_PHASE_DATAOUT ( 0 )
|
||||
#define SCSI_PHASE_DATAIN ( 1 )
|
||||
#define SCSI_PHASE_COMMAND ( 2 )
|
||||
#define SCSI_PHASE_STATUS ( 3 )
|
||||
#define SCSI_PHASE_MESSAGE_OUT ( 6 )
|
||||
#define SCSI_PHASE_MESSAGE_IN ( 7 )
|
||||
#define SCSI_PHASE_BUS_FREE ( 8 )
|
||||
#define SCSI_PHASE_SELECT ( 9 )
|
||||
|
||||
struct
|
||||
{
|
||||
uint8_t *CmdBuffer;
|
||||
uint32_t CmdBufferLength;
|
||||
int LunType;
|
||||
uint32_t InitLength;
|
||||
} SCSIDevices[16][8];
|
||||
|
||||
extern void SCSIReset(uint8_t id, uint8_t lun);
|
||||
|
||||
extern uint32_t SCSICDROMModeSense(uint8_t *buf, uint32_t pos, uint8_t type);
|
||||
extern uint8_t SCSICDROMSetProfile(uint8_t *buf, uint8_t *index, uint16_t profile);
|
||||
extern int SCSICDROMReadDVDStructure(int format, const uint8_t *packet, uint8_t *buf);
|
||||
extern uint32_t SCSICDROMEventStatus(uint8_t *buffer);
|
||||
extern void SCSICDROM_Insert(void);
|
||||
|
||||
extern int cdrom_add_error_and_subchannel(uint8_t *b, int real_sector_type);
|
||||
extern int cdrom_LBAtoMSF_accurate(void);
|
||||
|
||||
extern int mode_select_init(uint8_t command, uint16_t pl_length, uint8_t do_save);
|
||||
extern int mode_select_terminate(int force);
|
||||
extern int mode_select_write(uint8_t val);
|
||||
|
||||
extern int scsi_card_current;
|
||||
|
||||
extern int scsi_card_available(int card);
|
||||
extern char *scsi_card_getname(int card);
|
||||
extern struct device_t *scsi_card_getdevice(int card);
|
||||
extern int scsi_card_has_config(int card);
|
||||
extern char *scsi_card_get_internal_name(int card);
|
||||
extern int scsi_card_get_from_internal_name(char *s);
|
||||
extern void scsi_card_init();
|
||||
extern void scsi_card_reset(void);
|
||||
|
||||
extern uint8_t scsi_hard_disks[16][8];
|
||||
|
||||
extern int scsi_hd_err_stat_to_scsi(uint8_t id);
|
||||
extern int scsi_hd_phase_to_scsi(uint8_t id);
|
||||
extern int find_hdc_for_scsi_id(uint8_t scsi_id, uint8_t scsi_lun);
|
||||
extern void build_scsi_hd_map(void);
|
||||
extern void scsi_hd_reset(uint8_t id);
|
||||
extern void scsi_hd_request_sense_for_scsi(uint8_t id, uint8_t *buffer, uint8_t alloc_length);
|
||||
extern void scsi_hd_command(uint8_t id, uint8_t *cdb);
|
||||
extern void scsi_hd_callback(uint8_t id);
|
||||
|
||||
|
||||
#pragma pack(push,1)
|
||||
typedef struct {
|
||||
uint8_t hi;
|
||||
uint8_t mid;
|
||||
uint8_t lo;
|
||||
} addr24;
|
||||
#pragma pack(pop)
|
||||
|
||||
#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)
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* Scatter/Gather Segment List Definitions
|
||||
*
|
||||
* Adapter limits
|
||||
*/
|
||||
#define MAX_SG_DESCRIPTORS 32 /* Always make the array 32 elements long, if less are used, that's not an issue. */
|
||||
|
||||
#pragma pack(push,1)
|
||||
typedef struct {
|
||||
uint32_t Segment;
|
||||
uint32_t SegmentPointer;
|
||||
} SGE32;
|
||||
#pragma pack(pop)
|
||||
|
||||
#pragma pack(push,1)
|
||||
typedef struct {
|
||||
addr24 Segment;
|
||||
addr24 SegmentPointer;
|
||||
} SGE;
|
||||
#pragma pack(pop)
|
||||
|
||||
|
||||
#endif /*EMU_SCSI_H*/
|
||||
2262
src/scsi/scsi_aha154x.c
Normal file
2262
src/scsi/scsi_aha154x.c
Normal file
File diff suppressed because it is too large
Load Diff
12
src/scsi/scsi_aha154x.h
Normal file
12
src/scsi/scsi_aha154x.h
Normal file
@@ -0,0 +1,12 @@
|
||||
#ifndef SCSI_AHA154X_H
|
||||
# define SCSI_AHA154X_H
|
||||
|
||||
|
||||
extern device_t aha1540b_device;
|
||||
extern device_t aha1542cf_device;
|
||||
extern device_t aha1640_device;
|
||||
|
||||
extern void aha_device_reset(void *p);
|
||||
|
||||
|
||||
#endif /*SCSI_AHA154X_H*/
|
||||
446
src/scsi/scsi_bios_command.c
Normal file
446
src/scsi/scsi_bios_command.c
Normal file
@@ -0,0 +1,446 @@
|
||||
/*
|
||||
* 86Box A hypervisor and IBM PC system emulator that specializes in
|
||||
* running old operating systems and software designed for IBM
|
||||
* PC systems and compatibles from 1981 through fairly recent
|
||||
* system designs based on the PCI bus.
|
||||
*
|
||||
* This file is part of the 86Box distribution.
|
||||
*
|
||||
* The shared AHA and Buslogic SCSI BIOS command handler.
|
||||
*
|
||||
* Version: @(#)scsi_bios_command.c 1.0.0 2017/08/26
|
||||
*
|
||||
* Authors: TheCollector1995, <mariogplayer@gmail.com>
|
||||
* Miran Grca, <mgrca8@gmail.com>
|
||||
* Fred N. van Kempen, <decwiz@yahoo.com>
|
||||
* Copyright 2016,2017 Miran Grca.
|
||||
* Copyright 2017 Fred N. van Kempen.
|
||||
*/
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "../ibm.h"
|
||||
#include "../dma.h"
|
||||
#include "scsi.h"
|
||||
#include "scsi_bios_command.h"
|
||||
#include "scsi_device.h"
|
||||
|
||||
static void
|
||||
scsi_bios_command_log(const char *format, ...)
|
||||
{
|
||||
#ifdef ENABLE_SCSI_BIOS_COMMAND_LOG
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, format);
|
||||
vprintf(format, ap);
|
||||
va_end(ap);
|
||||
fflush(stdout);
|
||||
#endif
|
||||
}
|
||||
|
||||
static uint8_t scsi_bios_completion_code(uint8_t *sense)
|
||||
{
|
||||
switch (sense[12])
|
||||
{
|
||||
case 0x00:
|
||||
return 0x00;
|
||||
case 0x20:
|
||||
return 0x01;
|
||||
case 0x12:
|
||||
case 0x21:
|
||||
return 0x02;
|
||||
case 0x27:
|
||||
return 0x03;
|
||||
case 0x14: case 0x16:
|
||||
return 0x04;
|
||||
case 0x10: case 0x11:
|
||||
return 0x10;
|
||||
case 0x17: case 0x18:
|
||||
return 0x11;
|
||||
case 0x01: case 0x03: case 0x05: case 0x06: case 0x07: case 0x08: case 0x09:
|
||||
case 0x1B: case 0x1C: case 0x1D:
|
||||
case 0x40: case 0x41: case 0x42: case 0x43: case 0x44: case 0x45: case 0x46:
|
||||
case 0x47: case 0x48: case 0x49:
|
||||
return 0x20;
|
||||
case 0x15:
|
||||
case 0x02:
|
||||
return 0x40;
|
||||
case 0x04:
|
||||
case 0x28: case 0x29: case 0x2A:
|
||||
return 0xAA;
|
||||
default:
|
||||
return 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t scsi_bios_command_08(uint8_t id, uint8_t lun, uint8_t *buffer)
|
||||
{
|
||||
uint32_t len = 0;
|
||||
uint8_t cdb[12] = { GPCMD_READ_CDROM_CAPACITY, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||
uint8_t rcbuf[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||
int ret = 0;
|
||||
int i = 0;
|
||||
uint8_t sc = 0;
|
||||
|
||||
ret = scsi_device_read_capacity(id, lun, cdb, rcbuf, &len);
|
||||
sc = scsi_bios_completion_code(scsi_device_sense(id, lun));
|
||||
|
||||
if (ret == 0)
|
||||
{
|
||||
return sc;
|
||||
}
|
||||
|
||||
memset(buffer, 0, 6);
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
buffer[i] = rcbuf[i];
|
||||
}
|
||||
|
||||
for (i = 4; i < 6; i++)
|
||||
{
|
||||
buffer[i] = rcbuf[(i + 2) ^ 1];
|
||||
}
|
||||
|
||||
scsi_bios_command_log("BIOS Command 0x08: %02X %02X %02X %02X %02X %02X\n", buffer[0], buffer[1], buffer[2], buffer[3], buffer[4], buffer[5]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int scsi_bios_command_15(uint8_t id, uint8_t lun, uint8_t *buffer)
|
||||
{
|
||||
uint32_t len = 0;
|
||||
uint8_t cdb[12] = { GPCMD_READ_CDROM_CAPACITY, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||
uint8_t rcbuf[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||
int ret = 0;
|
||||
int i = 0;
|
||||
uint8_t sc = 0;
|
||||
|
||||
ret = scsi_device_read_capacity(id, lun, cdb, rcbuf, &len);
|
||||
sc = scsi_bios_completion_code(scsi_device_sense(id, lun));
|
||||
|
||||
memset(buffer, 0, 6);
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
buffer[i] = (ret == 0) ? 0 : rcbuf[i];
|
||||
}
|
||||
|
||||
scsi_device_type_data(id, lun, &(buffer[4]), &(buffer[5]));
|
||||
|
||||
scsi_bios_command_log("BIOS Command 0x15: %02X %02X %02X %02X %02X %02X\n", buffer[0], buffer[1], buffer[2], buffer[3], buffer[4], buffer[5]);
|
||||
|
||||
return sc;
|
||||
}
|
||||
|
||||
static void BuslogicIDCheck(uint8_t id, uint8_t lun)
|
||||
{
|
||||
if (!scsi_device_valid(id, lun))
|
||||
{
|
||||
fatal("BIOS INT13 CD-ROM on %02i:%02i has disappeared\n", id, lun);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* This returns the completion code. */
|
||||
uint8_t scsi_bios_command(uint8_t last_id, BIOSCMD *BiosCmd, int8_t islba)
|
||||
{
|
||||
uint32_t dma_address;
|
||||
uint32_t lba;
|
||||
int sector_len = BiosCmd->secount;
|
||||
int block_shift = 9;
|
||||
uint8_t ret = 0;
|
||||
uint8_t cdb[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||
|
||||
if (islba)
|
||||
lba = lba32_blk(BiosCmd);
|
||||
else
|
||||
lba = (BiosCmd->u.chs.cyl << 9) + (BiosCmd->u.chs.head << 5) + BiosCmd->u.chs.sec;
|
||||
|
||||
scsi_bios_command_log("BIOS Command = 0x%02X\n", BiosCmd->command);
|
||||
|
||||
if ((BiosCmd->id > last_id) || (BiosCmd->lun > 7)) {
|
||||
return 0x80;
|
||||
}
|
||||
|
||||
SCSIDevices[BiosCmd->id][BiosCmd->lun].InitLength = 0;
|
||||
|
||||
if (!scsi_device_present(BiosCmd->id, BiosCmd->lun))
|
||||
{
|
||||
scsi_bios_command_log("BIOS Target ID %i and LUN %i have no device attached\n",BiosCmd->id,BiosCmd->lun);
|
||||
return 0x80;
|
||||
}
|
||||
|
||||
dma_address = ADDR_TO_U32(BiosCmd->dma_address);
|
||||
|
||||
scsi_bios_command_log("BIOS Data Buffer write: length %d, pointer 0x%04X\n", sector_len, dma_address);
|
||||
|
||||
if (SCSIDevices[BiosCmd->id][BiosCmd->lun].CmdBuffer != NULL)
|
||||
{
|
||||
free(SCSIDevices[BiosCmd->id][BiosCmd->lun].CmdBuffer);
|
||||
SCSIDevices[BiosCmd->id][BiosCmd->lun].CmdBuffer = NULL;
|
||||
}
|
||||
|
||||
block_shift = scsi_device_block_shift(BiosCmd->id, BiosCmd->lun);
|
||||
|
||||
switch(BiosCmd->command)
|
||||
{
|
||||
case 0x00: /* Reset Disk System, in practice it's a nop */
|
||||
return 0;
|
||||
|
||||
case 0x01: /* Read Status of Last Operation */
|
||||
BuslogicIDCheck(BiosCmd->id, BiosCmd->lun);
|
||||
|
||||
/* Assuming 14 bytes because that's the default length for SCSI sense, and no command-specific
|
||||
indication is given. */
|
||||
SCSIDevices[BiosCmd->id][BiosCmd->lun].InitLength = 14;
|
||||
|
||||
SCSIDevices[BiosCmd->id][BiosCmd->lun].CmdBuffer = (uint8_t *) malloc(14);
|
||||
memset(SCSIDevices[BiosCmd->id][BiosCmd->lun].CmdBuffer, 0, 14);
|
||||
|
||||
/* SCSIStatus = scsi_bios_command_08(BiosCmd->id, BiosCmd->lun, SCSIDevices[BiosCmd->id][BiosCmd->lun].CmdBuffer) ? SCSI_STATUS_OK : SCSI_STATUS_CHECK_CONDITION; */
|
||||
|
||||
if (sector_len > 0)
|
||||
{
|
||||
scsi_bios_command_log("BusLogic BIOS DMA: Reading 14 bytes at %08X\n", dma_address);
|
||||
DMAPageWrite(dma_address, (char *)scsi_device_sense(BiosCmd->id, BiosCmd->lun), 14);
|
||||
}
|
||||
|
||||
if (SCSIDevices[BiosCmd->id][BiosCmd->lun].CmdBuffer != NULL)
|
||||
{
|
||||
free(SCSIDevices[BiosCmd->id][BiosCmd->lun].CmdBuffer);
|
||||
SCSIDevices[BiosCmd->id][BiosCmd->lun].CmdBuffer = NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
break;
|
||||
|
||||
case 0x02: /* Read Desired Sectors to Memory */
|
||||
BuslogicIDCheck(BiosCmd->id, BiosCmd->lun);
|
||||
|
||||
SCSIDevices[BiosCmd->id][BiosCmd->lun].InitLength = sector_len << block_shift;
|
||||
|
||||
SCSIDevices[BiosCmd->id][BiosCmd->lun].CmdBuffer = (uint8_t *) malloc(sector_len << block_shift);
|
||||
memset(SCSIDevices[BiosCmd->id][BiosCmd->lun].CmdBuffer, 0, sector_len << block_shift);
|
||||
|
||||
cdb[0] = GPCMD_READ_10;
|
||||
cdb[1] = (BiosCmd->lun & 7) << 5;
|
||||
cdb[2] = (lba >> 24) & 0xff;
|
||||
cdb[3] = (lba >> 16) & 0xff;
|
||||
cdb[4] = (lba >> 8) & 0xff;
|
||||
cdb[5] = lba & 0xff;
|
||||
cdb[7] = (sector_len >> 8) & 0xff;
|
||||
cdb[8] = sector_len & 0xff;
|
||||
#if 0
|
||||
pclog("BIOS CMD(READ, %08lx, %d)\n", lba, BiosCmd->secount);
|
||||
#endif
|
||||
|
||||
scsi_device_command(BiosCmd->id, BiosCmd->lun, 12, cdb);
|
||||
|
||||
if (sector_len > 0)
|
||||
{
|
||||
scsi_bios_command_log("BIOS DMA: Reading %i bytes at %08X\n", sector_len << block_shift, dma_address);
|
||||
DMAPageWrite(dma_address, (char *)SCSIDevices[BiosCmd->id][BiosCmd->lun].CmdBuffer, sector_len << block_shift);
|
||||
}
|
||||
|
||||
if (SCSIDevices[BiosCmd->id][BiosCmd->lun].CmdBuffer != NULL)
|
||||
{
|
||||
free(SCSIDevices[BiosCmd->id][BiosCmd->lun].CmdBuffer);
|
||||
SCSIDevices[BiosCmd->id][BiosCmd->lun].CmdBuffer = NULL;
|
||||
}
|
||||
|
||||
return scsi_bios_completion_code(scsi_device_sense(BiosCmd->id, BiosCmd->lun));
|
||||
|
||||
break;
|
||||
|
||||
case 0x03: /* Write Desired Sectors from Memory */
|
||||
BuslogicIDCheck(BiosCmd->id, BiosCmd->lun);
|
||||
|
||||
SCSIDevices[BiosCmd->id][BiosCmd->lun].InitLength = sector_len << block_shift;
|
||||
|
||||
SCSIDevices[BiosCmd->id][BiosCmd->lun].CmdBuffer = (uint8_t *) malloc(sector_len << block_shift);
|
||||
memset(SCSIDevices[BiosCmd->id][BiosCmd->lun].CmdBuffer, 0, sector_len << block_shift);
|
||||
|
||||
if (sector_len > 0)
|
||||
{
|
||||
scsi_bios_command_log("BIOS DMA: Reading %i bytes at %08X\n", sector_len << block_shift, dma_address);
|
||||
DMAPageRead(dma_address, (char *)SCSIDevices[BiosCmd->id][BiosCmd->lun].CmdBuffer, sector_len << block_shift);
|
||||
}
|
||||
|
||||
cdb[0] = GPCMD_WRITE_10;
|
||||
cdb[1] = (BiosCmd->lun & 7) << 5;
|
||||
cdb[2] = (lba >> 24) & 0xff;
|
||||
cdb[3] = (lba >> 16) & 0xff;
|
||||
cdb[4] = (lba >> 8) & 0xff;
|
||||
cdb[5] = lba & 0xff;
|
||||
cdb[7] = (sector_len >> 8) & 0xff;
|
||||
cdb[8] = sector_len & 0xff;
|
||||
#if 0
|
||||
pclog("BIOS CMD(WRITE, %08lx, %d)\n", lba, BiosCmd->secount);
|
||||
#endif
|
||||
|
||||
scsi_device_command(BiosCmd->id, BiosCmd->lun, 12, cdb);
|
||||
|
||||
if (SCSIDevices[BiosCmd->id][BiosCmd->lun].CmdBuffer != NULL)
|
||||
{
|
||||
free(SCSIDevices[BiosCmd->id][BiosCmd->lun].CmdBuffer);
|
||||
SCSIDevices[BiosCmd->id][BiosCmd->lun].CmdBuffer = NULL;
|
||||
}
|
||||
|
||||
return scsi_bios_completion_code(scsi_device_sense(BiosCmd->id, BiosCmd->lun));
|
||||
|
||||
break;
|
||||
|
||||
case 0x04: /* Verify Desired Sectors */
|
||||
BuslogicIDCheck(BiosCmd->id, BiosCmd->lun);
|
||||
|
||||
cdb[0] = GPCMD_VERIFY_10;
|
||||
cdb[1] = (BiosCmd->lun & 7) << 5;
|
||||
cdb[2] = (lba >> 24) & 0xff;
|
||||
cdb[3] = (lba >> 16) & 0xff;
|
||||
cdb[4] = (lba >> 8) & 0xff;
|
||||
cdb[5] = lba & 0xff;
|
||||
cdb[7] = (sector_len >> 8) & 0xff;
|
||||
cdb[8] = sector_len & 0xff;
|
||||
|
||||
scsi_device_command(BiosCmd->id, BiosCmd->lun, 12, cdb);
|
||||
|
||||
return scsi_bios_completion_code(scsi_device_sense(BiosCmd->id, BiosCmd->lun));
|
||||
|
||||
break;
|
||||
|
||||
case 0x05: /* Format Track, invalid since SCSI has no tracks */
|
||||
return 1;
|
||||
|
||||
break;
|
||||
|
||||
case 0x06: /* Identify SCSI Devices, in practice it's a nop */
|
||||
return 0;
|
||||
|
||||
break;
|
||||
|
||||
case 0x07: /* Format Unit */
|
||||
BuslogicIDCheck(BiosCmd->id, BiosCmd->lun);
|
||||
|
||||
cdb[0] = GPCMD_FORMAT_UNIT;
|
||||
cdb[1] = (BiosCmd->lun & 7) << 5;
|
||||
|
||||
scsi_device_command(BiosCmd->id, BiosCmd->lun, 12, cdb);
|
||||
|
||||
return scsi_bios_completion_code(scsi_device_sense(BiosCmd->id, BiosCmd->lun));
|
||||
|
||||
break;
|
||||
|
||||
case 0x08: /* Read Drive Parameters */
|
||||
BuslogicIDCheck(BiosCmd->id, BiosCmd->lun);
|
||||
|
||||
SCSIDevices[BiosCmd->id][BiosCmd->lun].InitLength = 6;
|
||||
|
||||
SCSIDevices[BiosCmd->id][BiosCmd->lun].CmdBuffer = (uint8_t *) malloc(6);
|
||||
memset(SCSIDevices[BiosCmd->id][BiosCmd->lun].CmdBuffer, 0, 6);
|
||||
|
||||
ret = scsi_bios_command_08(BiosCmd->id, BiosCmd->lun, SCSIDevices[BiosCmd->id][BiosCmd->lun].CmdBuffer);
|
||||
|
||||
scsi_bios_command_log("BIOS DMA: Reading 6 bytes at %08X\n", dma_address);
|
||||
DMAPageWrite(dma_address, (char *)SCSIDevices[BiosCmd->id][BiosCmd->lun].CmdBuffer, 6);
|
||||
|
||||
if (SCSIDevices[BiosCmd->id][BiosCmd->lun].CmdBuffer != NULL)
|
||||
{
|
||||
free(SCSIDevices[BiosCmd->id][BiosCmd->lun].CmdBuffer);
|
||||
SCSIDevices[BiosCmd->id][BiosCmd->lun].CmdBuffer = NULL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
break;
|
||||
|
||||
case 0x09: /* Initialize Drive Pair Characteristics, in practice it's a nop */
|
||||
return 0;
|
||||
|
||||
break;
|
||||
|
||||
case 0x0C: /* Seek */
|
||||
BuslogicIDCheck(BiosCmd->id, BiosCmd->lun);
|
||||
|
||||
SCSIDevices[BiosCmd->id][BiosCmd->lun].InitLength = sector_len << block_shift;
|
||||
|
||||
cdb[0] = GPCMD_SEEK_10;
|
||||
cdb[1] = (BiosCmd->lun & 7) << 5;
|
||||
cdb[2] = (lba >> 24) & 0xff;
|
||||
cdb[3] = (lba >> 16) & 0xff;
|
||||
cdb[4] = (lba >> 8) & 0xff;
|
||||
cdb[5] = lba & 0xff;
|
||||
|
||||
scsi_device_command(BiosCmd->id, BiosCmd->lun, 12, cdb);
|
||||
|
||||
return (SCSIStatus == SCSI_STATUS_OK) ? 1 : 0;
|
||||
|
||||
break;
|
||||
|
||||
case 0x0D: /* Alternate Disk Reset, in practice it's a nop */
|
||||
return 0;
|
||||
|
||||
break;
|
||||
|
||||
case 0x10: /* Test Drive Ready */
|
||||
BuslogicIDCheck(BiosCmd->id, BiosCmd->lun);
|
||||
|
||||
cdb[0] = GPCMD_TEST_UNIT_READY;
|
||||
cdb[1] = (BiosCmd->lun & 7) << 5;
|
||||
|
||||
scsi_device_command(BiosCmd->id, BiosCmd->lun, 12, cdb);
|
||||
|
||||
return scsi_bios_completion_code(scsi_device_sense(BiosCmd->id, BiosCmd->lun));
|
||||
|
||||
break;
|
||||
|
||||
case 0x11: /* Recalibrate */
|
||||
BuslogicIDCheck(BiosCmd->id, BiosCmd->lun);
|
||||
|
||||
cdb[0] = GPCMD_REZERO_UNIT;
|
||||
cdb[1] = (BiosCmd->lun & 7) << 5;
|
||||
|
||||
scsi_device_command(BiosCmd->id, BiosCmd->lun, 12, cdb);
|
||||
|
||||
return scsi_bios_completion_code(scsi_device_sense(BiosCmd->id, BiosCmd->lun));
|
||||
|
||||
break;
|
||||
|
||||
case 0x14: /* Controller Diagnostic */
|
||||
return 0;
|
||||
|
||||
break;
|
||||
|
||||
case 0x15: /* Read DASD Type */
|
||||
BuslogicIDCheck(BiosCmd->id, BiosCmd->lun);
|
||||
|
||||
SCSIDevices[BiosCmd->id][BiosCmd->lun].InitLength = 6;
|
||||
|
||||
SCSIDevices[BiosCmd->id][BiosCmd->lun].CmdBuffer = (uint8_t *) malloc(6);
|
||||
memset(SCSIDevices[BiosCmd->id][BiosCmd->lun].CmdBuffer, 0, 6);
|
||||
|
||||
ret = scsi_bios_command_15(BiosCmd->id, BiosCmd->lun, SCSIDevices[BiosCmd->id][BiosCmd->lun].CmdBuffer);
|
||||
|
||||
scsi_bios_command_log("BusLogic BIOS DMA: Reading 6 bytes at %08X\n", dma_address);
|
||||
DMAPageWrite(dma_address, (char *)SCSIDevices[BiosCmd->id][BiosCmd->lun].CmdBuffer, 6);
|
||||
|
||||
if (SCSIDevices[BiosCmd->id][BiosCmd->lun].CmdBuffer != NULL)
|
||||
{
|
||||
free(SCSIDevices[BiosCmd->id][BiosCmd->lun].CmdBuffer);
|
||||
SCSIDevices[BiosCmd->id][BiosCmd->lun].CmdBuffer = NULL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
scsi_bios_command_log("BusLogic BIOS: Unimplemented command: %02X\n", BiosCmd->command);
|
||||
return 1;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
pclog("BIOS Request complete\n");
|
||||
}
|
||||
47
src/scsi/scsi_bios_command.h
Normal file
47
src/scsi/scsi_bios_command.h
Normal file
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* 86Box A hypervisor and IBM PC system emulator that specializes in
|
||||
* running old operating systems and software designed for IBM
|
||||
* PC systems and compatibles from 1981 through fairly recent
|
||||
* system designs based on the PCI bus.
|
||||
*
|
||||
* This file is part of the 86Box distribution.
|
||||
*
|
||||
* The shared AHA and Buslogic SCSI BIOS command handler's
|
||||
* headler.
|
||||
*
|
||||
* Version: @(#)scsi_bios_command.h 1.0.0 2017/08/26
|
||||
*
|
||||
* Authors: TheCollector1995, <mariogplayer@gmail.com>
|
||||
* Miran Grca, <mgrca8@gmail.com>
|
||||
* Fred N. van Kempen, <decwiz@yahoo.com>
|
||||
* Copyright 2016,2017 Miran Grca.
|
||||
* Copyright 2017 Fred N. van Kempen.
|
||||
*/
|
||||
#pragma pack(push,1)
|
||||
typedef struct
|
||||
{
|
||||
uint8_t command;
|
||||
uint8_t lun:3,
|
||||
reserved:2,
|
||||
id:3;
|
||||
union {
|
||||
struct {
|
||||
uint16_t cyl;
|
||||
uint8_t head;
|
||||
uint8_t sec;
|
||||
} chs;
|
||||
struct {
|
||||
uint8_t lba0; /* MSB */
|
||||
uint8_t lba1;
|
||||
uint8_t lba2;
|
||||
uint8_t lba3; /* LSB */
|
||||
} lba;
|
||||
} u;
|
||||
uint8_t secount;
|
||||
addr24 dma_address;
|
||||
} BIOSCMD;
|
||||
#pragma pack(pop)
|
||||
#define lba32_blk(p) ((uint32_t)(p->u.lba.lba0<<24) | (p->u.lba.lba1<<16) | \
|
||||
(p->u.lba.lba2<<8) | p->u.lba.lba3)
|
||||
|
||||
extern uint8_t scsi_bios_command(uint8_t last_id, BIOSCMD *BiosCmd, int8_t islba);
|
||||
3048
src/scsi/scsi_buslogic.c
Normal file
3048
src/scsi/scsi_buslogic.c
Normal file
File diff suppressed because it is too large
Load Diff
29
src/scsi/scsi_buslogic.h
Normal file
29
src/scsi/scsi_buslogic.h
Normal file
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* 86Box A hypervisor and IBM PC system emulator that specializes in
|
||||
* running old operating systems and software designed for IBM
|
||||
* PC systems and compatibles from 1981 through fairly recent
|
||||
* system designs based on the PCI bus.
|
||||
*
|
||||
* Emulation of BusLogic BT-542B ISA and BT-958D PCI SCSI
|
||||
* controllers.
|
||||
*
|
||||
* Version: @(#)scsi_buslogic.h 1.0.1 2017/08/23
|
||||
*
|
||||
* Authors: TheCollector1995, <mariogplayer@gmail.com>
|
||||
* Miran Grca, <mgrca8@gmail.com>
|
||||
* Fred N. van Kempen, <decwiz@yahoo.com>
|
||||
* Copyright 2016,2017 Miran Grca.
|
||||
* Copyright 2017 Fred N. van Kempen.
|
||||
*/
|
||||
|
||||
#ifndef SCSI_BUSLOGIC_H
|
||||
# define SCSI_BUSLOGIC_H
|
||||
|
||||
|
||||
extern device_t buslogic_device;
|
||||
extern device_t buslogic_pci_device;
|
||||
|
||||
extern void BuslogicDeviceReset(void *p);
|
||||
|
||||
|
||||
#endif /*SCSI_BUSLOGIC_H*/
|
||||
327
src/scsi/scsi_device.c
Normal file
327
src/scsi/scsi_device.c
Normal file
@@ -0,0 +1,327 @@
|
||||
/*
|
||||
* 86Box A hypervisor and IBM PC system emulator that specializes in
|
||||
* running old operating systems and software designed for IBM
|
||||
* PC systems and compatibles from 1981 through fairly recent
|
||||
* system designs based on the PCI bus.
|
||||
*
|
||||
* This file is part of the 86Box distribution.
|
||||
*
|
||||
* The generic SCSI device command handler.
|
||||
*
|
||||
* Version: @(#)scsi_device.c 1.0.1 2017/08/23
|
||||
*
|
||||
* Authors: Miran Grca, <mgrca8@gmail.com>
|
||||
* Fred N. van Kempen, <decwiz@yahoo.com>
|
||||
* Copyright 2016,2017 Miran Grca.
|
||||
* Copyright 2017 Fred N. van Kempen.
|
||||
*/
|
||||
#include "../ibm.h"
|
||||
#include "scsi.h"
|
||||
#include "scsi_disk.h"
|
||||
#include "../cdrom.h"
|
||||
|
||||
|
||||
static uint8_t scsi_null_device_sense[14] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
|
||||
|
||||
|
||||
static void scsi_device_target_command(int lun_type, uint8_t id, uint8_t *cdb)
|
||||
{
|
||||
if (lun_type == SCSI_DISK)
|
||||
{
|
||||
SCSIPhase = SCSI_PHASE_COMMAND;
|
||||
scsi_hd_command(id, cdb);
|
||||
SCSIStatus = scsi_hd_err_stat_to_scsi(id);
|
||||
}
|
||||
else if (lun_type == SCSI_CDROM)
|
||||
{
|
||||
SCSIPhase = SCSI_PHASE_COMMAND;
|
||||
cdrom_command(id, cdb);
|
||||
SCSIStatus = cdrom_CDROM_PHASE_to_scsi(id);
|
||||
}
|
||||
else
|
||||
{
|
||||
SCSIStatus = SCSI_STATUS_CHECK_CONDITION;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int scsi_device_target_phase_to_scsi(int lun_type, uint8_t id)
|
||||
{
|
||||
if (lun_type == SCSI_DISK)
|
||||
{
|
||||
return scsi_hd_phase_to_scsi(id);
|
||||
}
|
||||
else if (lun_type == SCSI_CDROM)
|
||||
{
|
||||
return cdrom_atapi_phase_to_scsi(id);
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void scsi_device_target_phase_callback(int lun_type, uint8_t id)
|
||||
{
|
||||
if (lun_type == SCSI_DISK)
|
||||
{
|
||||
scsi_hd_callback(id);
|
||||
}
|
||||
else if (lun_type == SCSI_CDROM)
|
||||
{
|
||||
cdrom_phase_callback(id);
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int scsi_device_target_err_stat_to_scsi(int lun_type, uint8_t id)
|
||||
{
|
||||
if (lun_type == SCSI_DISK)
|
||||
{
|
||||
return scsi_hd_err_stat_to_scsi(id);
|
||||
}
|
||||
else if (lun_type == SCSI_CDROM)
|
||||
{
|
||||
return cdrom_CDROM_PHASE_to_scsi(id);
|
||||
}
|
||||
else
|
||||
{
|
||||
return SCSI_STATUS_CHECK_CONDITION;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void scsi_device_target_save_cdb_byte(int lun_type, uint8_t id, uint8_t cdb_byte)
|
||||
{
|
||||
if (lun_type == SCSI_DISK)
|
||||
{
|
||||
shdc[id].request_length = cdb_byte;
|
||||
}
|
||||
else if (lun_type == SCSI_CDROM)
|
||||
{
|
||||
cdrom[id].request_length = cdb_byte;
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint8_t *scsi_device_sense(uint8_t scsi_id, uint8_t scsi_lun)
|
||||
{
|
||||
uint8_t lun_type = SCSIDevices[scsi_id][scsi_lun].LunType;
|
||||
|
||||
uint8_t id = 0;
|
||||
|
||||
switch (lun_type)
|
||||
{
|
||||
case SCSI_DISK:
|
||||
id = scsi_hard_disks[scsi_id][scsi_lun];
|
||||
return shdc[id].sense;
|
||||
break;
|
||||
case SCSI_CDROM:
|
||||
id = scsi_cdrom_drives[scsi_id][scsi_lun];
|
||||
return cdrom[id].sense;
|
||||
break;
|
||||
default:
|
||||
return scsi_null_device_sense;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void scsi_device_request_sense(uint8_t scsi_id, uint8_t scsi_lun, uint8_t *buffer, uint8_t alloc_length)
|
||||
{
|
||||
uint8_t lun_type = SCSIDevices[scsi_id][scsi_lun].LunType;
|
||||
|
||||
uint8_t id = 0;
|
||||
|
||||
switch (lun_type)
|
||||
{
|
||||
case SCSI_DISK:
|
||||
id = scsi_hard_disks[scsi_id][scsi_lun];
|
||||
scsi_hd_request_sense_for_scsi(id, buffer, alloc_length);
|
||||
break;
|
||||
case SCSI_CDROM:
|
||||
id = scsi_cdrom_drives[scsi_id][scsi_lun];
|
||||
cdrom_request_sense_for_scsi(id, buffer, alloc_length);
|
||||
break;
|
||||
default:
|
||||
memcpy(buffer, scsi_null_device_sense, alloc_length);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void scsi_device_type_data(uint8_t scsi_id, uint8_t scsi_lun, uint8_t *type, uint8_t *rmb)
|
||||
{
|
||||
uint8_t lun_type = SCSIDevices[scsi_id][scsi_lun].LunType;
|
||||
|
||||
uint8_t id = 0;
|
||||
|
||||
switch (lun_type)
|
||||
{
|
||||
case SCSI_DISK:
|
||||
id = scsi_hard_disks[scsi_id][scsi_lun];
|
||||
*type = 0x00;
|
||||
*rmb = (hdc[id].bus == HDD_BUS_SCSI_REMOVABLE) ? 0x80 : 0x00;
|
||||
break;
|
||||
case SCSI_CDROM:
|
||||
*type = 0x05;
|
||||
*rmb = 0x80;
|
||||
break;
|
||||
default:
|
||||
*type = *rmb = 0xFF;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int scsi_device_read_capacity(uint8_t scsi_id, uint8_t scsi_lun, uint8_t *cdb, uint8_t *buffer, uint32_t *len)
|
||||
{
|
||||
uint8_t lun_type = SCSIDevices[scsi_id][scsi_lun].LunType;
|
||||
|
||||
uint8_t id = 0;
|
||||
|
||||
switch (lun_type)
|
||||
{
|
||||
case SCSI_DISK:
|
||||
id = scsi_hard_disks[scsi_id][scsi_lun];
|
||||
return scsi_hd_read_capacity(id, cdb, buffer, len);
|
||||
case SCSI_CDROM:
|
||||
id = scsi_hard_disks[scsi_id][scsi_lun];
|
||||
return cdrom_read_capacity(id, cdb, buffer, len);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int scsi_device_present(uint8_t scsi_id, uint8_t scsi_lun)
|
||||
{
|
||||
uint8_t lun_type = SCSIDevices[scsi_id][scsi_lun].LunType;
|
||||
|
||||
switch (lun_type)
|
||||
{
|
||||
case SCSI_NONE:
|
||||
return 0;
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int scsi_device_valid(uint8_t scsi_id, uint8_t scsi_lun)
|
||||
{
|
||||
uint8_t lun_type = SCSIDevices[scsi_id][scsi_lun].LunType;
|
||||
|
||||
uint8_t id = 0;
|
||||
|
||||
switch (lun_type)
|
||||
{
|
||||
case SCSI_DISK:
|
||||
id = scsi_hard_disks[scsi_id][scsi_lun];
|
||||
break;
|
||||
case SCSI_CDROM:
|
||||
id = scsi_cdrom_drives[scsi_id][scsi_lun];
|
||||
break;
|
||||
default:
|
||||
id = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
return (id == 0xFF) ? 0 : 1;
|
||||
}
|
||||
|
||||
|
||||
int scsi_device_cdb_length(uint8_t scsi_id, uint8_t scsi_lun)
|
||||
{
|
||||
uint8_t lun_type = SCSIDevices[scsi_id][scsi_lun].LunType;
|
||||
|
||||
uint8_t id = 0;
|
||||
|
||||
switch (lun_type)
|
||||
{
|
||||
case SCSI_CDROM:
|
||||
id = scsi_cdrom_drives[scsi_id][scsi_lun];
|
||||
return cdrom[id].cdb_len;
|
||||
default:
|
||||
return 12;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int scsi_device_block_shift(uint8_t scsi_id, uint8_t scsi_lun)
|
||||
{
|
||||
uint8_t lun_type = SCSIDevices[scsi_id][scsi_lun].LunType;
|
||||
|
||||
switch (lun_type)
|
||||
{
|
||||
case SCSI_CDROM:
|
||||
return 11; /* 2048 bytes per block */
|
||||
default:
|
||||
return 9; /* 512 bytes per block */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void scsi_device_command(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;
|
||||
|
||||
uint8_t id = 0;
|
||||
|
||||
switch (lun_type)
|
||||
{
|
||||
case SCSI_DISK:
|
||||
id = scsi_hard_disks[scsi_id][scsi_lun];
|
||||
break;
|
||||
case SCSI_CDROM:
|
||||
id = scsi_cdrom_drives[scsi_id][scsi_lun];
|
||||
break;
|
||||
default:
|
||||
id = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Since that field in the target struct is never used when
|
||||
* the bus type is SCSI, let's use it for this scope.
|
||||
*/
|
||||
scsi_device_target_save_cdb_byte(lun_type, id, cdb[1]);
|
||||
|
||||
if (cdb_len != 12) {
|
||||
/*
|
||||
* Make sure the LUN field of the temporary CDB is always 0,
|
||||
* otherwise Daemon Tools drives will misbehave when a command
|
||||
* is passed through to them.
|
||||
*/
|
||||
cdb[1] &= 0x1f;
|
||||
}
|
||||
|
||||
/* Finally, execute the SCSI command immediately and get the transfer length. */
|
||||
scsi_device_target_command(lun_type, id, cdb);
|
||||
if (SCSIStatus == SCSI_STATUS_OK) {
|
||||
phase = scsi_device_target_phase_to_scsi(lun_type, id);
|
||||
if (phase == 2) {
|
||||
/* Command completed - call the phase callback to complete the command. */
|
||||
scsi_device_target_phase_callback(lun_type, id);
|
||||
} else {
|
||||
/* Command first phase complete - call the callback to execute the second phase. */
|
||||
scsi_device_target_phase_callback(lun_type, id);
|
||||
SCSIStatus = scsi_device_target_err_stat_to_scsi(lun_type, id);
|
||||
/* Command second phase complete - call the callback to complete the command. */
|
||||
scsi_device_target_phase_callback(lun_type, id);
|
||||
}
|
||||
} else {
|
||||
/* Error (Check Condition) - call the phase callback to complete the command. */
|
||||
scsi_device_target_phase_callback(lun_type, id);
|
||||
}
|
||||
}
|
||||
37
src/scsi/scsi_device.h
Normal file
37
src/scsi/scsi_device.h
Normal file
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* 86Box A hypervisor and IBM PC system emulator that specializes in
|
||||
* running old operating systems and software designed for IBM
|
||||
* PC systems and compatibles from 1981 through fairly recent
|
||||
* system designs based on the PCI bus.
|
||||
*
|
||||
* This file is part of the 86Box distribution.
|
||||
*
|
||||
* Definitions for the generic SCSI device command handler.
|
||||
*
|
||||
* Version: @(#)scsi_device.h 1.0.2 2017/08/22
|
||||
*
|
||||
* Authors: Miran Grca, <mgrca8@gmail.com>
|
||||
* Fred N. van Kempen, <decwiz@yahoo.com>
|
||||
*/
|
||||
#ifndef SCSI_DEVICE_H
|
||||
# define SCSI_DEVICE_H
|
||||
|
||||
|
||||
extern uint8_t *scsi_device_sense(uint8_t id, uint8_t lun);
|
||||
extern void scsi_device_type_data(uint8_t id, uint8_t lun,
|
||||
uint8_t *type, uint8_t *rmb);
|
||||
extern void scsi_device_request_sense(uint8_t scsi_id, uint8_t scsi_lun,
|
||||
uint8_t *buffer,
|
||||
uint8_t alloc_length);
|
||||
extern int scsi_device_read_capacity(uint8_t id, uint8_t lun,
|
||||
uint8_t *cdb, uint8_t *buffer,
|
||||
uint32_t *len);
|
||||
extern int scsi_device_present(uint8_t id, uint8_t lun);
|
||||
extern int scsi_device_valid(uint8_t id, uint8_t lun);
|
||||
extern int scsi_device_cdb_length(uint8_t id, uint8_t lun);
|
||||
extern int scsi_device_block_shift(uint8_t id, uint8_t lun);
|
||||
extern void scsi_device_command(uint8_t id, uint8_t lun, int cdb_len,
|
||||
uint8_t *cdb);
|
||||
|
||||
|
||||
#endif /*SCSI_DEVICE_H*/
|
||||
1196
src/scsi/scsi_disk.c
Normal file
1196
src/scsi/scsi_disk.c
Normal file
File diff suppressed because it is too large
Load Diff
56
src/scsi/scsi_disk.h
Normal file
56
src/scsi/scsi_disk.h
Normal file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* 86Box A hypervisor and IBM PC system emulator that specializes in
|
||||
* running old operating systems and software designed for IBM
|
||||
* PC systems and compatibles from 1981 through fairly recent
|
||||
* system designs based on the PCI bus.
|
||||
*
|
||||
* Emulation of SCSI fixed and removable disks.
|
||||
*
|
||||
* Version: @(#)scsi_disk.h 1.0.1 2017/08/23
|
||||
*
|
||||
* Author: Miran Grca, <mgrca8@gmail.com>
|
||||
* Copyright 2017 Miran Grca.
|
||||
*/
|
||||
|
||||
#pragma pack(push,1)
|
||||
typedef struct {
|
||||
/* Stuff for SCSI hard disks. */
|
||||
uint8_t cdb[16];
|
||||
uint8_t current_cdb[16];
|
||||
uint8_t max_cdb_len;
|
||||
int requested_blocks;
|
||||
int max_blocks_at_once;
|
||||
uint16_t request_length;
|
||||
int block_total;
|
||||
int all_blocks_total;
|
||||
uint32_t packet_len;
|
||||
int packet_status;
|
||||
uint8_t status;
|
||||
uint8_t phase;
|
||||
uint32_t pos;
|
||||
int callback;
|
||||
int total_read;
|
||||
int unit_attention;
|
||||
uint8_t sense[256];
|
||||
uint8_t previous_command;
|
||||
uint8_t error;
|
||||
uint32_t sector_pos;
|
||||
uint32_t sector_len;
|
||||
uint32_t seek_pos;
|
||||
int data_pos;
|
||||
int old_len;
|
||||
int request_pos;
|
||||
uint8_t hd_cdb[16];
|
||||
} scsi_hard_disk_t;
|
||||
#pragma pack(pop)
|
||||
|
||||
extern scsi_hard_disk_t shdc[HDC_NUM];
|
||||
|
||||
extern void scsi_disk_insert(uint8_t id);
|
||||
extern void scsi_loadhd(int scsi_id, int scsi_lun, int id);
|
||||
extern void scsi_reloadhd(int id);
|
||||
extern void scsi_unloadhd(int scsi_id, int scsi_lun, int id);
|
||||
|
||||
extern FILE *shdf[HDC_NUM];
|
||||
|
||||
int scsi_hd_read_capacity(uint8_t id, uint8_t *cdb, uint8_t *buffer, uint32_t *len);
|
||||
Reference in New Issue
Block a user