2017-08-22 21:28:22 +02:00
/*
2022-11-13 16:37:58 -05: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 .
2017-08-22 21:28:22 +02:00
*
2022-11-13 16:37:58 -05:00
* This file is part of the 86 Box distribution .
2017-08-22 21:28:22 +02:00
*
2022-11-13 16:37:58 -05:00
* The generic SCSI device command handler .
2017-08-22 21:28:22 +02:00
*
2020-03-25 00:46:02 +02:00
*
2017-08-22 21:28:22 +02:00
*
2022-11-13 16:37:58 -05:00
* Authors : Miran Grca , < mgrca8 @ gmail . com >
* Fred N . van Kempen , < decwiz @ yahoo . com >
2017-10-17 01:59:09 -04:00
*
2022-11-13 16:37:58 -05:00
* Copyright 2016 - 2018 Miran Grca .
* Copyright 2017 - 2018 Fred N . van Kempen .
2017-08-22 21:28:22 +02:00
*/
2025-01-20 19:55:18 +01:00
# include <inttypes.h>
2017-09-25 04:31:20 -04:00
# include <stdio.h>
# include <stdint.h>
# include <string.h>
2025-01-20 19:55:18 +01:00
# include <stdlib.h>
# include <stdarg.h>
2017-09-25 04:31:20 -04:00
# include <wchar.h>
2025-01-20 19:55:18 +01:00
# define HAVE_STDARG_H
2020-03-29 14:24:42 +02:00
# include <86box/86box.h>
# include <86box/device.h>
# include <86box/hdd.h>
2023-10-28 22:00:23 +02:00
# include <86box/hdc_ide.h>
2020-03-29 14:24:42 +02:00
# include <86box/scsi.h>
# include <86box/scsi_device.h>
2023-06-09 23:46:54 -04:00
# include <86box/plat_unused.h>
2017-08-22 05:45:07 +02:00
2022-09-18 17:17:15 -04:00
scsi_device_t scsi_devices [ SCSI_BUS_MAX ] [ SCSI_ID_MAX ] ;
2025-01-20 19:55:18 +01:00
int scsi_command_length [ 8 ] = { 6 , 10 , 10 , 6 , 16 , 12 , 10 , 6 } ;
2022-09-18 17:17:15 -04:00
uint8_t scsi_null_device_sense [ 18 ] = { 0x70 , 0 , SENSE_ILLEGAL_REQUEST , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , ASC_INV_LUN , 0 , 0 , 0 , 0 , 0 } ;
2017-08-22 05:45:07 +02:00
2025-01-20 19:55:18 +01:00
# define SET_BUS_STATE(scsi_bus, state) scsi_bus->bus_out = (scsi_bus->bus_out & ~(SCSI_PHASE_MESSAGE_IN)) | (state & (SCSI_PHASE_MESSAGE_IN))
# ifdef ENABLE_SCSI_DEVICE_LOG
int scsi_device_do_log = ENABLE_SCSI_DEVICE_LOG ;
static void
scsi_device_log ( const char * fmt , . . . )
{
va_list ap ;
if ( scsi_device_do_log ) {
va_start ( ap , fmt ) ;
pclog_ex ( fmt , ap ) ;
va_end ( ap ) ;
}
}
# else
# define scsi_device_log(fmt, ...)
# endif
2018-07-15 01:41:53 +02:00
static uint8_t
2018-10-10 22:33:24 +02:00
scsi_device_target_command ( scsi_device_t * dev , uint8_t * cdb )
2017-08-22 05:45:07 +02:00
{
2018-10-30 13:32:25 +01:00
if ( dev - > command ) {
2022-09-18 17:17:15 -04:00
dev - > command ( dev - > sc , cdb ) ;
2018-10-30 13:32:25 +01:00
2023-10-28 22:00:23 +02:00
if ( dev - > sc - > tf - > status & ERR_STAT )
2022-09-18 17:17:15 -04:00
return SCSI_STATUS_CHECK_CONDITION ;
else
return SCSI_STATUS_OK ;
2018-10-10 22:33:24 +02:00
} else
2022-09-18 17:17:15 -04:00
return SCSI_STATUS_CHECK_CONDITION ;
2017-08-22 05:45:07 +02:00
}
Added the IBM 5161 ISA expansion for PC and XT;
Cleaned up the parallel port emulation, added IRQ support, and made enabling/disabling per port;
Added the Award 430NX and the Intel Classic/PCI (Alfredo, 420TX);
Finished the 586MC1;
Added 8087 emulation;
Moved Cyrix 6x86'es to the Dev branch;
Sanitized/cleaned up memregs.c/h and intel.c/h;
Split the chipsets from machines and sanitized Port 92 emulation;
Added support for the 15bpp mode to the Compaq ATI 28800;
Moved the MR 386DX and 486 machines to the Dev branch;
Ported the new dynamic recompiler from PCem, but it remains in Dev branch until after v2.00;
Ported the new timer code from PCem;
Cleaned up the CPU table of unused stuff and better optimized its structure;
Ported the Open-XT and Open-AT from VARCem, the Open-AT is in the Dev branch;
Ported the XT MFM controller rewrite and adding of more controllers (incl. two RLL ones), from VARCem;
Added the AHA-1540A and the BusTek BT-542B;
Moved the Sumo SCSI-AT to the Dev branch;
Minor IDE, FDC, and floppy drive code clean-ups;
Made NCR 5380/53C400-based cards' BIOS address configurable;
Got rid of the legacy romset variable;
Unified (video) buffer and buffer32 into one and make the unified buffer 32-bit;
Added the Amstead PPC512 per PCem patch by John Elliott;
Switched memory mapping granularity from 16k to 4k (less than 1k not possible due to internal pages);
Rewrote the CL-GD 54xx blitter, fixes Win-OS/2 on the 54x6 among other thing;
Added the Image Manager 1024 and Professional Graphics Controller per PCem patch by John Elliott and work done on VARCem;
Added Headland HT-216, GC-205 and Video 7 VGA 1024i emulation based on PCem commit;
Implemented the fuction keys for the Toshiba T1000/T1200/T3100 enhancement;
Amstrad MegaPC does now works correctly with non-internal graphics card;
The SLiRP code no longer casts a packed struct type to a non-packed struct type;
The Xi8088 and PB410a no longer hang on 86Box when PS/2 mouse is not present;
The S3 Virge on BeOS is no longer broken (was broken by build #1591);
OS/2 2.0 build 6.167 now sees key presses again;
Xi8088 now work on CGA again;
86F images converted from either the old or new variants of the HxC MFM format now work correctly;
Hardware interrupts with a vector of 0xFF are now handled correctly;
OPTi 495SX boards no longer incorrectly have 64 MB maximum RAM when 32 MB is correct;
Fixed VNC keyboard input bugs;
Fixed AT RTC periodic interrupt - Chicago 58s / 73f / 73g / 81 MIDI play no longer hangs with the build's own VTD driver;
Fixed mouse polling with internal mice - Amstrad and Olivetti mice now work correctly;
Triones ATAPI DMA driver now correctly reads a file at the end of a CD image with a sectors number not divisible by 4;
Compaq Portable now works with all graphics cards;
Fixed various MDSI Genius bugs;
Added segment limit checks and improved page fault checks for several CPU instructions - Memphis 15xx WINSETUP and Chicago 58s WINDISK.CPL no longer issue a GPF, and some S3 drivers that used to have glitches, now work correctly;
Further improved the 808x emulation, also fixes the noticably choppy sound when using 808x CPU's, also fixes #355;
OS/2 installer no logner locks up on splash screen on PS/2 Model 70 and 80, fixes #400.
Fixed several Amstead bugs, GEM no longer crashes on the Amstrad 1640, fixes #391.
Ported John Elliott's Amstrad fixes and improvement from PCem, and fixed the default language so it's correctly Engliish, fixes #278, fixes #389.
Fixed a minor IDE timing bug, fixes #388.
Fixed Toshiba T1000 RAM issues, fixes #379.
Fixed EGA/(S)VGA overscan border handling, fixes #378;
Got rid of the now long useless IDE channel 2 auto-removal, fixes #370;
Fixed the BIOS files used by the AMSTRAD PC1512, fixes #366;
Ported the Unicode CD image file name fix from VARCem, fixes #365;
Fixed high density floppy disks on the Xi8088, fixes #359;
Fixed some bugs in the Hercules emulation, fixes #346, fixes #358;
Fixed the SCSI hard disk mode sense pages, fixes #356;
Removed the AMI Unknown 386SX because of impossibility to identify the chipset, closes #349;
Fixed bugs in the serial mouse emulation, fixes #344;
Compiled 86Box binaries now include all the required .DLL's, fixes #341;
Made some combo boxes in the Settings dialog slightly wider, fixes #276.
2019-09-20 14:02:30 +02:00
double
2018-10-30 13:32:25 +01:00
scsi_device_get_callback ( scsi_device_t * dev )
2018-03-07 20:06:08 +01:00
{
2018-10-30 13:32:25 +01:00
if ( dev - > sc )
2022-09-18 17:17:15 -04:00
return dev - > sc - > callback ;
2018-10-10 22:33:24 +02:00
else
2022-09-18 17:17:15 -04:00
return - 1.0 ;
2018-03-07 20:06:08 +01:00
}
2018-10-30 13:32:25 +01:00
uint8_t *
scsi_device_sense ( scsi_device_t * dev )
2017-08-22 05:45:07 +02:00
{
2018-10-30 13:32:25 +01:00
if ( dev - > sc )
2022-09-18 17:17:15 -04:00
return dev - > sc - > sense ;
2018-10-10 22:33:24 +02:00
else
2022-09-18 17:17:15 -04:00
return scsi_null_device_sense ;
2017-08-22 05:45:07 +02:00
}
2018-10-30 13:32:25 +01:00
void
scsi_device_request_sense ( scsi_device_t * dev , uint8_t * buffer , uint8_t alloc_length )
2017-08-22 21:28:22 +02:00
{
2018-10-10 22:33:24 +02:00
if ( dev - > request_sense )
2022-09-18 17:17:15 -04:00
dev - > request_sense ( dev - > sc , buffer , alloc_length ) ;
2018-10-10 22:33:24 +02:00
else
2022-09-18 17:17:15 -04:00
memcpy ( buffer , scsi_null_device_sense , alloc_length ) ;
2017-08-22 21:28:22 +02:00
}
2018-10-30 13:32:25 +01:00
void
scsi_device_reset ( scsi_device_t * dev )
2017-08-22 05:45:07 +02:00
{
2018-10-10 22:33:24 +02:00
if ( dev - > reset )
2022-09-18 17:17:15 -04:00
dev - > reset ( dev - > sc ) ;
2018-04-25 23:51:13 +02:00
}
2018-10-30 13:32:25 +01:00
int
scsi_device_present ( scsi_device_t * dev )
2017-08-22 05:45:07 +02:00
{
2018-10-10 22:33:24 +02:00
if ( dev - > type = = SCSI_NONE )
2022-09-18 17:17:15 -04:00
return 0 ;
2018-10-10 22:33:24 +02:00
else
2022-09-18 17:17:15 -04:00
return 1 ;
2017-08-22 05:45:07 +02:00
}
2018-10-30 13:32:25 +01:00
int
scsi_device_valid ( scsi_device_t * dev )
2017-08-22 05:45:07 +02:00
{
2018-10-30 13:32:25 +01:00
if ( dev - > sc )
2022-09-18 17:17:15 -04:00
return 1 ;
2018-10-10 23:12:30 +02:00
else
2022-09-18 17:17:15 -04:00
return 0 ;
2017-08-22 05:45:07 +02:00
}
2018-10-30 13:32:25 +01:00
int
2023-06-09 23:46:54 -04:00
scsi_device_cdb_length ( UNUSED ( scsi_device_t * dev ) )
2017-08-22 05:45:07 +02:00
{
2018-07-15 01:41:53 +02:00
/* Right now, it's 12 for all devices. */
return 12 ;
2017-08-22 05:45:07 +02:00
}
2018-10-30 13:32:25 +01:00
void
scsi_device_command_phase0 ( scsi_device_t * dev , uint8_t * cdb )
2017-08-22 05:45:07 +02:00
{
2018-10-30 13:32:25 +01:00
if ( ! dev - > sc ) {
2022-09-18 17:17:15 -04:00
dev - > phase = SCSI_PHASE_STATUS ;
dev - > status = SCSI_STATUS_CHECK_CONDITION ;
return ;
2017-08-22 05:45:07 +02:00
}
/* Finally, execute the SCSI command immediately and get the transfer length. */
2022-09-18 17:17:15 -04:00
dev - > phase = SCSI_PHASE_COMMAND ;
2018-10-10 22:33:24 +02:00
dev - > status = scsi_device_target_command ( dev , cdb ) ;
2018-10-31 12:23:49 +01:00
}
void
scsi_device_command_stop ( scsi_device_t * dev )
{
if ( dev - > command_stop ) {
2022-09-18 17:17:15 -04:00
dev - > command_stop ( dev - > sc ) ;
dev - > status = SCSI_STATUS_OK ;
2017-08-22 05:45:07 +02:00
}
2017-08-22 02:13:45 -04:00
}
2017-10-08 05:04:38 +02:00
2018-10-30 13:32:25 +01:00
void
scsi_device_command_phase1 ( scsi_device_t * dev )
2017-10-08 05:04:38 +02:00
{
2018-10-30 13:32:25 +01:00
if ( ! dev - > sc )
2022-09-18 17:17:15 -04:00
return ;
2018-07-15 01:41:53 +02:00
/* Call the second phase. */
2018-10-31 12:23:49 +01:00
if ( dev - > phase = = SCSI_PHASE_DATA_OUT ) {
2022-09-18 17:17:15 -04:00
if ( dev - > phase_data_out )
dev - > phase_data_out ( dev - > sc ) ;
2018-10-31 12:23:49 +01:00
} else
2022-09-18 17:17:15 -04:00
scsi_device_command_stop ( dev ) ;
2018-10-30 13:32:25 +01:00
2023-10-28 22:00:23 +02:00
if ( dev - > sc - > tf - > status & ERR_STAT )
2022-09-18 17:17:15 -04:00
dev - > status = SCSI_STATUS_CHECK_CONDITION ;
2018-10-31 12:23:49 +01:00
else
2022-09-18 17:17:15 -04:00
dev - > status = SCSI_STATUS_OK ;
2018-10-30 13:32:25 +01:00
}
2021-03-23 06:32:18 +01:00
/* When LUN is FF, there has been no IDENTIFY message, otherwise
there has been one . */
void
scsi_device_identify ( scsi_device_t * dev , uint8_t lun )
{
if ( ( dev = = NULL ) | | ( dev - > type = = SCSI_NONE ) | | ! dev - > sc )
2022-09-18 17:17:15 -04:00
return ;
2021-03-23 06:32:18 +01:00
dev - > sc - > cur_lun = lun ;
/* TODO: This should return a value, should IDENTIFY fail due to a
2022-09-18 17:17:15 -04:00
a LUN not supported by the target . */
2021-03-23 06:32:18 +01:00
}
2018-10-30 13:32:25 +01:00
void
scsi_device_close_all ( void )
2017-10-14 07:03:19 +02:00
{
2018-10-30 13:32:25 +01:00
scsi_device_t * dev ;
2023-05-29 01:30:51 -04:00
for ( uint8_t i = 0 ; i < SCSI_BUS_MAX ; i + + ) {
for ( uint8_t j = 0 ; j < SCSI_ID_MAX ; j + + ) {
2022-09-18 17:17:15 -04:00
dev = & ( scsi_devices [ i ] [ j ] ) ;
if ( dev - > command_stop & & dev - > sc )
dev - > command_stop ( dev - > sc ) ;
}
2018-10-30 13:32:25 +01:00
}
2017-10-14 07:03:19 +02:00
}
2020-06-14 21:59:45 +02:00
void
scsi_device_init ( void )
{
scsi_device_t * dev ;
2023-05-29 01:30:51 -04:00
for ( uint8_t i = 0 ; i < SCSI_BUS_MAX ; i + + ) {
for ( uint8_t j = 0 ; j < SCSI_ID_MAX ; j + + ) {
2022-09-18 17:17:15 -04:00
dev = & ( scsi_devices [ i ] [ j ] ) ;
2020-06-14 21:59:45 +02:00
2022-09-18 17:17:15 -04:00
memset ( dev , 0 , sizeof ( scsi_device_t ) ) ;
dev - > type = SCSI_NONE ;
}
2020-06-14 21:59:45 +02:00
}
}
2025-01-20 19:55:18 +01:00
int
scsi_device_get_id ( uint8_t data )
{
for ( uint8_t c = 0 ; c < SCSI_ID_MAX ; c + + ) {
if ( data & ( 1 < < c ) )
return c ;
}
return - 1 ;
}
static int
scsi_device_get_msg ( uint8_t * msgp , int len )
{
uint8_t msg = msgp [ 0 ] ;
if ( ( msg = = 0 ) | | ( ( msg > = 0x02 ) & & ( msg < = 0x1f ) ) | | ( msg > = 0x80 ) )
return 1 ;
if ( ( msg > = 0x20 ) & & ( msg < = 0x2f ) )
return 2 ;
if ( len < 2 )
return 3 ;
return msgp [ 1 ] ;
}
int
scsi_bus_read ( scsi_bus_t * scsi_bus )
{
scsi_device_t * dev ;
int phase ;
/*Wait processes to handle bus requests*/
if ( scsi_bus - > clear_req ) {
scsi_bus - > clear_req - - ;
if ( ! scsi_bus - > clear_req ) {
scsi_device_log ( " Prelude to command data \n " ) ;
SET_BUS_STATE ( scsi_bus , scsi_bus - > bus_phase ) ;
scsi_bus - > bus_out | = BUS_REQ ;
}
}
if ( scsi_bus - > wait_data ) {
scsi_bus - > wait_data - - ;
if ( ! scsi_bus - > wait_data ) {
dev = & scsi_devices [ scsi_bus - > bus_device ] [ scsi_bus - > target_id ] ;
SET_BUS_STATE ( scsi_bus , scsi_bus - > bus_phase ) ;
phase = scsi_bus - > bus_out & SCSI_PHASE_MESSAGE_IN ;
switch ( phase ) {
case SCSI_PHASE_DATA_IN :
scsi_device_log ( " DataIn. \n " ) ;
scsi_bus - > state = STATE_DATAIN ;
if ( ( dev - > sc ! = NULL ) & & ( dev - > sc - > temp_buffer ! = NULL ) )
scsi_bus - > data = dev - > sc - > temp_buffer [ scsi_bus - > data_pos + + ] ;
scsi_bus - > bus_out = ( scsi_bus - > bus_out & ~ BUS_DATAMASK ) | BUS_SETDATA ( scsi_bus - > data ) | BUS_DBP ;
break ;
case SCSI_PHASE_DATA_OUT :
if ( scsi_bus - > bus_phase & BUS_IDLE ) {
scsi_device_log ( " Bus Idle. \n " ) ;
scsi_bus - > state = STATE_IDLE ;
scsi_bus - > bus_out & = ~ BUS_BSY ;
scsi_bus - > timer ( scsi_bus - > priv , 0.0 ) ;
} else {
scsi_device_log ( " DataOut. \n " ) ;
scsi_bus - > state = STATE_DATAOUT ;
}
break ;
case SCSI_PHASE_STATUS :
scsi_device_log ( " Status. \n " ) ;
scsi_bus - > bus_out | = BUS_REQ ;
scsi_bus - > state = STATE_STATUS ;
scsi_bus - > bus_out = ( scsi_bus - > bus_out & ~ BUS_DATAMASK ) | BUS_SETDATA ( dev - > status ) | BUS_DBP ;
break ;
case SCSI_PHASE_MESSAGE_IN :
scsi_device_log ( " Message In. \n " ) ;
scsi_bus - > state = STATE_MESSAGEIN ;
scsi_bus - > bus_out = ( scsi_bus - > bus_out & ~ BUS_DATAMASK ) | BUS_SETDATA ( 0 ) | BUS_DBP ;
break ;
case SCSI_PHASE_MESSAGE_OUT :
scsi_device_log ( " Message Out. \n " ) ;
scsi_bus - > bus_out | = BUS_REQ ;
scsi_bus - > state = STATE_MESSAGEOUT ;
scsi_bus - > bus_out = ( scsi_bus - > bus_out & ~ BUS_DATAMASK ) | BUS_SETDATA ( scsi_bus - > target_id > > 5 ) | BUS_DBP ;
break ;
default :
break ;
}
}
}
if ( scsi_bus - > wait_complete ) {
scsi_bus - > wait_complete - - ;
if ( ! scsi_bus - > wait_complete )
scsi_bus - > bus_out | = BUS_REQ ;
}
return scsi_bus - > bus_out ;
}
void
scsi_bus_update ( scsi_bus_t * scsi_bus , int bus )
{
scsi_device_t * dev = & scsi_devices [ scsi_bus - > bus_device ] [ scsi_bus - > target_id ] ;
double p ;
uint8_t sel_data ;
int msglen ;
/*Start the SCSI command layer, which will also make the timings*/
if ( bus & BUS_ARB )
scsi_bus - > state = STATE_IDLE ;
scsi_device_log ( " State = %i \n " , scsi_bus - > state ) ;
switch ( scsi_bus - > state ) {
case STATE_IDLE :
scsi_bus - > clear_req = scsi_bus - > wait_data = scsi_bus - > wait_complete = 0 ;
if ( ( bus & BUS_SEL ) & & ! ( bus & BUS_BSY ) ) {
sel_data = BUS_GETDATA ( bus ) ;
scsi_bus - > target_id = scsi_device_get_id ( sel_data ) ;
/*Once the device has been found and selected, mark it as busy*/
if ( ( scsi_bus - > target_id ! = ( uint8_t ) - 1 ) & & scsi_device_present ( & scsi_devices [ scsi_bus - > bus_device ] [ scsi_bus - > target_id ] ) ) {
scsi_bus - > bus_out | = BUS_BSY ;
scsi_bus - > state = STATE_SELECT ;
scsi_device_log ( " Select - target ID = %i, moving to state = %d. \n " , scsi_bus - > target_id , scsi_bus - > state ) ;
} else {
scsi_device_log ( " Device not found at ID %i, Current Bus BSY=%02x \n " , scsi_bus - > target_id , scsi_bus - > bus_out ) ;
scsi_bus - > bus_out = 0 ;
}
}
break ;
case STATE_SELECT :
if ( ! ( bus & BUS_SEL ) ) {
if ( ! ( bus & BUS_ATN ) ) {
if ( ( scsi_bus - > target_id ! = ( uint8_t ) - 1 ) & & scsi_device_present ( & scsi_devices [ scsi_bus - > bus_device ] [ scsi_bus - > target_id ] ) ) {
scsi_device_log ( " Device found at ID %i, Current Bus BSY=%02x \n " , scsi_bus - > target_id , scsi_bus - > bus_out ) ;
scsi_bus - > state = STATE_COMMAND ;
scsi_bus - > bus_out = BUS_BSY | BUS_REQ ;
scsi_bus - > command_pos = 0 ;
SET_BUS_STATE ( scsi_bus , SCSI_PHASE_COMMAND ) ;
} else {
scsi_device_log ( " Device not found at ID %i again. \n " , scsi_bus - > target_id ) ;
scsi_bus - > state = STATE_IDLE ;
scsi_bus - > bus_out = 0 ;
}
} else {
scsi_device_log ( " Set to SCSI Message Out \n " ) ;
scsi_bus - > bus_phase = SCSI_PHASE_MESSAGE_OUT ;
scsi_bus - > wait_data = 4 ;
scsi_bus - > msgout_pos = 0 ;
scsi_bus - > is_msgout = 1 ;
}
}
break ;
case STATE_COMMAND :
if ( ( bus & BUS_ACK ) & & ! ( scsi_bus - > bus_in & BUS_ACK ) ) {
/*Write command byte to the output data register*/
scsi_bus - > command [ scsi_bus - > command_pos + + ] = BUS_GETDATA ( bus ) ;
scsi_bus - > clear_req = 3 ;
scsi_bus - > bus_phase = scsi_bus - > bus_out & SCSI_PHASE_MESSAGE_IN ;
scsi_bus - > bus_out & = ~ BUS_REQ ;
scsi_device_log ( " Command pos=%i, output data=%02x \n " , scsi_bus - > command_pos , BUS_GETDATA ( bus ) ) ;
if ( scsi_bus - > command_pos = = scsi_command_length [ ( scsi_bus - > command [ 0 ] > > 5 ) & 7 ] ) {
if ( scsi_bus - > is_msgout ) {
scsi_bus - > is_msgout = 0 ;
#if 0
scsi_bus - > command [ 1 ] = ( scsi_bus - > command [ 1 ] & 0x1f ) | ( scsi_bus - > msglun < < 5 ) ;
# endif
}
/*Reset data position to default*/
scsi_bus - > data_pos = 0 ;
dev = & scsi_devices [ scsi_bus - > bus_device ] [ scsi_bus - > target_id ] ;
scsi_device_log ( " SCSI Command 0x%02X for ID %d, status code=%02x \n " , scsi_bus - > command [ 0 ] , scsi_bus - > target_id , dev - > status ) ;
dev - > buffer_length = - 1 ;
scsi_device_command_phase0 ( dev , scsi_bus - > command ) ;
scsi_device_log ( " SCSI ID %i: Command %02X: Buffer Length %i, SCSI Phase %02X \n " , scsi_bus - > target_id , scsi_bus - > command [ 0 ] , dev - > buffer_length , dev - > phase ) ;
scsi_bus - > period = 1.0 ;
scsi_bus - > wait_data = 4 ;
scsi_bus - > data_wait = 0 ;
scsi_bus - > command_issued = 1 ;
if ( dev - > status = = SCSI_STATUS_OK ) {
/*If the SCSI phase is Data In or Data Out, allocate the SCSI buffer based on the transfer length of the command*/
if ( dev - > buffer_length & & ( ( dev - > phase = = SCSI_PHASE_DATA_IN ) | | ( dev - > phase = = SCSI_PHASE_DATA_OUT ) ) ) {
p = scsi_device_get_callback ( dev ) ;
scsi_bus - > period = ( p > 0.0 ) ? ( ( p / scsi_bus - > divider ) * scsi_bus - > multi ) : ( ( ( double ) dev - > buffer_length ) * scsi_bus - > speed ) ;
scsi_device_log ( " SCSI ID %i: command 0x%02x for p = %lf, update = %lf, len = %i, dmamode = %x \n " , scsi_bus - > target_id , scsi_bus - > command [ 0 ] , scsi_device_get_callback ( dev ) , scsi_bus - > period , dev - > buffer_length , scsi_bus - > tx_mode ) ;
}
}
scsi_bus - > bus_phase = dev - > phase ;
}
}
break ;
case STATE_DATAIN :
dev = & scsi_devices [ scsi_bus - > bus_device ] [ scsi_bus - > target_id ] ;
if ( ( bus & BUS_ACK ) & & ! ( scsi_bus - > bus_in & BUS_ACK ) ) {
if ( scsi_bus - > data_pos > = dev - > buffer_length ) {
scsi_bus - > bus_out & = ~ BUS_REQ ;
scsi_device_command_phase1 ( dev ) ;
scsi_bus - > bus_phase = SCSI_PHASE_STATUS ;
scsi_bus - > wait_data = 4 ;
scsi_bus - > wait_complete = 8 ;
} else {
if ( ( dev - > sc ! = NULL ) & & ( dev - > sc - > temp_buffer ! = NULL ) )
scsi_bus - > data = dev - > sc - > temp_buffer [ scsi_bus - > data_pos + + ] ;
scsi_device_log ( " TXMode DataIn=%x, cmd=%02x. \n " , scsi_bus - > tx_mode , scsi_bus - > command [ 0 ] ) ;
scsi_bus - > bus_out = ( scsi_bus - > bus_out & ~ BUS_DATAMASK ) | BUS_SETDATA ( scsi_bus - > data ) | BUS_DBP | BUS_REQ ;
if ( scsi_bus - > tx_mode = = PIO_TX_BUS ) { /*If a data in command that is not read 6/10 has been issued*/
scsi_device_log ( " DMA mode idle IN=%d. \n " , scsi_bus - > data_pos ) ;
scsi_bus - > data_wait | = 1 ;
scsi_bus - > timer ( scsi_bus - > priv , scsi_bus - > period ) ;
} else {
scsi_device_log ( " DMA mode IN=%d. \n " , scsi_bus - > data_pos ) ;
scsi_bus - > clear_req = 3 ;
}
scsi_bus - > bus_out & = ~ BUS_REQ ;
scsi_bus - > bus_phase = SCSI_PHASE_DATA_IN ;
}
}
break ;
case STATE_DATAOUT :
dev = & scsi_devices [ scsi_bus - > bus_device ] [ scsi_bus - > target_id ] ;
if ( ( bus & BUS_ACK ) & & ! ( scsi_bus - > bus_in & BUS_ACK ) ) {
if ( ( dev - > sc ! = NULL ) & & ( dev - > sc - > temp_buffer ! = NULL ) )
dev - > sc - > temp_buffer [ scsi_bus - > data_pos + + ] = BUS_GETDATA ( bus ) ;
if ( scsi_bus - > data_pos > = dev - > buffer_length ) {
scsi_bus - > bus_out & = ~ BUS_REQ ;
scsi_device_command_phase1 ( dev ) ;
scsi_bus - > bus_phase = SCSI_PHASE_STATUS ;
scsi_bus - > wait_data = 4 ;
scsi_bus - > wait_complete = 8 ;
} else {
/*More data is to be transferred, place a request*/
if ( scsi_bus - > tx_mode = = PIO_TX_BUS ) { /*If a data in command that is not write 6/10 has been issued*/
scsi_device_log ( " DMA mode idle OUT=%d. \n " , scsi_bus - > data_pos ) ;
scsi_bus - > data_wait | = 1 ;
scsi_bus - > timer ( scsi_bus - > priv , scsi_bus - > period ) ;
scsi_bus - > bus_out & = ~ BUS_REQ ;
} else {
scsi_device_log ( " DMA mode OUT=%d. \n " , scsi_bus - > data_pos ) ;
scsi_bus - > bus_out | = BUS_REQ ;
}
}
}
break ;
case STATE_STATUS :
if ( ( bus & BUS_ACK ) & & ! ( scsi_bus - > bus_in & BUS_ACK ) ) {
/*All transfers done, wait until next transfer*/
scsi_device_identify ( & scsi_devices [ scsi_bus - > bus_device ] [ scsi_bus - > target_id ] , SCSI_LUN_USE_CDB ) ;
scsi_bus - > bus_out & = ~ BUS_REQ ;
scsi_bus - > bus_phase = SCSI_PHASE_MESSAGE_IN ;
scsi_bus - > wait_data = 4 ;
scsi_bus - > wait_complete = 8 ;
scsi_bus - > command_issued = 0 ;
}
break ;
case STATE_MESSAGEIN :
if ( ( bus & BUS_ACK ) & & ! ( scsi_bus - > bus_in & BUS_ACK ) ) {
scsi_bus - > bus_out & = ~ BUS_REQ ;
scsi_bus - > bus_phase = BUS_IDLE ;
scsi_bus - > wait_data = 4 ;
}
break ;
case STATE_MESSAGEOUT :
if ( ( bus & BUS_ACK ) & & ! ( scsi_bus - > bus_in & BUS_ACK ) ) {
scsi_bus - > msgout [ scsi_bus - > msgout_pos + + ] = BUS_GETDATA ( bus ) ;
msglen = scsi_device_get_msg ( scsi_bus - > msgout , scsi_bus - > msgout_pos ) ;
if ( scsi_bus - > msgout_pos > = msglen ) {
if ( ( scsi_bus - > msgout [ 0 ] & ( 0x80 | 0x20 ) ) = = 0x80 )
scsi_bus - > msglun = scsi_bus - > msgout [ 0 ] & 7 ;
scsi_bus - > bus_out & = ~ BUS_REQ ;
scsi_bus - > state = STATE_MESSAGE_ID ;
}
}
break ;
case STATE_MESSAGE_ID :
if ( ( scsi_bus - > target_id ! = ( uint8_t ) - 1 ) & & scsi_device_present ( & scsi_devices [ scsi_bus - > bus_device ] [ scsi_bus - > target_id ] ) ) {
scsi_device_log ( " Device found at ID %i on MSGOUT, Current Bus BSY=%02x \n " , scsi_bus - > target_id , scsi_bus - > bus_out ) ;
scsi_device_identify ( & scsi_devices [ scsi_bus - > bus_device ] [ scsi_bus - > target_id ] , scsi_bus - > msglun ) ;
scsi_bus - > state = STATE_COMMAND ;
scsi_bus - > bus_out = BUS_BSY | BUS_REQ ;
scsi_bus - > command_pos = 0 ;
SET_BUS_STATE ( scsi_bus , SCSI_PHASE_COMMAND ) ;
}
break ;
default :
break ;
}
scsi_bus - > bus_in = bus ;
}