2020-03-24 01:00:28 +01:00
/*
* 86 Box 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 86 Box distribution .
*
* Implementation of the IBM PS / 2 SCSI controller with
* cache for MCA only .
*
2020-03-25 00:46:02 +02:00
*
2020-03-24 01:00:28 +01:00
*
* Authors : Sarah Walker , < http : //pcem-emulator.co.uk/>
* TheCollector1995 , < mariogplayer @ gmail . com >
*
* Copyright 2020 Sarah Walker .
* Copyright 2020 TheCollector1995 .
*/
# include <inttypes.h>
# include <stdio.h>
# include <stdint.h>
# include <string.h>
# include <stdlib.h>
# include <stdarg.h>
# include <wchar.h>
# define HAVE_STDARG_H
2020-03-29 14:24:42 +02:00
# include <86box/86box.h>
# include <86box/io.h>
# include <86box/timer.h>
# include <86box/dma.h>
# include <86box/pic.h>
# include <86box/mca.h>
# include <86box/mem.h>
# include <86box/rom.h>
# include <86box/device.h>
# include <86box/nvr.h>
# include <86box/plat.h>
# include <86box/scsi.h>
# include <86box/scsi_device.h>
# include <86box/scsi_spock.h>
2020-03-24 01:00:28 +01:00
# define SPOCK_U68_1990_ROM L"roms / scsi / ibm / 64f4376.bin"
# define SPOCK_U69_1990_ROM L"roms / scsi / ibm / 64f4377.bin"
# define SPOCK_U68_1991_ROM L"roms / scsi / ibm / 92F2244.U68"
# define SPOCK_U69_1991_ROM L"roms / scsi / ibm / 92F2245.U69"
# define SPOCK_TIME (20)
typedef enum
{
SCSI_STATE_IDLE ,
SCSI_STATE_SELECT ,
SCSI_STATE_SEND_COMMAND ,
SCSI_STATE_END_PHASE
} scsi_state_t ;
# pragma pack(push,1)
typedef struct {
uint16_t pos ;
2020-04-08 21:58:52 +02:00
uint16_t pos1 ;
2020-03-24 01:00:28 +01:00
uint16_t pos2 ;
uint16_t pos3 ;
uint16_t pos4 ;
uint16_t pos5 ;
uint16_t pos6 ;
uint16_t pos7 ;
uint16_t pos8 ;
} get_pos_info_t ;
typedef struct {
uint16_t scb_status ;
uint16_t retry_count ;
uint32_t residual_byte_count ;
uint32_t sg_list_element_addr ;
uint16_t device_dep_status_len ;
uint16_t cmd_status ;
uint16_t error ;
uint16_t reserved ;
uint16_t cache_info_status ;
uint32_t scb_addr ;
} get_complete_stat_t ;
typedef struct {
uint32_t sys_buf_addr ;
uint32_t sys_buf_byte_count ;
} SGE ;
typedef struct {
uint16_t command ;
uint16_t enable ;
uint32_t lba_addr ;
SGE sge ;
uint32_t term_status_block_addr ;
uint32_t scb_chain_addr ;
uint16_t block_count ;
uint16_t block_length ;
} scb_t ;
# pragma pack(pop)
typedef struct {
rom_t bios_rom ;
int bios_ver ;
int irq , irq_inactive ;
uint8_t pos_regs [ 8 ] ;
uint8_t basic_ctrl ;
uint32_t command ;
uint8_t attention ,
attention_pending ;
int attention_wait ;
uint8_t cir [ 4 ] ,
cir_pending [ 4 ] ;
uint8_t irq_status ;
uint32_t scb_addr ;
uint8_t status ;
get_complete_stat_t get_complete_stat ;
get_pos_info_t get_pos_info ;
scb_t scb ;
2020-09-20 16:19:44 +02:00
int adapter_reset ;
2020-03-24 01:00:28 +01:00
int scb_id ;
2020-09-20 16:19:44 +02:00
int adapter_id ;
2020-03-24 01:00:28 +01:00
int cmd_status ;
int cir_status ;
uint8_t pacing ;
uint8_t buf [ 0x600 ] ;
struct {
int phys_id ;
int lun_id ;
} dev_id [ SCSI_ID_MAX ] ;
uint8_t last_status ;
uint8_t cdb [ 12 ] ;
int cdb_len ;
int cdb_id ;
uint32_t data_ptr , data_len ;
uint8_t temp_cdb [ 12 ] ;
int irq_requests [ SCSI_ID_MAX ] ;
pc_timer_t callback_timer ;
int cmd_timer ;
int scb_state ;
int in_reset ;
int in_invalid ;
uint64_t temp_period ;
double media_period ;
scsi_state_t scsi_state ;
} spock_t ;
# define CTRL_RESET (1 << 7)
# define CTRL_DMA_ENA (1 << 1)
# define CTRL_IRQ_ENA (1 << 0)
# define STATUS_CMD_FULL (1 << 3)
# define STATUS_CMD_EMPTY (1 << 2)
# define STATUS_IRQ (1 << 1)
# define STATUS_BUSY (1 << 0)
# define ENABLE_PT (1 << 12)
# define CMD_MASK 0xff3f
# define CMD_ASSIGN 0x040e
# define CMD_DEVICE_INQUIRY 0x1c0b
# define CMD_DMA_PACING_CONTROL 0x040d
# define CMD_FEATURE_CONTROL 0x040c
# define CMD_GET_POS_INFO 0x1c0a
# define CMD_INVALID_412 0x0412
# define CMD_GET_COMPLETE_STATUS 0x1c07
# define CMD_FORMAT_UNIT 0x1c16
# define CMD_READ_DATA 0x1c01
# define CMD_READ_DEVICE_CAPACITY 0x1c09
# define CMD_REQUEST_SENSE 0x1c08
# define CMD_RESET 0x0400
# define CMD_SEND_OTHER_SCSI 0x241f
# define CMD_UNKNOWN_1C10 0x1c10
# define CMD_UNKNOWN_1C11 0x1c11
# define CMD_WRITE_DATA 0x1c02
# define CMD_VERIFY 0x1c03
# define IRQ_TYPE_NONE 0x0
# define IRQ_TYPE_SCB_COMPLETE 0x1
# define IRQ_TYPE_SCB_COMPLETE_RETRY 0x5
# define IRQ_TYPE_ADAPTER_HW_FAILURE 0x7
# define IRQ_TYPE_IMM_CMD_COMPLETE 0xa
# define IRQ_TYPE_COMMAND_FAIL 0xc
# define IRQ_TYPE_COMMAND_ERROR 0xe
# define IRQ_TYPE_SW_SEQ_ERROR 0xf
# define IRQ_TYPE_RESET_COMPLETE 0x10
# ifdef ENABLE_SPOCK_LOG
int spock_do_log = ENABLE_SPOCK_LOG ;
static void
spock_log ( const char * fmt , . . . )
{
va_list ap ;
if ( spock_do_log ) {
va_start ( ap , fmt ) ;
pclog_ex ( fmt , ap ) ;
va_end ( ap ) ;
}
}
# else
# define spock_log(fmt, ...)
# endif
static void
spock_rethink_irqs ( spock_t * scsi )
{
int irq_pending = 0 ;
int c ;
if ( ! scsi - > irq_status ) {
for ( c = 0 ; c < SCSI_ID_MAX ; c + + ) {
if ( scsi - > irq_requests [ c ] ! = IRQ_TYPE_NONE ) {
/* Found IRQ */
scsi - > irq_status = c | ( scsi - > irq_requests [ c ] < < 4 ) ;
spock_log ( " Found IRQ: status = %02x \n " , scsi - > irq_status ) ;
scsi - > status | = STATUS_IRQ ;
irq_pending = 1 ;
break ;
}
}
} else
irq_pending = 1 ;
if ( scsi - > basic_ctrl & CTRL_IRQ_ENA ) {
if ( irq_pending ) {
spock_log ( " IRQ issued \n " ) ;
scsi - > irq_inactive = 0 ;
picint ( 1 < < scsi - > irq ) ;
} else {
/* No IRQs pending, clear IRQ state */
spock_log ( " IRQ cleared \n " ) ;
scsi - > irq_status = 0 ;
scsi - > irq_inactive = 1 ;
scsi - > status & = ~ STATUS_IRQ ;
picintc ( 1 < < scsi - > irq ) ;
}
} else {
spock_log ( " IRQ disabled \n " ) ;
picintc ( 1 < < scsi - > irq ) ;
}
}
static __inline void
spock_set_irq ( spock_t * scsi , int id , int type )
{
spock_log ( " spock_set_irq id=%i type=%x %02x \n " , id , type , scsi - > irq_status ) ;
scsi - > irq_requests [ id ] = type ;
if ( ! scsi - > irq_status ) /* Don't change IRQ status if one is currently being processed */
spock_rethink_irqs ( scsi ) ;
}
static __inline void
spock_clear_irq ( spock_t * scsi , int id )
{
spock_log ( " spock_clear_irq id=%i \n " , id ) ;
scsi - > irq_requests [ id ] = IRQ_TYPE_NONE ;
spock_rethink_irqs ( scsi ) ;
}
static void
spock_add_to_period ( spock_t * scsi , int TransferLength )
{
scsi - > temp_period + = ( uint64_t ) TransferLength ;
}
static void
spock_write ( uint16_t port , uint8_t val , void * p )
{
spock_t * scsi = ( spock_t * ) p ;
spock_log ( " spock_write: port=%04x val=%02x %04x:%04x \n " , port , val , CS , cpu_state . pc ) ;
switch ( port & 7 ) {
case 0 : case 1 : case 2 : case 3 : /*Command Interface Register*/
scsi - > cir_pending [ port & 3 ] = val ;
if ( port & 2 )
scsi - > cir_status | = 2 ;
else
scsi - > cir_status | = 1 ;
break ;
case 4 : /*Attention Register*/
scsi - > attention_pending = val ;
scsi - > attention_wait = 2 ;
scsi - > status | = STATUS_BUSY ;
break ;
case 5 : /*Basic Control Register*/
if ( ( scsi - > basic_ctrl & CTRL_RESET ) & & ! ( val & CTRL_RESET ) ) {
spock_log ( " Spock: SCSI reset and busy \n " ) ;
scsi - > in_reset = 1 ;
scsi - > cmd_timer = SPOCK_TIME * 2 ;
scsi - > status | = STATUS_BUSY ;
}
scsi - > basic_ctrl = val ;
spock_rethink_irqs ( scsi ) ;
break ;
}
}
static void
spock_writew ( uint16_t port , uint16_t val , void * p )
{
spock_t * scsi = ( spock_t * ) p ;
switch ( port & 7 ) {
case 0 : /*Command Interface Register*/
scsi - > cir_pending [ 0 ] = val & 0xff ;
scsi - > cir_pending [ 1 ] = val > > 8 ;
scsi - > cir_status | = 1 ;
break ;
case 2 : /*Command Interface Register*/
scsi - > cir_pending [ 2 ] = val & 0xff ;
scsi - > cir_pending [ 3 ] = val > > 8 ;
scsi - > cir_status | = 2 ;
break ;
}
spock_log ( " spock_writew: port=%04x val=%04x \n " , port , val ) ;
}
static uint8_t
spock_read ( uint16_t port , void * p )
{
spock_t * scsi = ( spock_t * ) p ;
uint8_t temp = 0xff ;
switch ( port & 7 ) {
case 0 : case 1 : case 2 : case 3 : /*Command Interface Register*/
temp = scsi - > cir_pending [ port & 3 ] ;
break ;
case 4 : /*Attention Register*/
temp = scsi - > attention_pending ;
break ;
case 5 : /*Basic Control Register*/
temp = scsi - > basic_ctrl ;
break ;
case 6 : /*IRQ status*/
temp = scsi - > irq_status ;
break ;
case 7 : /*Basic Status Register*/
temp = scsi - > status ;
2020-09-20 16:19:44 +02:00
spock_log ( " Cir Status=%d \n " , scsi - > cir_status ) ;
2020-03-24 01:00:28 +01:00
if ( scsi - > cir_status = = 0 ) {
spock_log ( " Status Cmd Empty \n " ) ;
temp | = STATUS_CMD_EMPTY ;
}
2020-09-20 16:19:44 +02:00
else if ( scsi - > cir_status = = 3 ) {
2020-03-24 01:00:28 +01:00
spock_log ( " Status Cmd Full \n " ) ;
temp | = STATUS_CMD_FULL ;
}
break ;
}
spock_log ( " spock_read: port=%04x val=%02x %04x(%05x):%04x %02x \n " , port , temp , CS , cs , cpu_state . pc , BH ) ;
return temp ;
}
static uint16_t
spock_readw ( uint16_t port , void * p )
{
spock_t * scsi = ( spock_t * ) p ;
uint16_t temp = 0xffff ;
switch ( port & 7 ) {
case 0 : /*Command Interface Register*/
temp = scsi - > cir_pending [ 0 ] | ( scsi - > cir_pending [ 1 ] < < 8 ) ;
break ;
case 2 : /*Command Interface Register*/
temp = scsi - > cir_pending [ 2 ] | ( scsi - > cir_pending [ 3 ] < < 8 ) ;
break ;
}
spock_log ( " spock_readw: port=%04x val=%04x \n " , port , temp ) ;
return temp ;
}
static void
spock_rd_sge ( spock_t * scsi , uint32_t Address , SGE * SG )
{
2020-04-28 01:01:39 +02:00
dma_bm_read ( Address , ( uint8_t * ) SG , sizeof ( SGE ) , 2 ) ;
2020-03-24 01:00:28 +01:00
spock_add_to_period ( scsi , sizeof ( SGE ) ) ;
}
static int
spock_get_len ( spock_t * scsi , scb_t * scb )
{
uint32_t DataToTransfer = 0 , i = 0 ;
spock_log ( " Data Buffer write: length %d, pointer 0x%04X \n " ,
scsi - > data_len , scsi - > data_ptr ) ;
if ( ! scsi - > data_len )
return ( 0 ) ;
if ( scb - > enable & ENABLE_PT ) {
for ( i = 0 ; i < scsi - > data_len ; i + = 8 ) {
spock_rd_sge ( scsi , scsi - > data_ptr + i , & scb - > sge ) ;
DataToTransfer + = scb - > sge . sys_buf_byte_count ;
}
return ( DataToTransfer ) ;
} else {
return ( scsi - > data_len ) ;
}
}
static void
spock_process_imm_cmd ( spock_t * scsi )
{
int i ;
int adapter_id , phys_id , lun_id ;
switch ( scsi - > command & CMD_MASK ) {
case CMD_ASSIGN :
adapter_id = ( scsi - > command > > 16 ) & 15 ;
phys_id = ( scsi - > command > > 20 ) & 7 ;
lun_id = ( scsi - > command > > 24 ) & 7 ;
2020-09-20 16:19:44 +02:00
2020-03-24 01:00:28 +01:00
if ( adapter_id = = 15 ) {
if ( phys_id = = 7 ) /*Device 15 always adapter*/
spock_set_irq ( scsi , scsi - > attention & 0x0f , IRQ_TYPE_IMM_CMD_COMPLETE ) ;
else /*Can not re-assign device 15 (always adapter)*/
spock_set_irq ( scsi , scsi - > attention & 0x0f , IRQ_TYPE_COMMAND_FAIL ) ;
} else {
if ( scsi - > command & ( 1 < < 23 ) ) {
2020-09-20 16:19:44 +02:00
spock_log ( " Assign: adapter id=%d \n " , adapter_id ) ;
2020-03-24 01:00:28 +01:00
scsi - > dev_id [ adapter_id ] . phys_id = - 1 ;
spock_set_irq ( scsi , scsi - > attention & 0x0f , IRQ_TYPE_IMM_CMD_COMPLETE ) ;
} else {
2020-09-20 16:19:44 +02:00
if ( phys_id ! = scsi - > adapter_id ) {
scsi - > dev_id [ adapter_id ] . phys_id = phys_id ;
scsi - > dev_id [ adapter_id ] . lun_id = lun_id ;
spock_log ( " Assign: adapter dev=%x scsi ID=%i LUN=%i \n " , adapter_id , scsi - > dev_id [ adapter_id ] . phys_id , scsi - > dev_id [ adapter_id ] . lun_id ) ;
spock_set_irq ( scsi , scsi - > attention & 0x0f , IRQ_TYPE_IMM_CMD_COMPLETE ) ;
} else { /*Can not assign adapter*/
spock_log ( " Assign: PUN=%d, cannot assign adapter \n " , phys_id ) ;
spock_set_irq ( scsi , scsi - > attention & 0x0f , IRQ_TYPE_COMMAND_FAIL ) ;
}
2020-03-24 01:00:28 +01:00
}
}
break ;
case CMD_DMA_PACING_CONTROL :
scsi - > pacing = scsi - > cir [ 2 ] ;
spock_log ( " Pacing control: %i \n " , scsi - > pacing ) ;
spock_set_irq ( scsi , scsi - > attention & 0x0f , IRQ_TYPE_IMM_CMD_COMPLETE ) ;
break ;
case CMD_FEATURE_CONTROL :
spock_log ( " Feature control: timeout=%is d-rate=%i \n " , ( scsi - > command > > 16 ) & 0x1fff , scsi - > command > > 29 ) ;
spock_set_irq ( scsi , scsi - > attention & 0x0f , IRQ_TYPE_IMM_CMD_COMPLETE ) ;
break ;
case CMD_INVALID_412 :
spock_log ( " Invalid 412 \n " ) ;
spock_set_irq ( scsi , scsi - > attention & 0x0f , IRQ_TYPE_IMM_CMD_COMPLETE ) ;
break ;
case CMD_RESET :
spock_log ( " Reset Command \n " ) ;
2020-09-20 16:19:44 +02:00
if ( ( scsi - > attention & 0x0f ) = = 0x0f ) { /*Adapter reset*/
for ( i = 0 ; i < 8 ; i + + )
2020-03-24 01:00:28 +01:00
scsi_device_reset ( & scsi_devices [ i ] ) ;
spock_log ( " Adapter Reset \n " ) ;
2020-09-20 16:19:44 +02:00
if ( ! scsi - > adapter_reset )
scsi - > adapter_reset = 1 ;
else
scsi - > adapter_reset = 0 ;
scsi - > scb_state = 0 ;
2020-03-24 01:00:28 +01:00
}
spock_set_irq ( scsi , scsi - > attention & 0x0f , IRQ_TYPE_IMM_CMD_COMPLETE ) ;
break ;
default :
fatal ( " scsi_callback: Bad command %02x \n " , scsi - > command ) ;
break ;
}
}
static void
spock_execute_cmd ( spock_t * scsi , scb_t * scb )
{
int c ;
int old_scb_state ;
if ( scsi - > in_reset ) {
spock_log ( " Reset type = %d \n " , scsi - > in_reset ) ;
scsi - > status & = ~ STATUS_BUSY ;
scsi - > irq_status = 0 ;
for ( c = 0 ; c < SCSI_ID_MAX ; c + + )
spock_clear_irq ( scsi , c ) ;
2020-09-20 16:19:44 +02:00
if ( scsi - > in_reset = = 1 ) {
2020-03-24 01:00:28 +01:00
scsi - > basic_ctrl | = CTRL_IRQ_ENA ;
2020-09-20 16:19:44 +02:00
spock_set_irq ( scsi , 0xf , IRQ_TYPE_RESET_COMPLETE ) ;
2020-03-24 01:00:28 +01:00
} else
2020-09-20 16:19:44 +02:00
spock_set_irq ( scsi , 0xf , IRQ_TYPE_RESET_COMPLETE ) ;
2020-03-24 01:00:28 +01:00
/*Reset device mappings*/
for ( c = 0 ; c < 7 ; c + + ) {
scsi - > dev_id [ c ] . phys_id = c ;
scsi - > dev_id [ c ] . lun_id = 0 ;
}
for ( ; c < ( SCSI_ID_MAX - 1 ) ; c + + )
scsi - > dev_id [ c ] . phys_id = - 1 ;
scsi - > in_reset = 0 ;
return ;
}
if ( scsi - > in_invalid ) {
spock_log ( " Invalid command \n " ) ;
spock_set_irq ( scsi , scsi - > attention & 0x0f , IRQ_TYPE_COMMAND_ERROR ) ;
scsi - > in_invalid = 0 ;
return ;
}
2020-09-20 16:19:44 +02:00
spock_log ( " SCB State = %d \n " , scsi - > scb_state ) ;
2020-03-24 01:00:28 +01:00
do
{
old_scb_state = scsi - > scb_state ;
switch ( scsi - > scb_state ) {
case 0 : /* Idle */
break ;
case 1 : /* Select */
if ( scsi - > dev_id [ scsi - > scb_id ] . phys_id = = - 1 ) {
uint16_t term_stat_block_addr7 = ( 0xe < < 8 ) | 0 ;
uint16_t term_stat_block_addr8 = ( 0xa < < 8 ) | 0 ;
spock_log ( " Start failed, SCB ID = %d \n " , scsi - > scb_id ) ;
spock_set_irq ( scsi , scsi - > scb_id , IRQ_TYPE_COMMAND_FAIL ) ;
scsi - > scb_state = 0 ;
2020-04-28 01:01:39 +02:00
dma_bm_write ( scb - > term_status_block_addr + 0x7 * 2 , ( uint8_t * ) & term_stat_block_addr7 , 2 , 2 ) ;
dma_bm_write ( scb - > term_status_block_addr + 0x8 * 2 , ( uint8_t * ) & term_stat_block_addr8 , 2 , 2 ) ;
2020-03-24 01:00:28 +01:00
break ;
}
2020-04-28 01:01:39 +02:00
dma_bm_read ( scsi - > scb_addr , ( uint8_t * ) & scb - > command , 2 , 2 ) ;
dma_bm_read ( scsi - > scb_addr + 2 , ( uint8_t * ) & scb - > enable , 2 , 2 ) ;
dma_bm_read ( scsi - > scb_addr + 4 , ( uint8_t * ) & scb - > lba_addr , 4 , 2 ) ;
dma_bm_read ( scsi - > scb_addr + 8 , ( uint8_t * ) & scb - > sge . sys_buf_addr , 4 , 2 ) ;
dma_bm_read ( scsi - > scb_addr + 12 , ( uint8_t * ) & scb - > sge . sys_buf_byte_count , 4 , 2 ) ;
dma_bm_read ( scsi - > scb_addr + 16 , ( uint8_t * ) & scb - > term_status_block_addr , 4 , 2 ) ;
dma_bm_read ( scsi - > scb_addr + 20 , ( uint8_t * ) & scb - > scb_chain_addr , 4 , 2 ) ;
dma_bm_read ( scsi - > scb_addr + 24 , ( uint8_t * ) & scb - > block_count , 2 , 2 ) ;
dma_bm_read ( scsi - > scb_addr + 26 , ( uint8_t * ) & scb - > block_length , 2 , 2 ) ;
2020-03-24 01:00:28 +01:00
spock_log ( " SCB : \n "
" Command = %04x \n "
" Enable = %04x \n "
" LBA addr = %08x \n "
" System buffer addr = %08x \n "
" System buffer byte count = %08x \n "
" Terminate status block addr = %08x \n "
" SCB chain address = %08x \n "
" Block count = %04x \n "
2020-09-20 16:19:44 +02:00
" Block length = %04x \n "
" SCB id = %d \n " ,
2020-03-24 01:00:28 +01:00
scb - > command , scb - > enable , scb - > lba_addr ,
scb - > sge . sys_buf_addr , scb - > sge . sys_buf_byte_count ,
scb - > term_status_block_addr , scb - > scb_chain_addr ,
2020-09-20 16:19:44 +02:00
scb - > block_count , scb - > block_length , scsi - > scb_id ) ;
2020-03-24 01:00:28 +01:00
switch ( scb - > command & CMD_MASK ) {
case CMD_GET_COMPLETE_STATUS :
{
spock_log ( " Get Complete Status \n " ) ;
get_complete_stat_t * get_complete_stat = & scsi - > get_complete_stat ;
get_complete_stat - > scb_status = 0x201 ;
get_complete_stat - > retry_count = 0 ;
get_complete_stat - > residual_byte_count = 0 ;
get_complete_stat - > sg_list_element_addr = 0 ;
get_complete_stat - > device_dep_status_len = 0x0c ;
get_complete_stat - > cmd_status = scsi - > cmd_status < < 8 ;
get_complete_stat - > error = 0 ;
get_complete_stat - > reserved = 0 ;
get_complete_stat - > cache_info_status = 0 ;
get_complete_stat - > scb_addr = scsi - > scb_addr ;
2020-04-28 01:01:39 +02:00
dma_bm_write ( scb - > sge . sys_buf_addr , ( uint8_t * ) & get_complete_stat - > scb_status , 2 , 2 ) ;
dma_bm_write ( scb - > sge . sys_buf_addr + 2 , ( uint8_t * ) & get_complete_stat - > retry_count , 2 , 2 ) ;
dma_bm_write ( scb - > sge . sys_buf_addr + 4 , ( uint8_t * ) & get_complete_stat - > residual_byte_count , 4 , 2 ) ;
dma_bm_write ( scb - > sge . sys_buf_addr + 8 , ( uint8_t * ) & get_complete_stat - > sg_list_element_addr , 4 , 2 ) ;
dma_bm_write ( scb - > sge . sys_buf_addr + 12 , ( uint8_t * ) & get_complete_stat - > device_dep_status_len , 2 , 2 ) ;
dma_bm_write ( scb - > sge . sys_buf_addr + 14 , ( uint8_t * ) & get_complete_stat - > cmd_status , 2 , 2 ) ;
dma_bm_write ( scb - > sge . sys_buf_addr + 16 , ( uint8_t * ) & get_complete_stat - > error , 2 , 2 ) ;
dma_bm_write ( scb - > sge . sys_buf_addr + 18 , ( uint8_t * ) & get_complete_stat - > reserved , 2 , 2 ) ;
dma_bm_write ( scb - > sge . sys_buf_addr + 20 , ( uint8_t * ) & get_complete_stat - > cache_info_status , 2 , 2 ) ;
dma_bm_write ( scb - > sge . sys_buf_addr + 22 , ( uint8_t * ) & get_complete_stat - > scb_addr , 4 , 2 ) ;
2020-03-24 01:00:28 +01:00
scsi - > scb_state = 3 ;
}
break ;
case CMD_UNKNOWN_1C10 :
spock_log ( " Unknown 1C10 \n " ) ;
2020-04-28 01:01:39 +02:00
dma_bm_read ( scb - > sge . sys_buf_addr , scsi - > buf , scb - > sge . sys_buf_byte_count , 2 ) ;
2020-03-24 01:00:28 +01:00
scsi - > scb_state = 3 ;
break ;
case CMD_UNKNOWN_1C11 :
spock_log ( " Unknown 1C11 \n " ) ;
2020-04-28 01:01:39 +02:00
dma_bm_write ( scb - > sge . sys_buf_addr , scsi - > buf , scb - > sge . sys_buf_byte_count , 2 ) ;
2020-03-24 01:00:28 +01:00
scsi - > scb_state = 3 ;
break ;
case CMD_GET_POS_INFO :
{
spock_log ( " Get POS Info \n " ) ;
get_pos_info_t * get_pos_info = & scsi - > get_pos_info ;
get_pos_info - > pos = 0x8eff ;
2020-04-08 21:58:52 +02:00
get_pos_info - > pos1 = scsi - > pos_regs [ 3 ] | ( scsi - > pos_regs [ 2 ] < < 8 ) ;
get_pos_info - > pos2 = 0x0e | ( scsi - > pos_regs [ 4 ] < < 8 ) ;
get_pos_info - > pos3 = 1 < < 12 ;
2020-03-24 01:00:28 +01:00
get_pos_info - > pos4 = ( 7 < < 8 ) | 8 ;
get_pos_info - > pos5 = ( 16 < < 8 ) | scsi - > pacing ;
get_pos_info - > pos6 = ( 30 < < 8 ) | 1 ;
get_pos_info - > pos7 = 0 ;
get_pos_info - > pos8 = 0 ;
2020-04-28 01:01:39 +02:00
dma_bm_write ( scb - > sge . sys_buf_addr , ( uint8_t * ) & get_pos_info - > pos , 2 , 2 ) ;
dma_bm_write ( scb - > sge . sys_buf_addr + 2 , ( uint8_t * ) & get_pos_info - > pos1 , 2 , 2 ) ;
dma_bm_write ( scb - > sge . sys_buf_addr + 4 , ( uint8_t * ) & get_pos_info - > pos2 , 2 , 2 ) ;
dma_bm_write ( scb - > sge . sys_buf_addr + 6 , ( uint8_t * ) & get_pos_info - > pos3 , 2 , 2 ) ;
dma_bm_write ( scb - > sge . sys_buf_addr + 8 , ( uint8_t * ) & get_pos_info - > pos4 , 2 , 2 ) ;
dma_bm_write ( scb - > sge . sys_buf_addr + 10 , ( uint8_t * ) & get_pos_info - > pos5 , 2 , 2 ) ;
dma_bm_write ( scb - > sge . sys_buf_addr + 12 , ( uint8_t * ) & get_pos_info - > pos6 , 2 , 2 ) ;
dma_bm_write ( scb - > sge . sys_buf_addr + 14 , ( uint8_t * ) & get_pos_info - > pos7 , 2 , 2 ) ;
dma_bm_write ( scb - > sge . sys_buf_addr + 16 , ( uint8_t * ) & get_pos_info - > pos8 , 2 , 2 ) ;
2020-03-24 01:00:28 +01:00
scsi - > scb_state = 3 ;
}
break ;
case CMD_DEVICE_INQUIRY :
2020-09-20 16:19:44 +02:00
if ( scsi - > adapter_reset ) {
scsi - > cdb_id = scsi - > scb_id ;
} else {
scsi - > cdb_id = scsi - > dev_id [ scsi - > scb_id ] . phys_id ;
}
spock_log ( " Device Inquiry, ID=%d \n " , scsi - > cdb_id ) ;
2020-03-24 01:00:28 +01:00
scsi - > cdb [ 0 ] = GPCMD_INQUIRY ;
scsi - > cdb [ 1 ] = scsi - > dev_id [ scsi - > scb_id ] . lun_id < < 5 ; /*LUN*/
scsi - > cdb [ 2 ] = 0 ; /*Page code*/
scsi - > cdb [ 3 ] = 0 ;
scsi - > cdb [ 4 ] = scb - > sge . sys_buf_byte_count ; /*Allocation length*/
scsi - > cdb [ 5 ] = 0 ; /*Control*/
scsi - > cdb_len = 6 ;
scsi - > data_ptr = scb - > sge . sys_buf_addr ;
scsi - > data_len = scb - > sge . sys_buf_byte_count ;
scsi - > scsi_state = SCSI_STATE_SELECT ;
scsi - > scb_state = 2 ;
return ;
case CMD_SEND_OTHER_SCSI :
2020-09-20 16:19:44 +02:00
if ( scsi - > adapter_reset ) {
scsi - > cdb_id = scsi - > scb_id ;
} else {
scsi - > cdb_id = scsi - > dev_id [ scsi - > scb_id ] . phys_id ;
}
spock_log ( " Send Other SCSI, ID=%d \n " , scsi - > cdb_id ) ;
2020-04-28 01:01:39 +02:00
dma_bm_read ( scsi - > scb_addr + 0x18 , scsi - > cdb , 12 , 2 ) ;
2020-03-24 01:00:28 +01:00
scsi - > cdb [ 1 ] = ( scsi - > cdb [ 1 ] & 0x1f ) | ( scsi - > dev_id [ scsi - > scb_id ] . lun_id < < 5 ) ; /*Patch correct LUN into command*/
scsi - > cdb_len = ( scb - > lba_addr & 0xff ) ? ( scb - > lba_addr & 0xff ) : 6 ;
scsi - > scsi_state = SCSI_STATE_SELECT ;
scsi - > scb_state = 2 ;
return ;
case CMD_READ_DEVICE_CAPACITY :
2020-09-20 16:19:44 +02:00
if ( scsi - > adapter_reset )
scsi - > cdb_id = scsi - > scb_id ;
else
scsi - > cdb_id = scsi - > dev_id [ scsi - > scb_id ] . phys_id ;
spock_log ( " Device Capacity, ID=%d \n " , scsi - > cdb_id ) ;
2020-03-24 01:00:28 +01:00
scsi - > cdb [ 0 ] = GPCMD_READ_CDROM_CAPACITY ;
scsi - > cdb [ 1 ] = scsi - > dev_id [ scsi - > scb_id ] . lun_id < < 5 ; /*LUN*/
scsi - > cdb [ 2 ] = 0 ; /*LBA*/
scsi - > cdb [ 3 ] = 0 ;
scsi - > cdb [ 4 ] = 0 ;
scsi - > cdb [ 5 ] = 0 ;
scsi - > cdb [ 6 ] = 0 ; /*Reserved*/
scsi - > cdb [ 7 ] = 0 ;
scsi - > cdb [ 8 ] = 0 ;
scsi - > cdb [ 9 ] = 0 ; /*Control*/
scsi - > cdb_len = 10 ;
scsi - > scsi_state = SCSI_STATE_SELECT ;
scsi - > scb_state = 2 ;
return ;
case CMD_READ_DATA :
spock_log ( " Device Read Data \n " ) ;
scsi - > cdb [ 0 ] = GPCMD_READ_10 ;
scsi - > cdb [ 1 ] = scsi - > dev_id [ scsi - > scb_id ] . lun_id < < 5 ; /*LUN*/
scsi - > cdb [ 2 ] = ( scb - > lba_addr > > 24 ) & 0xff ; /*LBA*/
scsi - > cdb [ 3 ] = ( scb - > lba_addr > > 16 ) & 0xff ;
scsi - > cdb [ 4 ] = ( scb - > lba_addr > > 8 ) & 0xff ;
scsi - > cdb [ 5 ] = scb - > lba_addr & 0xff ;
scsi - > cdb [ 6 ] = 0 ; /*Reserved*/
scsi - > cdb [ 7 ] = ( scb - > block_count > > 8 ) & 0xff ;
scsi - > cdb [ 8 ] = scb - > block_count & 0xff ;
scsi - > cdb [ 9 ] = 0 ; /*Control*/
scsi - > cdb_len = 10 ;
scsi - > cdb_id = scsi - > dev_id [ scsi - > scb_id ] . phys_id ;
scsi - > scsi_state = SCSI_STATE_SELECT ;
scsi - > scb_state = 2 ;
return ;
case CMD_WRITE_DATA :
spock_log ( " Device Write Data \n " ) ;
scsi - > cdb [ 0 ] = GPCMD_WRITE_10 ;
scsi - > cdb [ 1 ] = scsi - > dev_id [ scsi - > scb_id ] . lun_id < < 5 ; /*LUN*/
scsi - > cdb [ 2 ] = ( scb - > lba_addr > > 24 ) & 0xff ; /*LBA*/
scsi - > cdb [ 3 ] = ( scb - > lba_addr > > 16 ) & 0xff ;
scsi - > cdb [ 4 ] = ( scb - > lba_addr > > 8 ) & 0xff ;
scsi - > cdb [ 5 ] = scb - > lba_addr & 0xff ;
scsi - > cdb [ 6 ] = 0 ; /*Reserved*/
scsi - > cdb [ 7 ] = ( scb - > block_count > > 8 ) & 0xff ;
scsi - > cdb [ 8 ] = scb - > block_count & 0xff ;
scsi - > cdb [ 9 ] = 0 ; /*Control*/
scsi - > cdb_len = 10 ;
scsi - > cdb_id = scsi - > dev_id [ scsi - > scb_id ] . phys_id ;
scsi - > scsi_state = SCSI_STATE_SELECT ;
scsi - > scb_state = 2 ;
return ;
case CMD_VERIFY :
spock_log ( " Device Verify \n " ) ;
scsi - > cdb [ 0 ] = GPCMD_VERIFY_10 ;
scsi - > cdb [ 1 ] = scsi - > dev_id [ scsi - > scb_id ] . lun_id < < 5 ; /*LUN*/
scsi - > cdb [ 2 ] = ( scb - > lba_addr > > 24 ) & 0xff ; /*LBA*/
scsi - > cdb [ 3 ] = ( scb - > lba_addr > > 16 ) & 0xff ;
scsi - > cdb [ 4 ] = ( scb - > lba_addr > > 8 ) & 0xff ;
scsi - > cdb [ 5 ] = scb - > lba_addr & 0xff ;
scsi - > cdb [ 6 ] = 0 ; /*Reserved*/
scsi - > cdb [ 7 ] = ( scb - > block_count > > 8 ) & 0xff ;
scsi - > cdb [ 8 ] = scb - > block_count & 0xff ;
scsi - > cdb [ 9 ] = 0 ; /*Control*/
scsi - > cdb_len = 10 ;
scsi - > cdb_id = scsi - > dev_id [ scsi - > scb_id ] . phys_id ;
scsi - > data_len = 0 ;
scsi - > scsi_state = SCSI_STATE_SELECT ;
scsi - > scb_state = 2 ;
return ;
case CMD_REQUEST_SENSE :
2020-09-20 16:19:44 +02:00
if ( scsi - > adapter_reset )
scsi - > cdb_id = scsi - > scb_id ;
else
scsi - > cdb_id = scsi - > dev_id [ scsi - > scb_id ] . phys_id ;
spock_log ( " Device Request Sense, ID=%d \n " , scsi - > cdb_id ) ;
2020-03-24 01:00:28 +01:00
scsi - > cdb [ 0 ] = GPCMD_REQUEST_SENSE ;
scsi - > cdb [ 1 ] = scsi - > dev_id [ scsi - > scb_id ] . lun_id < < 5 ; /*LUN*/
scsi - > cdb [ 2 ] = 0 ;
scsi - > cdb [ 3 ] = 0 ;
scsi - > cdb [ 4 ] = scb - > sge . sys_buf_byte_count ; /*Allocation length*/
scsi - > cdb [ 5 ] = 0 ;
scsi - > cdb_len = 6 ;
scsi - > scsi_state = SCSI_STATE_SELECT ;
scsi - > scb_state = 2 ;
return ;
}
break ;
case 2 : /* Wait */
2020-09-20 16:19:44 +02:00
if ( scsi - > scsi_state = = SCSI_STATE_IDLE & & scsi_device_present ( & scsi_devices [ scsi - > cdb_id ] ) ) {
2020-03-24 01:00:28 +01:00
if ( scsi - > last_status = = SCSI_STATUS_OK ) {
scsi - > scb_state = 3 ;
2020-09-20 16:19:44 +02:00
spock_log ( " Status is Good on device ID %d, timer = %i \n " , scsi - > cdb_id , scsi - > cmd_timer ) ;
2020-03-24 01:00:28 +01:00
} else if ( scsi - > last_status = = SCSI_STATUS_CHECK_CONDITION ) {
uint16_t term_stat_block_addr7 = ( 0xc < < 8 ) | 2 ;
uint16_t term_stat_block_addr8 = 0x20 ;
uint16_t term_stat_block_addrb = scsi - > scb_addr & 0xffff ;
uint16_t term_stat_block_addrc = scsi - > scb_addr > > 16 ;
spock_set_irq ( scsi , scsi - > scb_id , IRQ_TYPE_COMMAND_FAIL ) ;
scsi - > scb_state = 0 ;
spock_log ( " Status Check Condition on device ID %d \n " , scsi - > cdb_id ) ;
2020-04-28 01:01:39 +02:00
dma_bm_write ( scb - > term_status_block_addr + 0x7 * 2 , ( uint8_t * ) & term_stat_block_addr7 , 2 , 2 ) ;
dma_bm_write ( scb - > term_status_block_addr + 0x8 * 2 , ( uint8_t * ) & term_stat_block_addr8 , 2 , 2 ) ;
dma_bm_write ( scb - > term_status_block_addr + 0xb * 2 , ( uint8_t * ) & term_stat_block_addrb , 2 , 2 ) ;
dma_bm_write ( scb - > term_status_block_addr + 0xc * 2 , ( uint8_t * ) & term_stat_block_addrc , 2 , 2 ) ;
2020-03-24 01:00:28 +01:00
}
2020-09-20 16:19:44 +02:00
} else if ( scsi - > scsi_state = = SCSI_STATE_IDLE & & ! scsi_device_present ( & scsi_devices [ scsi - > cdb_id ] ) ) {
2020-03-24 01:00:28 +01:00
uint16_t term_stat_block_addr7 = ( 0xc < < 8 ) | 2 ;
uint16_t term_stat_block_addr8 = 0x10 ;
spock_set_irq ( scsi , scsi - > scb_id , IRQ_TYPE_COMMAND_FAIL ) ;
scsi - > scb_state = 0 ;
2020-04-28 01:01:39 +02:00
dma_bm_write ( scb - > term_status_block_addr + 0x7 * 2 , ( uint8_t * ) & term_stat_block_addr7 , 2 , 2 ) ;
dma_bm_write ( scb - > term_status_block_addr + 0x8 * 2 , ( uint8_t * ) & term_stat_block_addr8 , 2 , 2 ) ;
2020-03-24 01:00:28 +01:00
}
break ;
case 3 : /* Complete */
if ( scb - > enable & 1 ) {
scsi - > scb_state = 1 ;
scsi - > scb_addr = scb - > scb_chain_addr ;
spock_log ( " Next SCB - %08x \n " , scsi - > scb_addr ) ;
} else {
spock_set_irq ( scsi , scsi - > scb_id , IRQ_TYPE_SCB_COMPLETE ) ;
scsi - > scb_state = 0 ;
spock_log ( " Complete SCB \n " ) ;
}
break ;
}
} while ( scsi - > scb_state ! = old_scb_state ) ;
}
static void
spock_process_scsi ( spock_t * scsi , scb_t * scb )
{
int c ;
double p ;
scsi_device_t * sd ;
switch ( scsi - > scsi_state ) {
case SCSI_STATE_IDLE :
break ;
case SCSI_STATE_SELECT :
2020-09-20 16:19:44 +02:00
spock_log ( " Selecting ID %d \n " , scsi - > cdb_id ) ;
2020-03-24 01:00:28 +01:00
if ( ( scsi - > cdb_id ! = ( uint8_t ) - 1 ) & & scsi_device_present ( & scsi_devices [ scsi - > cdb_id ] ) ) {
scsi - > scsi_state = SCSI_STATE_SEND_COMMAND ;
spock_log ( " Device selected at ID %i \n " , scsi - > cdb_id ) ;
} else {
spock_log ( " Device selection failed at ID %i \n " , scsi - > cdb_id ) ;
2020-09-20 16:19:44 +02:00
scsi - > scsi_state = SCSI_STATE_IDLE ;
2020-03-24 01:00:28 +01:00
if ( ! scsi - > cmd_timer ) {
spock_log ( " Callback to reset \n " ) ;
scsi - > cmd_timer = 1 ;
}
spock_add_to_period ( scsi , 1 ) ;
}
break ;
case SCSI_STATE_SEND_COMMAND :
sd = & scsi_devices [ scsi - > cdb_id ] ;
memset ( scsi - > temp_cdb , 0x00 , 12 ) ;
if ( scsi - > cdb_len < 12 ) {
memcpy ( scsi - > temp_cdb , scsi - > cdb ,
scsi - > cdb_len ) ;
spock_add_to_period ( scsi , scsi - > cdb_len ) ;
} else {
memcpy ( scsi - > temp_cdb , scsi - > cdb ,
12 ) ;
spock_add_to_period ( scsi , 12 ) ;
}
scsi - > data_ptr = scb - > sge . sys_buf_addr ;
scsi - > data_len = scb - > sge . sys_buf_byte_count ;
2020-09-20 16:19:44 +02:00
if ( scb - > enable & 0x400 )
sd - > buffer_length = - 1 ;
else
sd - > buffer_length = spock_get_len ( scsi , scb ) ;
2020-03-24 01:00:28 +01:00
scsi_device_command_phase0 ( sd , scsi - > temp_cdb ) ;
2020-09-20 16:19:44 +02:00
spock_log ( " SCSI ID %i: Current CDB[0] = %02x, LUN = %i, data len = %i, max len = %i, phase val = %02x \n " , scsi - > cdb_id , scsi - > temp_cdb [ 0 ] , scsi - > temp_cdb [ 1 ] > > 5 , sd - > buffer_length , spock_get_len ( scsi , scb ) , sd - > phase ) ;
2020-03-24 01:00:28 +01:00
if ( sd - > phase ! = SCSI_PHASE_STATUS & & sd - > buffer_length > 0 ) {
p = scsi_device_get_callback ( sd ) ;
if ( p < = 0.0 )
spock_add_to_period ( scsi , sd - > buffer_length ) ;
else
scsi - > media_period + = p ;
if ( scb - > enable & ENABLE_PT ) {
int32_t buflen = sd - > buffer_length ;
int sg_pos = 0 ;
uint32_t DataTx = 0 ;
uint32_t Address ;
if ( scb - > sge . sys_buf_byte_count > 0 ) {
for ( c = 0 ; c < scsi - > data_len ; c + = 8 ) {
spock_rd_sge ( scsi , scsi - > data_ptr + c , & scb - > sge ) ;
Address = scb - > sge . sys_buf_addr ;
DataTx = MIN ( ( int ) scb - > sge . sys_buf_byte_count , buflen ) ;
if ( ( sd - > phase = = SCSI_PHASE_DATA_IN ) & & DataTx ) {
spock_log ( " Writing S/G segment %i: length %i, pointer %08X \n " , c , DataTx , Address ) ;
2020-04-28 01:01:39 +02:00
dma_bm_write ( Address , & sd - > sc - > temp_buffer [ sg_pos ] , DataTx , 2 ) ;
2020-03-24 01:00:28 +01:00
} else if ( ( sd - > phase = = SCSI_PHASE_DATA_OUT ) & & DataTx ) {
spock_log ( " Reading S/G segment %i: length %i, pointer %08X \n " , c , DataTx , Address ) ;
2020-04-28 01:01:39 +02:00
dma_bm_read ( Address , & sd - > sc - > temp_buffer [ sg_pos ] , DataTx , 2 ) ;
2020-03-24 01:00:28 +01:00
}
sg_pos + = scb - > sge . sys_buf_byte_count ;
buflen - = scb - > sge . sys_buf_byte_count ;
if ( buflen < 0 )
buflen = 0 ;
}
}
} else {
2020-09-20 16:19:44 +02:00
spock_log ( " Normal Transfer \n " ) ;
2020-03-24 01:00:28 +01:00
if ( sd - > phase = = SCSI_PHASE_DATA_IN ) {
2020-04-28 01:01:39 +02:00
dma_bm_write ( scsi - > data_ptr , sd - > sc - > temp_buffer , MIN ( sd - > buffer_length , ( int ) scsi - > data_len ) , 2 ) ;
2020-03-24 01:00:28 +01:00
} else if ( sd - > phase = = SCSI_PHASE_DATA_OUT )
2020-04-28 01:01:39 +02:00
dma_bm_read ( scsi - > data_ptr , sd - > sc - > temp_buffer , MIN ( sd - > buffer_length , ( int ) scsi - > data_len ) , 2 ) ;
2020-03-24 01:00:28 +01:00
}
scsi_device_command_phase1 ( sd ) ;
}
scsi - > last_status = sd - > status ;
scsi - > scsi_state = SCSI_STATE_END_PHASE ;
break ;
case SCSI_STATE_END_PHASE :
scsi - > scsi_state = SCSI_STATE_IDLE ;
2020-09-20 16:19:44 +02:00
spock_log ( " State to idle, cmd timer %d \n " , scsi - > cmd_timer ) ;
2020-03-24 01:00:28 +01:00
if ( ! scsi - > cmd_timer ) {
scsi - > cmd_timer = 1 ;
}
spock_add_to_period ( scsi , 1 ) ;
break ;
}
}
static void
spock_callback ( void * priv )
{
double period ;
spock_t * scsi = ( spock_t * ) priv ;
scb_t * scb = & scsi - > scb ;
scsi - > temp_period = 0 ;
scsi - > media_period = 0.0 ;
if ( scsi - > cmd_timer ) {
scsi - > cmd_timer - - ;
if ( ! scsi - > cmd_timer ) {
spock_execute_cmd ( scsi , scb ) ;
}
}
if ( scsi - > attention_wait & &
( scsi - > scb_state = = 0 | | ( scsi - > attention_pending & 0xf0 ) = = 0xe0 ) ) {
scsi - > attention_wait - - ;
if ( ! scsi - > attention_wait ) {
scsi - > attention = scsi - > attention_pending ;
scsi - > status & = ~ STATUS_BUSY ;
scsi - > cir [ 0 ] = scsi - > cir_pending [ 0 ] ;
scsi - > cir [ 1 ] = scsi - > cir_pending [ 1 ] ;
scsi - > cir [ 2 ] = scsi - > cir_pending [ 2 ] ;
scsi - > cir [ 3 ] = scsi - > cir_pending [ 3 ] ;
scsi - > cir_status = 0 ;
switch ( scsi - > attention > > 4 ) {
case 1 : /*Immediate command*/
scsi - > cmd_status = 0x0a ;
scsi - > command = scsi - > cir [ 0 ] | ( scsi - > cir [ 1 ] < < 8 ) | ( scsi - > cir [ 2 ] < < 16 ) | ( scsi - > cir [ 3 ] < < 24 ) ;
switch ( scsi - > command & CMD_MASK ) {
case CMD_ASSIGN :
case CMD_DMA_PACING_CONTROL :
case CMD_FEATURE_CONTROL :
case CMD_INVALID_412 :
case CMD_RESET :
spock_process_imm_cmd ( scsi ) ;
break ;
}
break ;
case 3 : case 4 : case 0x0f : /*Start SCB*/
scsi - > cmd_status = 1 ;
scsi - > scb_addr = scsi - > cir [ 0 ] | ( scsi - > cir [ 1 ] < < 8 ) | ( scsi - > cir [ 2 ] < < 16 ) | ( scsi - > cir [ 3 ] < < 24 ) ;
scsi - > scb_id = scsi - > attention & 0x0f ;
scsi - > cmd_timer = SPOCK_TIME * 2 ;
2020-09-20 16:19:44 +02:00
spock_log ( " Start SCB at ID = %d \n " , scsi - > scb_id ) ;
2020-03-24 01:00:28 +01:00
scsi - > scb_state = 1 ;
break ;
case 5 : /*Invalid*/
case 0x0a : /*Invalid*/
scsi - > in_invalid = 1 ;
scsi - > cmd_timer = SPOCK_TIME * 2 ;
break ;
case 0x0e : /*EOI*/
scsi - > irq_status = 0 ;
spock_clear_irq ( scsi , scsi - > attention & 0xf ) ;
break ;
}
}
}
spock_process_scsi ( scsi , scb ) ;
period = 0.2 * ( ( double ) scsi - > temp_period ) ;
timer_on ( & scsi - > callback_timer , ( scsi - > media_period + period + 10.0 ) , 0 ) ;
spock_log ( " Temporary period: %lf us (% " PRIi64 " periods) \n " , scsi - > callback_timer . period , scsi - > temp_period ) ;
}
static void
spock_mca_write ( int port , uint8_t val , void * priv )
{
spock_t * scsi = ( spock_t * ) priv ;
if ( port < 0x102 )
return ;
io_removehandler ( ( ( ( scsi - > pos_regs [ 2 ] > > 1 ) & 7 ) * 8 ) + 0x3540 , 0x0008 , spock_read , spock_readw , NULL , spock_write , spock_writew , NULL , scsi ) ;
mem_mapping_disable ( & scsi - > bios_rom . mapping ) ;
scsi - > pos_regs [ port & 7 ] = val ;
2020-09-20 16:19:44 +02:00
scsi - > adapter_id = ( scsi - > pos_regs [ 3 ] & 0xe0 ) > > 5 ;
2020-03-24 01:00:28 +01:00
if ( scsi - > pos_regs [ 2 ] & 1 ) {
io_sethandler ( ( ( ( scsi - > pos_regs [ 2 ] > > 1 ) & 7 ) * 8 ) + 0x3540 , 0x0008 , spock_read , spock_readw , NULL , spock_write , spock_writew , NULL , scsi ) ;
if ( ( scsi - > pos_regs [ 2 ] > > 4 ) = = 0x0f )
mem_mapping_disable ( & scsi - > bios_rom . mapping ) ;
else {
mem_mapping_set_addr ( & scsi - > bios_rom . mapping , ( ( scsi - > pos_regs [ 2 ] > > 4 ) * 0x2000 ) + 0xc0000 , 0x8000 ) ;
}
}
}
static uint8_t
spock_mca_read ( int port , void * priv )
{
spock_t * scsi = ( spock_t * ) priv ;
2020-09-20 16:19:44 +02:00
2020-03-24 01:00:28 +01:00
return scsi - > pos_regs [ port & 7 ] ;
}
static uint8_t
spock_mca_feedb ( void * priv )
{
spock_t * scsi = ( spock_t * ) priv ;
return ( scsi - > pos_regs [ 2 ] & 0x01 ) ;
}
static void
spock_mca_reset ( void * priv )
{
spock_t * scsi = ( spock_t * ) priv ;
int i ;
scsi - > in_reset = 2 ;
scsi - > cmd_timer = SPOCK_TIME * 50 ;
scsi - > status = STATUS_BUSY ;
scsi - > scsi_state = SCSI_STATE_IDLE ;
scsi - > scb_state = 0 ;
scsi - > in_invalid = 0 ;
scsi - > attention_wait = 0 ;
scsi - > basic_ctrl = 0 ;
/* Reset all devices on controller reset. */
2020-09-20 16:19:44 +02:00
for ( i = 0 ; i < 8 ; i + + )
scsi_device_reset ( & scsi_devices [ i ] ) ;
scsi - > adapter_reset = 0 ;
2020-03-24 01:00:28 +01:00
}
static void *
spock_init ( const device_t * info )
{
int c ;
spock_t * scsi = malloc ( sizeof ( spock_t ) ) ;
memset ( scsi , 0x00 , sizeof ( spock_t ) ) ;
scsi - > irq = 14 ;
scsi - > bios_ver = device_get_config_int ( " bios_ver " ) ;
if ( scsi - > bios_ver )
rom_init_interleaved ( & scsi - > bios_rom , SPOCK_U68_1991_ROM , SPOCK_U69_1991_ROM ,
0xc8000 , 0x8000 , 0x7fff , 0x4000 , MEM_MAPPING_EXTERNAL ) ;
else
rom_init_interleaved ( & scsi - > bios_rom , SPOCK_U68_1990_ROM , SPOCK_U69_1990_ROM ,
0xc8000 , 0x8000 , 0x7fff , 0x4000 , MEM_MAPPING_EXTERNAL ) ;
mem_mapping_disable ( & scsi - > bios_rom . mapping ) ;
scsi - > pos_regs [ 0 ] = 0xff ;
scsi - > pos_regs [ 1 ] = 0x8e ;
2020-03-25 00:49:25 +01:00
mca_add ( spock_mca_read , spock_mca_write , spock_mca_feedb , spock_mca_reset , scsi ) ;
2020-03-24 01:00:28 +01:00
scsi - > in_reset = 2 ;
scsi - > cmd_timer = SPOCK_TIME * 50 ;
scsi - > status = STATUS_BUSY ;
2020-09-20 16:19:44 +02:00
for ( c = 0 ; c < ( SCSI_ID_MAX - 1 ) ; c + + ) {
2020-03-24 01:00:28 +01:00
scsi - > dev_id [ c ] . phys_id = - 1 ;
2020-09-20 16:19:44 +02:00
}
scsi - > dev_id [ SCSI_ID_MAX - 1 ] . phys_id = scsi - > adapter_id ;
2020-03-24 01:00:28 +01:00
timer_add ( & scsi - > callback_timer , spock_callback , scsi , 1 ) ;
scsi - > callback_timer . period = 10.0 ;
timer_set_delay_u64 ( & scsi - > callback_timer , ( uint64_t ) ( scsi - > callback_timer . period * ( ( double ) TIMER_USEC ) ) ) ;
return scsi ;
}
static void
spock_close ( void * p )
{
spock_t * scsi = ( spock_t * ) p ;
if ( scsi ) {
free ( scsi ) ;
scsi = NULL ;
}
}
static int
spock_available ( void )
{
return rom_present ( SPOCK_U68_1991_ROM ) & & rom_present ( SPOCK_U69_1991_ROM ) & &
rom_present ( SPOCK_U68_1990_ROM ) & & rom_present ( SPOCK_U69_1990_ROM ) ;
}
static const device_config_t spock_rom_config [ ] = {
{
" bios_ver " , " BIOS Version " , CONFIG_SELECTION , " " , 1 ,
{
{
" 1991 BIOS (>1GB) " , 1
} ,
{
" 1990 BIOS " , 0
} ,
{
" "
}
} ,
} ,
{
" " , " " , - 1
}
} ;
const device_t spock_device =
{
" IBM PS/2 SCSI Adapter (Spock) " ,
DEVICE_MCA ,
0 ,
spock_init , spock_close , NULL ,
spock_available ,
NULL , NULL ,
spock_rom_config
} ;