Files
86Box/src/scsi/scsi_device.c

524 lines
18 KiB
C
Raw Normal View History

/*
* 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.
*
2020-03-25 00:46:02 +02:00
*
*
* Authors: Miran Grca, <mgrca8@gmail.com>
* Fred N. van Kempen, <decwiz@yahoo.com>
2017-10-17 01:59:09 -04:00
*
* Copyright 2016-2018 Miran Grca.
* Copyright 2017-2018 Fred N. van Kempen.
*/
#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
#include <86box/86box.h>
#include <86box/device.h>
#include <86box/hdd.h>
#include <86box/hdc_ide.h>
#include <86box/scsi.h>
#include <86box/scsi_device.h>
2023-06-09 23:46:54 -04:00
#include <86box/plat_unused.h>
2022-09-18 17:17:15 -04:00
scsi_device_t scsi_devices[SCSI_BUS_MAX][SCSI_ID_MAX];
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 };
#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
static uint8_t
scsi_device_target_command(scsi_device_t *dev, uint8_t *cdb)
{
if (dev->command) {
2022-09-18 17:17:15 -04:00
dev->command(dev->sc, cdb);
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;
} else
2022-09-18 17:17:15 -04:00
return SCSI_STATUS_CHECK_CONDITION;
}
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
scsi_device_get_callback(scsi_device_t *dev)
{
if (dev->sc)
2022-09-18 17:17:15 -04:00
return dev->sc->callback;
else
2022-09-18 17:17:15 -04:00
return -1.0;
}
uint8_t *
scsi_device_sense(scsi_device_t *dev)
{
if (dev->sc)
2022-09-18 17:17:15 -04:00
return dev->sc->sense;
else
2022-09-18 17:17:15 -04:00
return scsi_null_device_sense;
}
void
scsi_device_request_sense(scsi_device_t *dev, uint8_t *buffer, uint8_t alloc_length)
{
if (dev->request_sense)
2022-09-18 17:17:15 -04:00
dev->request_sense(dev->sc, buffer, alloc_length);
else
2022-09-18 17:17:15 -04:00
memcpy(buffer, scsi_null_device_sense, alloc_length);
}
void
scsi_device_reset(scsi_device_t *dev)
{
if (dev->reset)
2022-09-18 17:17:15 -04:00
dev->reset(dev->sc);
}
int
scsi_device_present(scsi_device_t *dev)
{
if (dev->type == SCSI_NONE)
2022-09-18 17:17:15 -04:00
return 0;
else
2022-09-18 17:17:15 -04:00
return 1;
}
int
scsi_device_valid(scsi_device_t *dev)
{
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;
}
int
2023-06-09 23:46:54 -04:00
scsi_device_cdb_length(UNUSED(scsi_device_t *dev))
{
/* Right now, it's 12 for all devices. */
return 12;
}
void
scsi_device_command_phase0(scsi_device_t *dev, uint8_t *cdb)
{
if (!dev->sc) {
2022-09-18 17:17:15 -04:00
dev->phase = SCSI_PHASE_STATUS;
dev->status = SCSI_STATUS_CHECK_CONDITION;
return;
}
/* Finally, execute the SCSI command immediately and get the transfer length. */
2022-09-18 17:17:15 -04:00
dev->phase = SCSI_PHASE_COMMAND;
dev->status = scsi_device_target_command(dev, cdb);
}
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;
}
}
void
scsi_device_command_phase1(scsi_device_t *dev)
{
if (!dev->sc)
2022-09-18 17:17:15 -04:00
return;
/* Call the second phase. */
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);
} else
2022-09-18 17:17:15 -04:00
scsi_device_command_stop(dev);
if (dev->sc->tf->status & ERR_STAT)
2022-09-18 17:17:15 -04:00
dev->status = SCSI_STATUS_CHECK_CONDITION;
else
2022-09-18 17:17:15 -04:00
dev->status = SCSI_STATUS_OK;
}
/* 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;
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. */
}
void
scsi_device_close_all(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]);
if (dev->command_stop && dev->sc)
dev->command_stop(dev->sc);
}
}
}
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]);
2022-09-18 17:17:15 -04:00
memset(dev, 0, sizeof(scsi_device_t));
dev->type = SCSI_NONE;
}
}
}
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;
}