|  | @@ -1,1371 +1,1371 @@
 | 
											
												
													
														|  | -//	Copyright (C) 2014 Michael McMaster <michael@codesrc.com>
 |  | 
 | 
											
												
													
														|  | -//
 |  | 
 | 
											
												
													
														|  | -//	This file is part of SCSI2SD.
 |  | 
 | 
											
												
													
														|  | -//
 |  | 
 | 
											
												
													
														|  | -//	SCSI2SD is free software: you can redistribute it and/or modify
 |  | 
 | 
											
												
													
														|  | -//	it under the terms of the GNU General Public License as published by
 |  | 
 | 
											
												
													
														|  | -//	the Free Software Foundation, either version 3 of the License, or
 |  | 
 | 
											
												
													
														|  | -//	(at your option) any later version.
 |  | 
 | 
											
												
													
														|  | -//
 |  | 
 | 
											
												
													
														|  | -//	SCSI2SD is distributed in the hope that it will be useful,
 |  | 
 | 
											
												
													
														|  | -//	but WITHOUT ANY WARRANTY; without even the implied warranty of
 |  | 
 | 
											
												
													
														|  | -//	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 |  | 
 | 
											
												
													
														|  | -//	GNU General Public License for more details.
 |  | 
 | 
											
												
													
														|  | -//
 |  | 
 | 
											
												
													
														|  | -//	You should have received a copy of the GNU General Public License
 |  | 
 | 
											
												
													
														|  | -//	along with SCSI2SD.  If not, see <http://www.gnu.org/licenses/>.
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -#include "scsi.h"
 |  | 
 | 
											
												
													
														|  | -#include "scsiPhy.h"
 |  | 
 | 
											
												
													
														|  | -#include "config.h"
 |  | 
 | 
											
												
													
														|  | -#include "diagnostic.h"
 |  | 
 | 
											
												
													
														|  | -#include "disk.h"
 |  | 
 | 
											
												
													
														|  | -#include "inquiry.h"
 |  | 
 | 
											
												
													
														|  | -#include "led.h"
 |  | 
 | 
											
												
													
														|  | -#include "mode.h"
 |  | 
 | 
											
												
													
														|  | -#include "scsi2sd_time.h"
 |  | 
 | 
											
												
													
														|  | -#include "bsp.h"
 |  | 
 | 
											
												
													
														|  | -#include "cdrom.h"
 |  | 
 | 
											
												
													
														|  | -//#include "debug.h"
 |  | 
 | 
											
												
													
														|  | -#include "tape.h"
 |  | 
 | 
											
												
													
														|  | -#include "mo.h"
 |  | 
 | 
											
												
													
														|  | -#include "vendor.h"
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -#include <string.h>
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -// Global SCSI device state.
 |  | 
 | 
											
												
													
														|  | -ScsiDevice scsiDev S2S_DMA_ALIGN;
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -static void enter_SelectionPhase(void);
 |  | 
 | 
											
												
													
														|  | -static void process_SelectionPhase(void);
 |  | 
 | 
											
												
													
														|  | -static void enter_MessageIn(uint8_t message);
 |  | 
 | 
											
												
													
														|  | -static void enter_Status(uint8_t status);
 |  | 
 | 
											
												
													
														|  | -static void enter_DataIn(int len);
 |  | 
 | 
											
												
													
														|  | -static void process_DataIn(void);
 |  | 
 | 
											
												
													
														|  | -static void process_DataOut(void);
 |  | 
 | 
											
												
													
														|  | -static void process_Command(void);
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -static void doReserveRelease(void);
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -void enter_BusFree()
 |  | 
 | 
											
												
													
														|  | -{
 |  | 
 | 
											
												
													
														|  | -	// This delay probably isn't needed for most SCSI hosts, but it won't
 |  | 
 | 
											
												
													
														|  | -	// hurt either. It's possible some of the samplers needed this delay.
 |  | 
 | 
											
												
													
														|  | -	if (scsiDev.compatMode < COMPAT_SCSI2)
 |  | 
 | 
											
												
													
														|  | -	{
 |  | 
 | 
											
												
													
														|  | -		s2s_delay_us(2);
 |  | 
 | 
											
												
													
														|  | -	}
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -#if 0
 |  | 
 | 
											
												
													
														|  | -	if (scsiDev.status != GOOD)// && isDebugEnabled())
 |  | 
 | 
											
												
													
														|  | -	{
 |  | 
 | 
											
												
													
														|  | -		// We want to capture debug information for failure cases.
 |  | 
 | 
											
												
													
														|  | -		s2s_delay_ms(80);
 |  | 
 | 
											
												
													
														|  | -	}
 |  | 
 | 
											
												
													
														|  | -#endif
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -	scsiEnterBusFree();
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -	// Wait for the initiator to cease driving signals
 |  | 
 | 
											
												
													
														|  | -	// Bus settle delay + bus clear delay = 1200ns
 |  | 
 | 
											
												
													
														|  | -    // Just waiting the clear delay is sufficient.
 |  | 
 | 
											
												
													
														|  | -	s2s_delay_ns(800);
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -	s2s_ledOff();
 |  | 
 | 
											
												
													
														|  | -	scsiDev.phase = BUS_FREE;
 |  | 
 | 
											
												
													
														|  | -	scsiDev.selFlag = 0;
 |  | 
 | 
											
												
													
														|  | -}
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -static void enter_MessageIn(uint8_t message)
 |  | 
 | 
											
												
													
														|  | -{
 |  | 
 | 
											
												
													
														|  | -	scsiDev.msgIn = message;
 |  | 
 | 
											
												
													
														|  | -	scsiDev.phase = MESSAGE_IN;
 |  | 
 | 
											
												
													
														|  | -}
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -int process_MessageIn(int releaseBusFree)
 |  | 
 | 
											
												
													
														|  | -{
 |  | 
 | 
											
												
													
														|  | -	scsiEnterPhase(MESSAGE_IN);
 |  | 
 | 
											
												
													
														|  | -	scsiWriteByte(scsiDev.msgIn);
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -	if (unlikely(scsiDev.atnFlag))
 |  | 
 | 
											
												
													
														|  | -	{
 |  | 
 | 
											
												
													
														|  | -		// If there was a parity error, we go
 |  | 
 | 
											
												
													
														|  | -		// back to MESSAGE_OUT first, get out parity error message, then come
 |  | 
 | 
											
												
													
														|  | -		// back here.
 |  | 
 | 
											
												
													
														|  | -		return 0;
 |  | 
 | 
											
												
													
														|  | -	}
 |  | 
 | 
											
												
													
														|  | -	else if ((scsiDev.msgIn == MSG_LINKED_COMMAND_COMPLETE) ||
 |  | 
 | 
											
												
													
														|  | -		(scsiDev.msgIn == MSG_LINKED_COMMAND_COMPLETE_WITH_FLAG))
 |  | 
 | 
											
												
													
														|  | -	{
 |  | 
 | 
											
												
													
														|  | -		// Go back to the command phase and start again.
 |  | 
 | 
											
												
													
														|  | -		scsiDev.phase = COMMAND;
 |  | 
 | 
											
												
													
														|  | -		scsiDev.dataPtr = 0;
 |  | 
 | 
											
												
													
														|  | -		scsiDev.savedDataPtr = 0;
 |  | 
 | 
											
												
													
														|  | -		scsiDev.dataLen = 0;
 |  | 
 | 
											
												
													
														|  | -		scsiDev.status = GOOD;
 |  | 
 | 
											
												
													
														|  | -		transfer.blocks = 0;
 |  | 
 | 
											
												
													
														|  | -		transfer.currentBlock = 0;
 |  | 
 | 
											
												
													
														|  | -		return 0;
 |  | 
 | 
											
												
													
														|  | -	}
 |  | 
 | 
											
												
													
														|  | -	else if (releaseBusFree) /*if (scsiDev.msgIn == MSG_COMMAND_COMPLETE)*/
 |  | 
 | 
											
												
													
														|  | -	{
 |  | 
 | 
											
												
													
														|  | -		enter_BusFree();
 |  | 
 | 
											
												
													
														|  | -		return 1;
 |  | 
 | 
											
												
													
														|  | -	}
 |  | 
 | 
											
												
													
														|  | -	else
 |  | 
 | 
											
												
													
														|  | -	{
 |  | 
 | 
											
												
													
														|  | -		return 1;
 |  | 
 | 
											
												
													
														|  | -	}
 |  | 
 | 
											
												
													
														|  | -}
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -static void messageReject()
 |  | 
 | 
											
												
													
														|  | -{
 |  | 
 | 
											
												
													
														|  | -	scsiEnterPhase(MESSAGE_IN);
 |  | 
 | 
											
												
													
														|  | -	scsiWriteByte(MSG_REJECT);
 |  | 
 | 
											
												
													
														|  | -}
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -static void enter_Status(uint8_t status)
 |  | 
 | 
											
												
													
														|  | -{
 |  | 
 | 
											
												
													
														|  | -	scsiDev.status = status;
 |  | 
 | 
											
												
													
														|  | -	scsiDev.phase = STATUS;
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -	scsiDev.lastStatus = scsiDev.status;
 |  | 
 | 
											
												
													
														|  | -	scsiDev.lastSense = scsiDev.target->sense.code;
 |  | 
 | 
											
												
													
														|  | -	scsiDev.lastSenseASC = scsiDev.target->sense.asc;
 |  | 
 | 
											
												
													
														|  | -}
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -void process_Status()
 |  | 
 | 
											
												
													
														|  | -{
 |  | 
 | 
											
												
													
														|  | -	scsiEnterPhase(STATUS);
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -	uint8_t message;
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -	uint8_t control = scsiDev.cdb[scsiDev.cdbLen - 1];
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -	if (scsiDev.target->cfg->quirks == S2S_CFG_QUIRKS_OMTI)
 |  | 
 | 
											
												
													
														|  | -	{
 |  | 
 | 
											
												
													
														|  | -		// All commands have a control byte, except 0xC0
 |  | 
 | 
											
												
													
														|  | -		if (scsiDev.cdb[0] == 0xC0)
 |  | 
 | 
											
												
													
														|  | -		{
 |  | 
 | 
											
												
													
														|  | -			control = 0;
 |  | 
 | 
											
												
													
														|  | -		}
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -		// OMTI non-standard LINK control
 |  | 
 | 
											
												
													
														|  | -		if (control & 0x01)
 |  | 
 | 
											
												
													
														|  | -		{
 |  | 
 | 
											
												
													
														|  | -			scsiDev.phase = COMMAND;
 |  | 
 | 
											
												
													
														|  | -			return;
 |  | 
 | 
											
												
													
														|  | -		}
 |  | 
 | 
											
												
													
														|  | -	}
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -	if ((scsiDev.status == GOOD) && (control & 0x01) &&
 |  | 
 | 
											
												
													
														|  | -		scsiDev.target->cfg->quirks != S2S_CFG_QUIRKS_XEBEC)
 |  | 
 | 
											
												
													
														|  | -	{
 |  | 
 | 
											
												
													
														|  | -		// Linked command.
 |  | 
 | 
											
												
													
														|  | -		scsiDev.status = INTERMEDIATE;
 |  | 
 | 
											
												
													
														|  | -		if (control & 0x02)
 |  | 
 | 
											
												
													
														|  | -		{
 |  | 
 | 
											
												
													
														|  | -			message = MSG_LINKED_COMMAND_COMPLETE_WITH_FLAG;
 |  | 
 | 
											
												
													
														|  | -		}
 |  | 
 | 
											
												
													
														|  | -		else
 |  | 
 | 
											
												
													
														|  | -		{
 |  | 
 | 
											
												
													
														|  | -			message = MSG_LINKED_COMMAND_COMPLETE;
 |  | 
 | 
											
												
													
														|  | -		}
 |  | 
 | 
											
												
													
														|  | -	}
 |  | 
 | 
											
												
													
														|  | -	else
 |  | 
 | 
											
												
													
														|  | -	{
 |  | 
 | 
											
												
													
														|  | -		message = MSG_COMMAND_COMPLETE;
 |  | 
 | 
											
												
													
														|  | -	}
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -	if (scsiDev.target->cfg->quirks == S2S_CFG_QUIRKS_XEBEC)
 |  | 
 | 
											
												
													
														|  | -	{
 |  | 
 | 
											
												
													
														|  | -		// More non-standardness. Expects 2 status bytes (really status + msg)
 |  | 
 | 
											
												
													
														|  | -		// 00 d 000 err 0
 |  | 
 | 
											
												
													
														|  | -		// d == disk number
 |  | 
 | 
											
												
													
														|  | -		// ERR = 1 if error.
 |  | 
 | 
											
												
													
														|  | -		if (scsiDev.status == GOOD)
 |  | 
 | 
											
												
													
														|  | -		{
 |  | 
 | 
											
												
													
														|  | -			scsiWriteByte(scsiDev.cdb[1] & 0x20);
 |  | 
 | 
											
												
													
														|  | -		}
 |  | 
 | 
											
												
													
														|  | -		else
 |  | 
 | 
											
												
													
														|  | -		{
 |  | 
 | 
											
												
													
														|  | -			scsiWriteByte((scsiDev.cdb[1] & 0x20) | 0x2);
 |  | 
 | 
											
												
													
														|  | -		}
 |  | 
 | 
											
												
													
														|  | -		s2s_delay_us(10); // Seems to need a delay before changing phase bits.
 |  | 
 | 
											
												
													
														|  | -	}
 |  | 
 | 
											
												
													
														|  | -	else if (scsiDev.target->cfg->quirks == S2S_CFG_QUIRKS_OMTI)
 |  | 
 | 
											
												
													
														|  | -	{
 |  | 
 | 
											
												
													
														|  | -		scsiDev.status |= (scsiDev.target->targetId & 0x03) << 5;
 |  | 
 | 
											
												
													
														|  | -		scsiWriteByte(scsiDev.status);
 |  | 
 | 
											
												
													
														|  | -	}
 |  | 
 | 
											
												
													
														|  | -	else
 |  | 
 | 
											
												
													
														|  | -	{
 |  | 
 | 
											
												
													
														|  | -		scsiWriteByte(scsiDev.status);
 |  | 
 | 
											
												
													
														|  | -	}
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -	scsiDev.lastStatus = scsiDev.status;
 |  | 
 | 
											
												
													
														|  | -	scsiDev.lastSense = scsiDev.target->sense.code;
 |  | 
 | 
											
												
													
														|  | -	scsiDev.lastSenseASC = scsiDev.target->sense.asc;
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -	// Command Complete occurs AFTER a valid status has been
 |  | 
 | 
											
												
													
														|  | -	// sent. then we go bus-free.
 |  | 
 | 
											
												
													
														|  | -	enter_MessageIn(message);
 |  | 
 | 
											
												
													
														|  | -}
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -static void enter_DataIn(int len)
 |  | 
 | 
											
												
													
														|  | -{
 |  | 
 | 
											
												
													
														|  | -	scsiDev.dataLen = len;
 |  | 
 | 
											
												
													
														|  | -	scsiDev.phase = DATA_IN;
 |  | 
 | 
											
												
													
														|  | -}
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -static void process_DataIn()
 |  | 
 | 
											
												
													
														|  | -{
 |  | 
 | 
											
												
													
														|  | -	uint32_t len;
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -	if (scsiDev.dataLen > sizeof(scsiDev.data))
 |  | 
 | 
											
												
													
														|  | -	{
 |  | 
 | 
											
												
													
														|  | -		scsiDev.dataLen = sizeof(scsiDev.data);
 |  | 
 | 
											
												
													
														|  | -	}
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -	len = scsiDev.dataLen - scsiDev.dataPtr;
 |  | 
 | 
											
												
													
														|  | -	if (len > 0)
 |  | 
 | 
											
												
													
														|  | -	{
 |  | 
 | 
											
												
													
														|  | -		scsiEnterPhase(DATA_IN);
 |  | 
 | 
											
												
													
														|  | -		scsiWrite(scsiDev.data + scsiDev.dataPtr, len);
 |  | 
 | 
											
												
													
														|  | -		scsiDev.dataPtr += len;
 |  | 
 | 
											
												
													
														|  | -	}
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -	if ((scsiDev.dataPtr >= scsiDev.dataLen) &&
 |  | 
 | 
											
												
													
														|  | -		(transfer.currentBlock == transfer.blocks))
 |  | 
 | 
											
												
													
														|  | -	{
 |  | 
 | 
											
												
													
														|  | -		enter_Status(GOOD);
 |  | 
 | 
											
												
													
														|  | -	}
 |  | 
 | 
											
												
													
														|  | -}
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -static void process_DataOut()
 |  | 
 | 
											
												
													
														|  | -{
 |  | 
 | 
											
												
													
														|  | -	uint32_t len;
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -	if (scsiDev.dataLen > sizeof(scsiDev.data))
 |  | 
 | 
											
												
													
														|  | -	{
 |  | 
 | 
											
												
													
														|  | -		scsiDev.dataLen = sizeof(scsiDev.data);
 |  | 
 | 
											
												
													
														|  | -	}
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -	len = scsiDev.dataLen - scsiDev.dataPtr;
 |  | 
 | 
											
												
													
														|  | -	if (len > 0)
 |  | 
 | 
											
												
													
														|  | -	{
 |  | 
 | 
											
												
													
														|  | -		scsiEnterPhase(DATA_OUT);
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -		int parityError = 0;
 |  | 
 | 
											
												
													
														|  | -		scsiRead(scsiDev.data + scsiDev.dataPtr, len, &parityError);
 |  | 
 | 
											
												
													
														|  | -		scsiDev.dataPtr += len;
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -		if (parityError &&
 |  | 
 | 
											
												
													
														|  | -			(scsiDev.boardCfg.flags & S2S_CFG_ENABLE_PARITY))
 |  | 
 | 
											
												
													
														|  | -		{
 |  | 
 | 
											
												
													
														|  | -			scsiDev.target->sense.code = ABORTED_COMMAND;
 |  | 
 | 
											
												
													
														|  | -			scsiDev.target->sense.asc = SCSI_PARITY_ERROR;
 |  | 
 | 
											
												
													
														|  | -			enter_Status(CHECK_CONDITION);
 |  | 
 | 
											
												
													
														|  | -		}
 |  | 
 | 
											
												
													
														|  | -	}
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -	if ((scsiDev.dataPtr >= scsiDev.dataLen) &&
 |  | 
 | 
											
												
													
														|  | -		(transfer.currentBlock == transfer.blocks))
 |  | 
 | 
											
												
													
														|  | -	{
 |  | 
 | 
											
												
													
														|  | -		if (scsiDev.postDataOutHook != NULL)
 |  | 
 | 
											
												
													
														|  | -		{
 |  | 
 | 
											
												
													
														|  | -			scsiDev.postDataOutHook();
 |  | 
 | 
											
												
													
														|  | -		}
 |  | 
 | 
											
												
													
														|  | -		else
 |  | 
 | 
											
												
													
														|  | -		{
 |  | 
 | 
											
												
													
														|  | -			enter_Status(GOOD);
 |  | 
 | 
											
												
													
														|  | -		}
 |  | 
 | 
											
												
													
														|  | -	}
 |  | 
 | 
											
												
													
														|  | -}
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -static const uint8_t CmdGroupBytes[] = {
 |  | 
 | 
											
												
													
														|  | -	6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
 |  | 
 | 
											
												
													
														|  | -	10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
 |  | 
 | 
											
												
													
														|  | -	10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
 |  | 
 | 
											
												
													
														|  | -	10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
 |  | 
 | 
											
												
													
														|  | -	10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
 |  | 
 | 
											
												
													
														|  | -	10,10,10,10,10,10,10,10,10,10,10,10,10,16,16,16,16,16,16,16,16,
 |  | 
 | 
											
												
													
														|  | -	16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,
 |  | 
 | 
											
												
													
														|  | -	16,16,16,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,
 |  | 
 | 
											
												
													
														|  | -	12,12,12,12,12,12,12,12,12,12,12,12,12,12,10,10,10,10,10,10,10,
 |  | 
 | 
											
												
													
														|  | -	10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
 |  | 
 | 
											
												
													
														|  | -	10,10,10,10,10,10,10,10,10,10,10,10,10,10
 |  | 
 | 
											
												
													
														|  | -};
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -static void process_Command()
 |  | 
 | 
											
												
													
														|  | -{
 |  | 
 | 
											
												
													
														|  | -	uint8_t command;
 |  | 
 | 
											
												
													
														|  | -	uint8_t control;
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -	scsiEnterPhase(COMMAND);
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -	memset(scsiDev.cdb + 6, 0, sizeof(scsiDev.cdb) - 6);
 |  | 
 | 
											
												
													
														|  | -	int parityError = 0;
 |  | 
 | 
											
												
													
														|  | -	scsiRead(scsiDev.cdb, 6, &parityError);
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -	// Handle Atari ST ICD extended commands
 |  | 
 | 
											
												
													
														|  | -	if (scsiDev.cdb[0] == 0x1F)
 |  | 
 | 
											
												
													
														|  | -	{
 |  | 
 | 
											
												
													
														|  | -		scsiDev.cdb[0] = scsiDev.cdb[1];
 |  | 
 | 
											
												
													
														|  | -		scsiDev.cdb[1] = scsiDev.cdb[2];
 |  | 
 | 
											
												
													
														|  | -		scsiDev.cdb[2] = scsiDev.cdb[3];
 |  | 
 | 
											
												
													
														|  | -		scsiDev.cdb[3] = scsiDev.cdb[4];
 |  | 
 | 
											
												
													
														|  | -		scsiDev.cdb[4] = scsiDev.cdb[5];
 |  | 
 | 
											
												
													
														|  | -		scsiDev.cdb[5] = scsiReadByte();
 |  | 
 | 
											
												
													
														|  | -	}
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -	scsiDev.cdbLen = CmdGroupBytes[scsiDev.cdb[0]];
 |  | 
 | 
											
												
													
														|  | -	if (parityError &&
 |  | 
 | 
											
												
													
														|  | -		(scsiDev.boardCfg.flags & S2S_CFG_ENABLE_PARITY))
 |  | 
 | 
											
												
													
														|  | -	{
 |  | 
 | 
											
												
													
														|  | -		// Don't try and read more bytes, as we cannot be sure what group
 |  | 
 | 
											
												
													
														|  | -		// the command should be.
 |  | 
 | 
											
												
													
														|  | -	}
 |  | 
 | 
											
												
													
														|  | -	else if (scsiDev.cdbLen - 6 > 0)
 |  | 
 | 
											
												
													
														|  | -	{
 |  | 
 | 
											
												
													
														|  | -		scsiRead(scsiDev.cdb + 6, scsiDev.cdbLen - 6, &parityError);
 |  | 
 | 
											
												
													
														|  | -	}
 |  | 
 | 
											
												
													
														|  | -	command = scsiDev.cdb[0];
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -	// Prefer LUN's set by IDENTIFY messages for newer hosts.
 |  | 
 | 
											
												
													
														|  | -	if (scsiDev.lun < 0)
 |  | 
 | 
											
												
													
														|  | -	{
 |  | 
 | 
											
												
													
														|  | -		if (command == 0xE0 || command == 0xE4) // XEBEC s1410
 |  | 
 | 
											
												
													
														|  | -		{
 |  | 
 | 
											
												
													
														|  | -			scsiDev.lun = 0;
 |  | 
 | 
											
												
													
														|  | -		}
 |  | 
 | 
											
												
													
														|  | -		else
 |  | 
 | 
											
												
													
														|  | -		{
 |  | 
 | 
											
												
													
														|  | -			scsiDev.lun = scsiDev.cdb[1] >> 5;
 |  | 
 | 
											
												
													
														|  | -		}
 |  | 
 | 
											
												
													
														|  | -	}
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -	// For Philips P2000C with Xebec S1410 SASI/MFM adapter
 |  | 
 | 
											
												
													
														|  | -	// http://bitsavers.trailing-edge.com/pdf/xebec/104524C_S1410Man_Aug83.pdf
 |  | 
 | 
											
												
													
														|  | -	if ((scsiDev.lun > 0) && (scsiDev.boardCfg.flags & S2S_CFG_MAP_LUNS_TO_IDS))
 |  | 
 | 
											
												
													
														|  | -	{
 |  | 
 | 
											
												
													
														|  | -		int tgtIndex;
 |  | 
 | 
											
												
													
														|  | -		for (tgtIndex = 0; tgtIndex < S2S_MAX_TARGETS; ++tgtIndex)
 |  | 
 | 
											
												
													
														|  | -		{
 |  | 
 | 
											
												
													
														|  | -			if (scsiDev.targets[tgtIndex].targetId == scsiDev.lun)
 |  | 
 | 
											
												
													
														|  | -			{
 |  | 
 | 
											
												
													
														|  | -				scsiDev.target = &scsiDev.targets[tgtIndex];
 |  | 
 | 
											
												
													
														|  | -				scsiDev.lun = 0;
 |  | 
 | 
											
												
													
														|  | -				break;
 |  | 
 | 
											
												
													
														|  | -			}
 |  | 
 | 
											
												
													
														|  | -		}
 |  | 
 | 
											
												
													
														|  | -	}
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -	control = scsiDev.cdb[scsiDev.cdbLen - 1];
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -	scsiDev.cmdCount++;
 |  | 
 | 
											
												
													
														|  | -	const S2S_TargetCfg* cfg = scsiDev.target->cfg;
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -	if (unlikely(scsiDev.resetFlag))
 |  | 
 | 
											
												
													
														|  | -	{
 |  | 
 | 
											
												
													
														|  | -		// Don't log bogus commands
 |  | 
 | 
											
												
													
														|  | -		scsiDev.cmdCount--;
 |  | 
 | 
											
												
													
														|  | -		memset(scsiDev.cdb, 0xff, sizeof(scsiDev.cdb));
 |  | 
 | 
											
												
													
														|  | -		return;
 |  | 
 | 
											
												
													
														|  | -	}
 |  | 
 | 
											
												
													
														|  | -	else if (parityError &&
 |  | 
 | 
											
												
													
														|  | -		(scsiDev.boardCfg.flags & S2S_CFG_ENABLE_PARITY))
 |  | 
 | 
											
												
													
														|  | -	{
 |  | 
 | 
											
												
													
														|  | -		scsiDev.target->sense.code = ABORTED_COMMAND;
 |  | 
 | 
											
												
													
														|  | -		scsiDev.target->sense.asc = SCSI_PARITY_ERROR;
 |  | 
 | 
											
												
													
														|  | -		enter_Status(CHECK_CONDITION);
 |  | 
 | 
											
												
													
														|  | -	}
 |  | 
 | 
											
												
													
														|  | -	else if ((control & 0x02) && ((control & 0x01) == 0) &&
 |  | 
 | 
											
												
													
														|  | -		// used for head step options on xebec.
 |  | 
 | 
											
												
													
														|  | -		likely(scsiDev.target->cfg->quirks != S2S_CFG_QUIRKS_XEBEC))
 |  | 
 | 
											
												
													
														|  | -	{
 |  | 
 | 
											
												
													
														|  | -		// FLAG set without LINK flag.
 |  | 
 | 
											
												
													
														|  | -		scsiDev.target->sense.code = ILLEGAL_REQUEST;
 |  | 
 | 
											
												
													
														|  | -		scsiDev.target->sense.asc = INVALID_FIELD_IN_CDB;
 |  | 
 | 
											
												
													
														|  | -		enter_Status(CHECK_CONDITION);
 |  | 
 | 
											
												
													
														|  | -	}
 |  | 
 | 
											
												
													
														|  | -	else if (command == 0x12)
 |  | 
 | 
											
												
													
														|  | -	{
 |  | 
 | 
											
												
													
														|  | -		s2s_scsiInquiry();
 |  | 
 | 
											
												
													
														|  | -	}
 |  | 
 | 
											
												
													
														|  | -	else if (command == 0x03)
 |  | 
 | 
											
												
													
														|  | -	{
 |  | 
 | 
											
												
													
														|  | -		// REQUEST SENSE
 |  | 
 | 
											
												
													
														|  | -		uint32_t allocLength = scsiDev.cdb[4];
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -		if (scsiDev.target->cfg->quirks == S2S_CFG_QUIRKS_XEBEC)
 |  | 
 | 
											
												
													
														|  | -		{
 |  | 
 | 
											
												
													
														|  | -			// Completely non-standard
 |  | 
 | 
											
												
													
														|  | -			allocLength = 4;
 |  | 
 | 
											
												
													
														|  | -			if (scsiDev.target->sense.code == NO_SENSE)
 |  | 
 | 
											
												
													
														|  | -				scsiDev.data[0] = 0;
 |  | 
 | 
											
												
													
														|  | -			else if (scsiDev.target->sense.code == ILLEGAL_REQUEST)
 |  | 
 | 
											
												
													
														|  | -				scsiDev.data[0] = 0x20; // Illegal command
 |  | 
 | 
											
												
													
														|  | -			else if (scsiDev.target->sense.code == NOT_READY)
 |  | 
 | 
											
												
													
														|  | -				scsiDev.data[0] = 0x04; // Drive not ready
 |  | 
 | 
											
												
													
														|  | -			else
 |  | 
 | 
											
												
													
														|  | -				scsiDev.data[0] = 0x11;  // Uncorrectable data error
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -			scsiDev.data[1] = (scsiDev.cdb[1] & 0x20) | ((transfer.lba >> 16) & 0x1F);
 |  | 
 | 
											
												
													
														|  | -			scsiDev.data[2] = transfer.lba >> 8;
 |  | 
 | 
											
												
													
														|  | -			scsiDev.data[3] = transfer.lba;
 |  | 
 | 
											
												
													
														|  | -		}
 |  | 
 | 
											
												
													
														|  | -		else if (cfg->quirks == S2S_CFG_QUIRKS_OMTI)
 |  | 
 | 
											
												
													
														|  | -		{
 |  | 
 | 
											
												
													
														|  | -			// The response is completely non-standard.
 |  | 
 | 
											
												
													
														|  | -			if (likely(allocLength > 12))
 |  | 
 | 
											
												
													
														|  | -			    allocLength = 12;
 |  | 
 | 
											
												
													
														|  | -			else if (unlikely(allocLength < 4))
 |  | 
 | 
											
												
													
														|  | -				allocLength = 4;
 |  | 
 | 
											
												
													
														|  | -			if (cfg->deviceType != S2S_CFG_SEQUENTIAL)
 |  | 
 | 
											
												
													
														|  | -			    allocLength = 4;
 |  | 
 | 
											
												
													
														|  | -			memset(scsiDev.data, 0, allocLength);
 |  | 
 | 
											
												
													
														|  | -			if (scsiDev.target->sense.code == NO_SENSE)
 |  | 
 | 
											
												
													
														|  | -			{
 |  | 
 | 
											
												
													
														|  | -				// Nothing to report.
 |  | 
 | 
											
												
													
														|  | -			}
 |  | 
 | 
											
												
													
														|  | -			else if (scsiDev.target->sense.code == UNIT_ATTENTION &&
 |  | 
 | 
											
												
													
														|  | -			    cfg->deviceType == S2S_CFG_SEQUENTIAL)
 |  | 
 | 
											
												
													
														|  | -			{
 |  | 
 | 
											
												
													
														|  | -				scsiDev.data[0] = 0x10; // Tape exception
 |  | 
 | 
											
												
													
														|  | -			}
 |  | 
 | 
											
												
													
														|  | -			else if (scsiDev.target->sense.code == ILLEGAL_REQUEST)
 |  | 
 | 
											
												
													
														|  | -			{
 |  | 
 | 
											
												
													
														|  | -				if (scsiDev.target->sense.asc == LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE)
 |  | 
 | 
											
												
													
														|  | -				{
 |  | 
 | 
											
												
													
														|  | -					if (cfg->deviceType == S2S_CFG_SEQUENTIAL)
 |  | 
 | 
											
												
													
														|  | -						scsiDev.data[0] = 0x10; // Tape exception
 |  | 
 | 
											
												
													
														|  | -					else
 |  | 
 | 
											
												
													
														|  | -						scsiDev.data[0] = 0x21; // Illegal Parameters
 |  | 
 | 
											
												
													
														|  | -				}
 |  | 
 | 
											
												
													
														|  | -				else if (scsiDev.target->sense.asc == INVALID_COMMAND_OPERATION_CODE)
 |  | 
 | 
											
												
													
														|  | -				{
 |  | 
 | 
											
												
													
														|  | -					scsiDev.data[0] = 0x20; // Invalid Command
 |  | 
 | 
											
												
													
														|  | -				}
 |  | 
 | 
											
												
													
														|  | -			}
 |  | 
 | 
											
												
													
														|  | -			else if (scsiDev.target->sense.code == NOT_READY)
 |  | 
 | 
											
												
													
														|  | -			{
 |  | 
 | 
											
												
													
														|  | -				scsiDev.data[0] = 0x04; // Drive not ready
 |  | 
 | 
											
												
													
														|  | -			}
 |  | 
 | 
											
												
													
														|  | -			else if (scsiDev.target->sense.code == BLANK_CHECK)
 |  | 
 | 
											
												
													
														|  | -			{
 |  | 
 | 
											
												
													
														|  | -				scsiDev.data[0] = 0x10; // Tape exception
 |  | 
 | 
											
												
													
														|  | -			}
 |  | 
 | 
											
												
													
														|  | -			else
 |  | 
 | 
											
												
													
														|  | -			{
 |  | 
 | 
											
												
													
														|  | -				scsiDev.data[0] = 0x11; // Uncorrectable data error
 |  | 
 | 
											
												
													
														|  | -			}
 |  | 
 | 
											
												
													
														|  | -			scsiDev.data[1] = (scsiDev.cdb[1] & 0x60) | ((transfer.lba >> 16) & 0x1F);
 |  | 
 | 
											
												
													
														|  | -			scsiDev.data[2] = transfer.lba >> 8;
 |  | 
 | 
											
												
													
														|  | -			scsiDev.data[3] = transfer.lba;
 |  | 
 | 
											
												
													
														|  | -			if (cfg->deviceType == S2S_CFG_SEQUENTIAL)
 |  | 
 | 
											
												
													
														|  | -			{
 |  | 
 | 
											
												
													
														|  | -				// For the tape drive there are 8 extra sense bytes.
 |  | 
 | 
											
												
													
														|  | -				if (scsiDev.target->sense.code == BLANK_CHECK)
 |  | 
 | 
											
												
													
														|  | -					scsiDev.data[11] = 0x88; // End of data recorded on the tape
 |  | 
 | 
											
												
													
														|  | -				else if (scsiDev.target->sense.code == UNIT_ATTENTION)
 |  | 
 | 
											
												
													
														|  | -					scsiDev.data[5] = 0x81; // Power On Reset occurred
 |  | 
 | 
											
												
													
														|  | -				else if (scsiDev.target->sense.code == ILLEGAL_REQUEST &&
 |  | 
 | 
											
												
													
														|  | -					 scsiDev.target->sense.asc == LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE)
 |  | 
 | 
											
												
													
														|  | -					scsiDev.data[4] = 0x81; // File Mark detected
 |  | 
 | 
											
												
													
														|  | -			}
 |  | 
 | 
											
												
													
														|  | -		}
 |  | 
 | 
											
												
													
														|  | -		else
 |  | 
 | 
											
												
													
														|  | -		{
 |  | 
 | 
											
												
													
														|  | -			// As specified by the SASI and SCSI1 standard.
 |  | 
 | 
											
												
													
														|  | -			// Newer initiators won't be specifying 0 anyway.
 |  | 
 | 
											
												
													
														|  | -			if (allocLength == 0) allocLength = 4;
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -			memset(scsiDev.data, 0, 256); // Max possible alloc length
 |  | 
 | 
											
												
													
														|  | -			scsiDev.data[0] = 0xF0;
 |  | 
 | 
											
												
													
														|  | -			scsiDev.data[2] = scsiDev.target->sense.code & 0x0F;
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -			scsiDev.data[3] = transfer.lba >> 24;
 |  | 
 | 
											
												
													
														|  | -			scsiDev.data[4] = transfer.lba >> 16;
 |  | 
 | 
											
												
													
														|  | -			scsiDev.data[5] = transfer.lba >> 8;
 |  | 
 | 
											
												
													
														|  | -			scsiDev.data[6] = transfer.lba;
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -			// Additional bytes if there are errors to report
 |  | 
 | 
											
												
													
														|  | -			scsiDev.data[7] = 10; // additional length
 |  | 
 | 
											
												
													
														|  | -			scsiDev.data[12] = scsiDev.target->sense.asc >> 8;
 |  | 
 | 
											
												
													
														|  | -			scsiDev.data[13] = scsiDev.target->sense.asc;
 |  | 
 | 
											
												
													
														|  | -		}
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -		// Silently truncate results. SCSI-2 spec 8.2.14.
 |  | 
 | 
											
												
													
														|  | -		enter_DataIn(allocLength);
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -		// This is a good time to clear out old sense information.
 |  | 
 | 
											
												
													
														|  | -		scsiDev.target->sense.code = NO_SENSE;
 |  | 
 | 
											
												
													
														|  | -		scsiDev.target->sense.asc = NO_ADDITIONAL_SENSE_INFORMATION;
 |  | 
 | 
											
												
													
														|  | -	}
 |  | 
 | 
											
												
													
														|  | -	// Some old SCSI drivers do NOT properly support
 |  | 
 | 
											
												
													
														|  | -	// unitAttention. eg. the Mac Plus would trigger a SCSI reset
 |  | 
 | 
											
												
													
														|  | -	// on receiving the unit attention response on boot, thus
 |  | 
 | 
											
												
													
														|  | -	// triggering another unit attention condition.
 |  | 
 | 
											
												
													
														|  | -	else if (scsiDev.target->unitAttention &&
 |  | 
 | 
											
												
													
														|  | -		(scsiDev.boardCfg.flags & S2S_CFG_ENABLE_UNIT_ATTENTION))
 |  | 
 | 
											
												
													
														|  | -	{
 |  | 
 | 
											
												
													
														|  | -		scsiDev.target->sense.code = UNIT_ATTENTION;
 |  | 
 | 
											
												
													
														|  | -		scsiDev.target->sense.asc = scsiDev.target->unitAttention;
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -		// If initiator doesn't do REQUEST SENSE for the next command, then
 |  | 
 | 
											
												
													
														|  | -		// data is lost.
 |  | 
 | 
											
												
													
														|  | -		scsiDev.target->unitAttention = 0;
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -		enter_Status(CHECK_CONDITION);
 |  | 
 | 
											
												
													
														|  | -	}
 |  | 
 | 
											
												
													
														|  | -	else if (scsiDev.lun)
 |  | 
 | 
											
												
													
														|  | -	{
 |  | 
 | 
											
												
													
														|  | -		scsiDev.target->sense.code = ILLEGAL_REQUEST;
 |  | 
 | 
											
												
													
														|  | -		scsiDev.target->sense.asc = LOGICAL_UNIT_NOT_SUPPORTED;
 |  | 
 | 
											
												
													
														|  | -		enter_Status(CHECK_CONDITION);
 |  | 
 | 
											
												
													
														|  | -	}
 |  | 
 | 
											
												
													
														|  | -	else if (command == 0x17 || command == 0x16)
 |  | 
 | 
											
												
													
														|  | -	{
 |  | 
 | 
											
												
													
														|  | -		doReserveRelease();
 |  | 
 | 
											
												
													
														|  | -	}
 |  | 
 | 
											
												
													
														|  | -	else if ((scsiDev.target->reservedId >= 0) &&
 |  | 
 | 
											
												
													
														|  | -		(scsiDev.target->reservedId != scsiDev.initiatorId))
 |  | 
 | 
											
												
													
														|  | -	{
 |  | 
 | 
											
												
													
														|  | -		enter_Status(CONFLICT);
 |  | 
 | 
											
												
													
														|  | -	}
 |  | 
 | 
											
												
													
														|  | -	// Handle odd device types first that may override basic read and
 |  | 
 | 
											
												
													
														|  | -	// write commands. Will fall-through to generic disk handling.
 |  | 
 | 
											
												
													
														|  | -	else if (((cfg->deviceType == S2S_CFG_OPTICAL) && scsiCDRomCommand()) ||
 |  | 
 | 
											
												
													
														|  | -		((cfg->deviceType == S2S_CFG_SEQUENTIAL) && scsiTapeCommand()) ||
 |  | 
 | 
											
												
													
														|  | -		((cfg->deviceType == S2S_CFG_MO) && scsiMOCommand()))
 |  | 
 | 
											
												
													
														|  | -	{
 |  | 
 | 
											
												
													
														|  | -		// Already handled.
 |  | 
 | 
											
												
													
														|  | -	}
 |  | 
 | 
											
												
													
														|  | -	else if (scsiDiskCommand())
 |  | 
 | 
											
												
													
														|  | -	{
 |  | 
 | 
											
												
													
														|  | -		// Already handled.
 |  | 
 | 
											
												
													
														|  | -		// check for the performance-critical read/write
 |  | 
 | 
											
												
													
														|  | -		// commands ASAP.
 |  | 
 | 
											
												
													
														|  | -	}
 |  | 
 | 
											
												
													
														|  | -	else if (command == 0x1C)
 |  | 
 | 
											
												
													
														|  | -	{
 |  | 
 | 
											
												
													
														|  | -		scsiReceiveDiagnostic();
 |  | 
 | 
											
												
													
														|  | -	}
 |  | 
 | 
											
												
													
														|  | -	else if (command == 0x1D)
 |  | 
 | 
											
												
													
														|  | -	{
 |  | 
 | 
											
												
													
														|  | -		scsiSendDiagnostic();
 |  | 
 | 
											
												
													
														|  | -	}
 |  | 
 | 
											
												
													
														|  | -	else if (command == 0x3B)
 |  | 
 | 
											
												
													
														|  | -	{
 |  | 
 | 
											
												
													
														|  | -		scsiWriteBuffer();
 |  | 
 | 
											
												
													
														|  | -	}
 |  | 
 | 
											
												
													
														|  | -	else if (command == 0x0f &&
 |  | 
 | 
											
												
													
														|  | -		scsiDev.target->cfg->quirks == S2S_CFG_QUIRKS_XEBEC)
 |  | 
 | 
											
												
													
														|  | -	{
 |  | 
 | 
											
												
													
														|  | -		scsiWriteSectorBuffer();
 |  | 
 | 
											
												
													
														|  | -	}
 |  | 
 | 
											
												
													
														|  | -	else if (command == 0x3C)
 |  | 
 | 
											
												
													
														|  | -	{
 |  | 
 | 
											
												
													
														|  | -		scsiReadBuffer();
 |  | 
 | 
											
												
													
														|  | -	}
 |  | 
 | 
											
												
													
														|  | -	else if (!scsiModeCommand() && !scsiVendorCommand())
 |  | 
 | 
											
												
													
														|  | -	{
 |  | 
 | 
											
												
													
														|  | -		scsiDev.target->sense.code = ILLEGAL_REQUEST;
 |  | 
 | 
											
												
													
														|  | -		scsiDev.target->sense.asc = INVALID_COMMAND_OPERATION_CODE;
 |  | 
 | 
											
												
													
														|  | -		enter_Status(CHECK_CONDITION);
 |  | 
 | 
											
												
													
														|  | -	}
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -	// Successful
 |  | 
 | 
											
												
													
														|  | -	if (scsiDev.phase == COMMAND) // No status set, and not in DATA_IN
 |  | 
 | 
											
												
													
														|  | -	{
 |  | 
 | 
											
												
													
														|  | -		enter_Status(GOOD);
 |  | 
 | 
											
												
													
														|  | -	}
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -}
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -static void doReserveRelease()
 |  | 
 | 
											
												
													
														|  | -{
 |  | 
 | 
											
												
													
														|  | -	int extentReservation = scsiDev.cdb[1] & 1;
 |  | 
 | 
											
												
													
														|  | -	int thirdPty = scsiDev.cdb[1] & 0x10;
 |  | 
 | 
											
												
													
														|  | -	int thirdPtyId = (scsiDev.cdb[1] >> 1) & 0x7;
 |  | 
 | 
											
												
													
														|  | -	uint8_t command = scsiDev.cdb[0];
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -	int canRelease =
 |  | 
 | 
											
												
													
														|  | -		(!thirdPty && (scsiDev.initiatorId == scsiDev.target->reservedId)) ||
 |  | 
 | 
											
												
													
														|  | -			(thirdPty &&
 |  | 
 | 
											
												
													
														|  | -				(scsiDev.target->reserverId == scsiDev.initiatorId) &&
 |  | 
 | 
											
												
													
														|  | -				(scsiDev.target->reservedId == thirdPtyId)
 |  | 
 | 
											
												
													
														|  | -			);
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -	if (extentReservation)
 |  | 
 | 
											
												
													
														|  | -	{
 |  | 
 | 
											
												
													
														|  | -		// Not supported.
 |  | 
 | 
											
												
													
														|  | -		scsiDev.target->sense.code = ILLEGAL_REQUEST;
 |  | 
 | 
											
												
													
														|  | -		scsiDev.target->sense.asc = INVALID_FIELD_IN_CDB;
 |  | 
 | 
											
												
													
														|  | -		enter_Status(CHECK_CONDITION);
 |  | 
 | 
											
												
													
														|  | -	}
 |  | 
 | 
											
												
													
														|  | -	else if (command == 0x17) // release
 |  | 
 | 
											
												
													
														|  | -	{
 |  | 
 | 
											
												
													
														|  | -		if ((scsiDev.target->reservedId < 0) || canRelease)
 |  | 
 | 
											
												
													
														|  | -		{
 |  | 
 | 
											
												
													
														|  | -			scsiDev.target->reservedId = -1;
 |  | 
 | 
											
												
													
														|  | -			scsiDev.target->reserverId = -1;
 |  | 
 | 
											
												
													
														|  | -		}
 |  | 
 | 
											
												
													
														|  | -		else
 |  | 
 | 
											
												
													
														|  | -		{
 |  | 
 | 
											
												
													
														|  | -			enter_Status(CONFLICT);
 |  | 
 | 
											
												
													
														|  | -		}
 |  | 
 | 
											
												
													
														|  | -	}
 |  | 
 | 
											
												
													
														|  | -	else // assume reserve.
 |  | 
 | 
											
												
													
														|  | -	{
 |  | 
 | 
											
												
													
														|  | -		if ((scsiDev.target->reservedId < 0) || canRelease)
 |  | 
 | 
											
												
													
														|  | -		{
 |  | 
 | 
											
												
													
														|  | -			scsiDev.target->reserverId = scsiDev.initiatorId;
 |  | 
 | 
											
												
													
														|  | -			if (thirdPty)
 |  | 
 | 
											
												
													
														|  | -			{
 |  | 
 | 
											
												
													
														|  | -				scsiDev.target->reservedId = thirdPtyId;
 |  | 
 | 
											
												
													
														|  | -			}
 |  | 
 | 
											
												
													
														|  | -			else
 |  | 
 | 
											
												
													
														|  | -			{
 |  | 
 | 
											
												
													
														|  | -				scsiDev.target->reservedId = scsiDev.initiatorId;
 |  | 
 | 
											
												
													
														|  | -			}
 |  | 
 | 
											
												
													
														|  | -		}
 |  | 
 | 
											
												
													
														|  | -		else
 |  | 
 | 
											
												
													
														|  | -		{
 |  | 
 | 
											
												
													
														|  | -			// Already reserved by someone else!
 |  | 
 | 
											
												
													
														|  | -			enter_Status(CONFLICT);
 |  | 
 | 
											
												
													
														|  | -		}
 |  | 
 | 
											
												
													
														|  | -	}
 |  | 
 | 
											
												
													
														|  | -}
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -static uint32_t resetUntil = 0;
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -static void scsiReset()
 |  | 
 | 
											
												
													
														|  | -{
 |  | 
 | 
											
												
													
														|  | -	scsiDev.rstCount++;
 |  | 
 | 
											
												
													
														|  | -	s2s_ledOff();
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -	scsiPhyReset();
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -	scsiDev.phase = BUS_FREE;
 |  | 
 | 
											
												
													
														|  | -	scsiDev.atnFlag = 0;
 |  | 
 | 
											
												
													
														|  | -	scsiDev.resetFlag = 0;
 |  | 
 | 
											
												
													
														|  | -	scsiDev.selFlag = 0;
 |  | 
 | 
											
												
													
														|  | -	scsiDev.lun = -1;
 |  | 
 | 
											
												
													
														|  | -	scsiDev.compatMode = COMPAT_UNKNOWN;
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -	if (scsiDev.target)
 |  | 
 | 
											
												
													
														|  | -	{
 |  | 
 | 
											
												
													
														|  | -		if (scsiDev.target->unitAttention != POWER_ON_RESET)
 |  | 
 | 
											
												
													
														|  | -		{
 |  | 
 | 
											
												
													
														|  | -			scsiDev.target->unitAttention = SCSI_BUS_RESET;
 |  | 
 | 
											
												
													
														|  | -		}
 |  | 
 | 
											
												
													
														|  | -		scsiDev.target->reservedId = -1;
 |  | 
 | 
											
												
													
														|  | -		scsiDev.target->reserverId = -1;
 |  | 
 | 
											
												
													
														|  | -		scsiDev.target->sense.code = NO_SENSE;
 |  | 
 | 
											
												
													
														|  | -		scsiDev.target->sense.asc = NO_ADDITIONAL_SENSE_INFORMATION;
 |  | 
 | 
											
												
													
														|  | -	}
 |  | 
 | 
											
												
													
														|  | -	scsiDev.target = NULL;
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -	for (int i = 0; i < S2S_MAX_TARGETS; ++i)
 |  | 
 | 
											
												
													
														|  | -	{
 |  | 
 | 
											
												
													
														|  | -		scsiDev.targets[i].syncOffset = 0;
 |  | 
 | 
											
												
													
														|  | -		scsiDev.targets[i].syncPeriod = 0;
 |  | 
 | 
											
												
													
														|  | -	}
 |  | 
 | 
											
												
													
														|  | -	scsiDev.minSyncPeriod = 0;
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -	scsiDiskReset();
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -	scsiDev.postDataOutHook = NULL;
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -	scsiDev.sdUnderrunCount = 0;
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -	// Sleep to allow the bus to settle down a bit.
 |  | 
 | 
											
												
													
														|  | -	// We must be ready again within the "Reset to selection time" of
 |  | 
 | 
											
												
													
														|  | -	// 250ms.
 |  | 
 | 
											
												
													
														|  | -	// There is no guarantee that the RST line will be negated by then.
 |  | 
 | 
											
												
													
														|  | -	// NOTE: We could be connected and powered by USB for configuration,
 |  | 
 | 
											
												
													
														|  | -	// in which case TERMPWR cannot be supplied, and reset will ALWAYS
 |  | 
 | 
											
												
													
														|  | -	// be true. Therefore, the sleep here must be slow to avoid slowing
 |  | 
 | 
											
												
													
														|  | -	// USB comms
 |  | 
 | 
											
												
													
														|  | -	resetUntil = s2s_getTime_ms() + 2; // At least 1ms.
 |  | 
 | 
											
												
													
														|  | -}
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -static void enter_SelectionPhase()
 |  | 
 | 
											
												
													
														|  | -{
 |  | 
 | 
											
												
													
														|  | -	// Ignore stale versions of this flag, but ensure we know the
 |  | 
 | 
											
												
													
														|  | -	// current value if the flag is still set.
 |  | 
 | 
											
												
													
														|  | -	scsiDev.atnFlag = 0;
 |  | 
 | 
											
												
													
														|  | -	scsiDev.dataPtr = 0;
 |  | 
 | 
											
												
													
														|  | -	scsiDev.savedDataPtr = 0;
 |  | 
 | 
											
												
													
														|  | -	scsiDev.dataLen = 0;
 |  | 
 | 
											
												
													
														|  | -	scsiDev.status = GOOD;
 |  | 
 | 
											
												
													
														|  | -	scsiDev.phase = SELECTION;
 |  | 
 | 
											
												
													
														|  | -	scsiDev.lun = -1;
 |  | 
 | 
											
												
													
														|  | -	scsiDev.discPriv = 0;
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -	scsiDev.initiatorId = -1;
 |  | 
 | 
											
												
													
														|  | -	scsiDev.target = NULL;
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -	transfer.blocks = 0;
 |  | 
 | 
											
												
													
														|  | -	transfer.currentBlock = 0;
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -	scsiDev.postDataOutHook = NULL;
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -	scsiDev.needSyncNegotiationAck = 0;
 |  | 
 | 
											
												
													
														|  | -}
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -static void process_SelectionPhase()
 |  | 
 | 
											
												
													
														|  | -{
 |  | 
 | 
											
												
													
														|  | -	// Selection delays.
 |  | 
 | 
											
												
													
														|  | -	// Many SCSI1 samplers that use a 5380 chip need a delay of at least 1ms.
 |  | 
 | 
											
												
													
														|  | -	// The Mac Plus boot-time (ie. rom code) selection abort time
 |  | 
 | 
											
												
													
														|  | -	// is < 1ms and must have no delay (standard suggests 250ms abort time)
 |  | 
 | 
											
												
													
														|  | -	// Most newer SCSI2 hosts don't care either way.
 |  | 
 | 
											
												
													
														|  | -	if (scsiDev.target->cfg->quirks == S2S_CFG_QUIRKS_XEBEC)
 |  | 
 | 
											
												
													
														|  | -	{
 |  | 
 | 
											
												
													
														|  | -		s2s_delay_ms(1); // Simply won't work if set to 0.
 |  | 
 | 
											
												
													
														|  | -	}
 |  | 
 | 
											
												
													
														|  | -	else if (scsiDev.boardCfg.selectionDelay == 255) // auto
 |  | 
 | 
											
												
													
														|  | -	{
 |  | 
 | 
											
												
													
														|  | -		if (scsiDev.compatMode < COMPAT_SCSI2)
 |  | 
 | 
											
												
													
														|  | -		{
 |  | 
 | 
											
												
													
														|  | -			s2s_delay_ms(1);
 |  | 
 | 
											
												
													
														|  | -		}
 |  | 
 | 
											
												
													
														|  | -	}
 |  | 
 | 
											
												
													
														|  | -	else if (scsiDev.boardCfg.selectionDelay != 0)
 |  | 
 | 
											
												
													
														|  | -	{
 |  | 
 | 
											
												
													
														|  | -		s2s_delay_ms(scsiDev.boardCfg.selectionDelay);
 |  | 
 | 
											
												
													
														|  | -	}
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -	uint8_t selStatus = *SCSI_STS_SELECTED;
 |  | 
 | 
											
												
													
														|  | -	if ((selStatus == 0) && (scsiDev.boardCfg.flags & S2S_CFG_ENABLE_SEL_LATCH))
 |  | 
 | 
											
												
													
														|  | -	{
 |  | 
 | 
											
												
													
														|  | -		selStatus = scsiDev.selFlag;
 |  | 
 | 
											
												
													
														|  | -	}
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -	int tgtIndex;
 |  | 
 | 
											
												
													
														|  | -	TargetState* target = NULL;
 |  | 
 | 
											
												
													
														|  | -	for (tgtIndex = 0; tgtIndex < S2S_MAX_TARGETS; ++tgtIndex)
 |  | 
 | 
											
												
													
														|  | -	{
 |  | 
 | 
											
												
													
														|  | -		if (scsiDev.targets[tgtIndex].targetId == (selStatus & 7))
 |  | 
 | 
											
												
													
														|  | -		{
 |  | 
 | 
											
												
													
														|  | -			target = &scsiDev.targets[tgtIndex];
 |  | 
 | 
											
												
													
														|  | -			break;
 |  | 
 | 
											
												
													
														|  | -		}
 |  | 
 | 
											
												
													
														|  | -	}
 |  | 
 | 
											
												
													
														|  | -	if ((target != NULL) && (selStatus & 0x40))
 |  | 
 | 
											
												
													
														|  | -	{
 |  | 
 | 
											
												
													
														|  | -		// We've been selected!
 |  | 
 | 
											
												
													
														|  | -		// Assert BSY - Selection success!
 |  | 
 | 
											
												
													
														|  | -		// must happen within 200us (Selection abort time) of seeing our
 |  | 
 | 
											
												
													
														|  | -		// ID + SEL.
 |  | 
 | 
											
												
													
														|  | -		// (Note: the initiator will be waiting the "Selection time-out delay"
 |  | 
 | 
											
												
													
														|  | -		// for our BSY response, which is actually a very generous 250ms)
 |  | 
 | 
											
												
													
														|  | -		*SCSI_CTRL_BSY = 1;
 |  | 
 | 
											
												
													
														|  | -		s2s_ledOn();
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -		scsiDev.target = target;
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -		// Do we enter MESSAGE OUT immediately ? SCSI 1 and 2 standards says
 |  | 
 | 
											
												
													
														|  | -		// move to MESSAGE OUT if ATN is true before we assert BSY.
 |  | 
 | 
											
												
													
														|  | -		// The initiator should assert ATN with SEL.
 |  | 
 | 
											
												
													
														|  | -		scsiDev.atnFlag = selStatus & 0x80;
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -		// Unit attention breaks many older SCSI hosts. Disable it completely
 |  | 
 | 
											
												
													
														|  | -		// for SCSI-1 (and older) hosts, regardless of our configured setting.
 |  | 
 | 
											
												
													
														|  | -		// Enable the compatability mode also as many SASI and SCSI1
 |  | 
 | 
											
												
													
														|  | -		// controllers don't generate parity bits.
 |  | 
 | 
											
												
													
														|  | -		if (!scsiDev.atnFlag)
 |  | 
 | 
											
												
													
														|  | -		{
 |  | 
 | 
											
												
													
														|  | -			target->unitAttention = 0;
 |  | 
 | 
											
												
													
														|  | -			scsiDev.compatMode = COMPAT_SCSI1;
 |  | 
 | 
											
												
													
														|  | -		}
 |  | 
 | 
											
												
													
														|  | -		else if (!(scsiDev.boardCfg.flags & S2S_CFG_ENABLE_SCSI2))
 |  | 
 | 
											
												
													
														|  | -		{
 |  | 
 | 
											
												
													
														|  | -			scsiDev.compatMode = COMPAT_SCSI2_DISABLED;
 |  | 
 | 
											
												
													
														|  | -		}
 |  | 
 | 
											
												
													
														|  | -		else
 |  | 
 | 
											
												
													
														|  | -		{
 |  | 
 | 
											
												
													
														|  | -			scsiDev.compatMode = COMPAT_SCSI2;
 |  | 
 | 
											
												
													
														|  | -		}
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -		scsiDev.selCount++;
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -		// Save our initiator now that we're no longer in a time-critical
 |  | 
 | 
											
												
													
														|  | -		// section.
 |  | 
 | 
											
												
													
														|  | -		// SCSI1/SASI initiators may not set their own ID.
 |  | 
 | 
											
												
													
														|  | -		scsiDev.initiatorId = (selStatus >> 3) & 0x7;
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -		// Wait until the end of the selection phase.
 |  | 
 | 
											
												
													
														|  | -		uint32_t selTimerBegin = s2s_getTime_ms();
 |  | 
 | 
											
												
													
														|  | -		while (likely(!scsiDev.resetFlag))
 |  | 
 | 
											
												
													
														|  | -		{
 |  | 
 | 
											
												
													
														|  | -			if (!scsiStatusSEL())
 |  | 
 | 
											
												
													
														|  | -			{
 |  | 
 | 
											
												
													
														|  | -				break;
 |  | 
 | 
											
												
													
														|  | -			}
 |  | 
 | 
											
												
													
														|  | -			else if (s2s_elapsedTime_ms(selTimerBegin) >= 10 &&
 |  | 
 | 
											
												
													
														|  | -				scsiDev.target->cfg->quirks == S2S_CFG_QUIRKS_XEBEC)
 |  | 
 | 
											
												
													
														|  | -			{
 |  | 
 | 
											
												
													
														|  | -				// XEBEC hosts may not bother releasing SEL at all until
 |  | 
 | 
											
												
													
														|  | -				// just before the command ends.
 |  | 
 | 
											
												
													
														|  | -				break;
 |  | 
 | 
											
												
													
														|  | -			}
 |  | 
 | 
											
												
													
														|  | -			else if (s2s_elapsedTime_ms(selTimerBegin) >= 250)
 |  | 
 | 
											
												
													
														|  | -			{
 |  | 
 | 
											
												
													
														|  | -				*SCSI_CTRL_BSY = 0;
 |  | 
 | 
											
												
													
														|  | -				scsiDev.resetFlag = 1;
 |  | 
 | 
											
												
													
														|  | -				break;
 |  | 
 | 
											
												
													
														|  | -			}
 |  | 
 | 
											
												
													
														|  | -		}
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -		scsiDev.phase = COMMAND;
 |  | 
 | 
											
												
													
														|  | -	}
 |  | 
 | 
											
												
													
														|  | -	else if (!selStatus)
 |  | 
 | 
											
												
													
														|  | -	{
 |  | 
 | 
											
												
													
														|  | -		scsiDev.phase = BUS_BUSY;
 |  | 
 | 
											
												
													
														|  | -	}
 |  | 
 | 
											
												
													
														|  | -	scsiDev.selFlag = 0;
 |  | 
 | 
											
												
													
														|  | -}
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -static void process_MessageOut()
 |  | 
 | 
											
												
													
														|  | -{
 |  | 
 | 
											
												
													
														|  | -	int wasNeedSyncNegotiationAck = scsiDev.needSyncNegotiationAck;
 |  | 
 | 
											
												
													
														|  | -	scsiDev.needSyncNegotiationAck = 0; // Successful on -most- messages.
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -	scsiEnterPhase(MESSAGE_OUT);
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -	scsiDev.atnFlag = 0;
 |  | 
 | 
											
												
													
														|  | -	scsiDev.msgOut = scsiReadByte();
 |  | 
 | 
											
												
													
														|  | -	scsiDev.msgCount++;
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -	if (scsiParityError() &&
 |  | 
 | 
											
												
													
														|  | -		(scsiDev.boardCfg.flags & S2S_CFG_ENABLE_PARITY))
 |  | 
 | 
											
												
													
														|  | -	{
 |  | 
 | 
											
												
													
														|  | -		// Skip the remaining message bytes, and then start the MESSAGE_OUT
 |  | 
 | 
											
												
													
														|  | -		// phase again from the start. The initiator will re-send the
 |  | 
 | 
											
												
													
														|  | -		// same set of messages.
 |  | 
 | 
											
												
													
														|  | -		while (scsiStatusATN() && !scsiDev.resetFlag)
 |  | 
 | 
											
												
													
														|  | -		{
 |  | 
 | 
											
												
													
														|  | -			scsiReadByte();
 |  | 
 | 
											
												
													
														|  | -		}
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -		// Go-back and try the message again.
 |  | 
 | 
											
												
													
														|  | -		scsiDev.atnFlag = 1;
 |  | 
 | 
											
												
													
														|  | -	}
 |  | 
 | 
											
												
													
														|  | -	else if (scsiDev.msgOut == 0x00)
 |  | 
 | 
											
												
													
														|  | -	{
 |  | 
 | 
											
												
													
														|  | -		// COMMAND COMPLETE. but why would the target be receiving this ? nfi.
 |  | 
 | 
											
												
													
														|  | -		enter_BusFree();
 |  | 
 | 
											
												
													
														|  | -	}
 |  | 
 | 
											
												
													
														|  | -	else if (scsiDev.msgOut == 0x06)
 |  | 
 | 
											
												
													
														|  | -	{
 |  | 
 | 
											
												
													
														|  | -		// ABORT
 |  | 
 | 
											
												
													
														|  | -		scsiDiskReset();
 |  | 
 | 
											
												
													
														|  | -		enter_BusFree();
 |  | 
 | 
											
												
													
														|  | -	}
 |  | 
 | 
											
												
													
														|  | -	else if (scsiDev.msgOut == 0x0C)
 |  | 
 | 
											
												
													
														|  | -	{
 |  | 
 | 
											
												
													
														|  | -		// BUS DEVICE RESET
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -		scsiDiskReset();
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -		scsiDev.target->unitAttention = SCSI_BUS_RESET;
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -		// ANY initiator can reset the reservation state via this message.
 |  | 
 | 
											
												
													
														|  | -		scsiDev.target->reservedId = -1;
 |  | 
 | 
											
												
													
														|  | -		scsiDev.target->reserverId = -1;
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -		// Cancel any sync negotiation
 |  | 
 | 
											
												
													
														|  | -		scsiDev.target->syncOffset = 0;
 |  | 
 | 
											
												
													
														|  | -		scsiDev.target->syncPeriod = 0;
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -		enter_BusFree();
 |  | 
 | 
											
												
													
														|  | -	}
 |  | 
 | 
											
												
													
														|  | -	else if (scsiDev.msgOut == 0x05)
 |  | 
 | 
											
												
													
														|  | -	{
 |  | 
 | 
											
												
													
														|  | -		// Initiate Detected Error
 |  | 
 | 
											
												
													
														|  | -		// Ignore for now
 |  | 
 | 
											
												
													
														|  | -	}
 |  | 
 | 
											
												
													
														|  | -	else if (scsiDev.msgOut == 0x0F)
 |  | 
 | 
											
												
													
														|  | -	{
 |  | 
 | 
											
												
													
														|  | -		// INITIATE RECOVERY
 |  | 
 | 
											
												
													
														|  | -		// Ignore for now
 |  | 
 | 
											
												
													
														|  | -	}
 |  | 
 | 
											
												
													
														|  | -	else if (scsiDev.msgOut == 0x10)
 |  | 
 | 
											
												
													
														|  | -	{
 |  | 
 | 
											
												
													
														|  | -		// RELEASE RECOVERY
 |  | 
 | 
											
												
													
														|  | -		// Ignore for now
 |  | 
 | 
											
												
													
														|  | -		enter_BusFree();
 |  | 
 | 
											
												
													
														|  | -	}
 |  | 
 | 
											
												
													
														|  | -	else if (scsiDev.msgOut == MSG_REJECT)
 |  | 
 | 
											
												
													
														|  | -	{
 |  | 
 | 
											
												
													
														|  | -		// Message Reject
 |  | 
 | 
											
												
													
														|  | -		// Oh well.
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -		if (wasNeedSyncNegotiationAck)
 |  | 
 | 
											
												
													
														|  | -		{
 |  | 
 | 
											
												
													
														|  | -			scsiDev.target->syncOffset = 0;
 |  | 
 | 
											
												
													
														|  | -			scsiDev.target->syncPeriod = 0;
 |  | 
 | 
											
												
													
														|  | -		}
 |  | 
 | 
											
												
													
														|  | -	}
 |  | 
 | 
											
												
													
														|  | -	else if (scsiDev.msgOut == 0x08)
 |  | 
 | 
											
												
													
														|  | -	{
 |  | 
 | 
											
												
													
														|  | -		// NOP
 |  | 
 | 
											
												
													
														|  | -	}
 |  | 
 | 
											
												
													
														|  | -	else if (scsiDev.msgOut == 0x09)
 |  | 
 | 
											
												
													
														|  | -	{
 |  | 
 | 
											
												
													
														|  | -		// Message Parity Error
 |  | 
 | 
											
												
													
														|  | -		// Go back and re-send the last message.
 |  | 
 | 
											
												
													
														|  | -		scsiDev.phase = MESSAGE_IN;
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -		if (wasNeedSyncNegotiationAck)
 |  | 
 | 
											
												
													
														|  | -		{
 |  | 
 | 
											
												
													
														|  | -			scsiDev.target->syncOffset = 0;
 |  | 
 | 
											
												
													
														|  | -			scsiDev.target->syncPeriod = 0;
 |  | 
 | 
											
												
													
														|  | -		}
 |  | 
 | 
											
												
													
														|  | -	}
 |  | 
 | 
											
												
													
														|  | -	else if (scsiDev.msgOut & 0x80) // 0x80 -> 0xFF
 |  | 
 | 
											
												
													
														|  | -	{
 |  | 
 | 
											
												
													
														|  | -		// IDENTIFY
 |  | 
 | 
											
												
													
														|  | -		if ((scsiDev.msgOut & 0x18) || // Reserved bits set.
 |  | 
 | 
											
												
													
														|  | -			(scsiDev.msgOut & 0x20))  // We don't have any target routines!
 |  | 
 | 
											
												
													
														|  | -		{
 |  | 
 | 
											
												
													
														|  | -			messageReject();
 |  | 
 | 
											
												
													
														|  | -		}
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -		scsiDev.lun = scsiDev.msgOut & 0x7;
 |  | 
 | 
											
												
													
														|  | -		scsiDev.discPriv = 
 |  | 
 | 
											
												
													
														|  | -			((scsiDev.msgOut & 0x40) && (scsiDev.initiatorId >= 0))
 |  | 
 | 
											
												
													
														|  | -				? 1 : 0;
 |  | 
 | 
											
												
													
														|  | -	}
 |  | 
 | 
											
												
													
														|  | -	else if (scsiDev.msgOut >= 0x20 && scsiDev.msgOut <= 0x2F)
 |  | 
 | 
											
												
													
														|  | -	{
 |  | 
 | 
											
												
													
														|  | -		// Two byte message. We don't support these. read and discard.
 |  | 
 | 
											
												
													
														|  | -		scsiReadByte();
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -		if (scsiDev.msgOut == 0x23) {
 |  | 
 | 
											
												
													
														|  | -			// Ignore Wide Residue. We're only 8 bit anyway.
 |  | 
 | 
											
												
													
														|  | -		} else {
 |  | 
 | 
											
												
													
														|  | -			messageReject();
 |  | 
 | 
											
												
													
														|  | -		}
 |  | 
 | 
											
												
													
														|  | -	}
 |  | 
 | 
											
												
													
														|  | -	else if (scsiDev.msgOut == 0x01)
 |  | 
 | 
											
												
													
														|  | -	{
 |  | 
 | 
											
												
													
														|  | -		int i;
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -		// Extended message.
 |  | 
 | 
											
												
													
														|  | -		int msgLen = scsiReadByte();
 |  | 
 | 
											
												
													
														|  | -		if (msgLen == 0) msgLen = 256;
 |  | 
 | 
											
												
													
														|  | -		uint8_t extmsg[256];
 |  | 
 | 
											
												
													
														|  | -		for (i = 0; i < msgLen && !scsiDev.resetFlag; ++i)
 |  | 
 | 
											
												
													
														|  | -		{
 |  | 
 | 
											
												
													
														|  | -			// Discard bytes.
 |  | 
 | 
											
												
													
														|  | -			extmsg[i] = scsiReadByte();
 |  | 
 | 
											
												
													
														|  | -		}
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -		if (extmsg[0] == 3 && msgLen == 2) // Wide Data Request
 |  | 
 | 
											
												
													
														|  | -		{
 |  | 
 | 
											
												
													
														|  | -			// Negotiate down to 8bit
 |  | 
 | 
											
												
													
														|  | -			scsiEnterPhase(MESSAGE_IN);
 |  | 
 | 
											
												
													
														|  | -			static const uint8_t WDTR[] = {0x01, 0x02, 0x03, 0x00};
 |  | 
 | 
											
												
													
														|  | -			scsiWrite(WDTR, sizeof(WDTR));
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -			// SDTR becomes invalidated.
 |  | 
 | 
											
												
													
														|  | -			scsiDev.target->syncOffset = 0;
 |  | 
 | 
											
												
													
														|  | -			scsiDev.target->syncPeriod = 0;
 |  | 
 | 
											
												
													
														|  | -		}
 |  | 
 | 
											
												
													
														|  | -		else if (extmsg[0] == 1 && msgLen == 3) // Synchronous data request
 |  | 
 | 
											
												
													
														|  | -		{
 |  | 
 | 
											
												
													
														|  | -			int oldPeriod = scsiDev.target->syncPeriod;
 |  | 
 | 
											
												
													
														|  | -			int oldOffset = scsiDev.target->syncOffset;
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -			int transferPeriod = extmsg[1];
 |  | 
 | 
											
												
													
														|  | -			int offset = extmsg[2];
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -			if ((
 |  | 
 | 
											
												
													
														|  | -					(transferPeriod > 0) &&
 |  | 
 | 
											
												
													
														|  | -					(transferPeriod < scsiDev.minSyncPeriod)) ||
 |  | 
 | 
											
												
													
														|  | -				(scsiDev.minSyncPeriod == 0))
 |  | 
 | 
											
												
													
														|  | -			{
 |  | 
 | 
											
												
													
														|  | -				scsiDev.minSyncPeriod = transferPeriod;
 |  | 
 | 
											
												
													
														|  | -			}
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -			if ((transferPeriod > 80) || // 320ns, 3.125MB/s
 |  | 
 | 
											
												
													
														|  | -				// Amiga A590 (WD33C93 chip) only does 3.5MB/s sync
 |  | 
 | 
											
												
													
														|  | -				// After 80 we start to run out of bits in the fpga timing
 |  | 
 | 
											
												
													
														|  | -				// register.
 |  | 
 | 
											
												
													
														|  | -				(transferPeriod == 0) ||
 |  | 
 | 
											
												
													
														|  | -				(offset == 0) ||
 |  | 
 | 
											
												
													
														|  | -				((scsiDev.boardCfg.scsiSpeed != S2S_CFG_SPEED_NoLimit) &&
 |  | 
 | 
											
												
													
														|  | -					(scsiDev.boardCfg.scsiSpeed <= S2S_CFG_SPEED_ASYNC_50)))
 |  | 
 | 
											
												
													
														|  | -			{
 |  | 
 | 
											
												
													
														|  | -				scsiDev.target->syncOffset = 0;
 |  | 
 | 
											
												
													
														|  | -				scsiDev.target->syncPeriod = 0;
 |  | 
 | 
											
												
													
														|  | -			} else {
 |  | 
 | 
											
												
													
														|  | -				scsiDev.target->syncOffset = offset <= 15 ? offset : 15;
 |  | 
 | 
											
												
													
														|  | -				// FAST20 / 50ns / 20MHz is disabled for now due to
 |  | 
 | 
											
												
													
														|  | -				// data corruption while reading data. We can count the
 |  | 
 | 
											
												
													
														|  | -				// ACK's correctly, but can't save the data to a register
 |  | 
 | 
											
												
													
														|  | -				// before it changes. (ie. transferPeriod == 12)
 |  | 
 | 
											
												
													
														|  | -				if ((scsiDev.boardCfg.scsiSpeed == S2S_CFG_SPEED_TURBO) &&
 |  | 
 | 
											
												
													
														|  | -					(transferPeriod <= 16))
 |  | 
 | 
											
												
													
														|  | -				{
 |  | 
 | 
											
												
													
														|  | -					scsiDev.target->syncPeriod = 16; // 15.6MB/s
 |  | 
 | 
											
												
													
														|  | -				}
 |  | 
 | 
											
												
													
														|  | -				else if (scsiDev.boardCfg.scsiSpeed == S2S_CFG_SPEED_TURBO)
 |  | 
 | 
											
												
													
														|  | -				{
 |  | 
 | 
											
												
													
														|  | -					scsiDev.target->syncPeriod = transferPeriod;
 |  | 
 | 
											
												
													
														|  | -				}
 |  | 
 | 
											
												
													
														|  | -				else if (transferPeriod <= 25 &&
 |  | 
 | 
											
												
													
														|  | -					((scsiDev.boardCfg.scsiSpeed == S2S_CFG_SPEED_NoLimit) ||
 |  | 
 | 
											
												
													
														|  | -						(scsiDev.boardCfg.scsiSpeed >= S2S_CFG_SPEED_SYNC_10)))
 |  | 
 | 
											
												
													
														|  | -				{
 |  | 
 | 
											
												
													
														|  | -					scsiDev.target->syncPeriod = 25; // 100ns, 10MB/s
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -				} else if (transferPeriod < 50 &&
 |  | 
 | 
											
												
													
														|  | -					((scsiDev.boardCfg.scsiSpeed == S2S_CFG_SPEED_NoLimit) ||
 |  | 
 | 
											
												
													
														|  | -						(scsiDev.boardCfg.scsiSpeed >= S2S_CFG_SPEED_SYNC_10)))
 |  | 
 | 
											
												
													
														|  | -				{
 |  | 
 | 
											
												
													
														|  | -					scsiDev.target->syncPeriod = transferPeriod;
 |  | 
 | 
											
												
													
														|  | -				} else if (transferPeriod >= 50)
 |  | 
 | 
											
												
													
														|  | -				{
 |  | 
 | 
											
												
													
														|  | -					scsiDev.target->syncPeriod = transferPeriod;
 |  | 
 | 
											
												
													
														|  | -				} else {
 |  | 
 | 
											
												
													
														|  | -					scsiDev.target->syncPeriod = 50;
 |  | 
 | 
											
												
													
														|  | -				}
 |  | 
 | 
											
												
													
														|  | -			}
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -			if (transferPeriod != oldPeriod ||
 |  | 
 | 
											
												
													
														|  | -				scsiDev.target->syncPeriod != oldPeriod ||
 |  | 
 | 
											
												
													
														|  | -				offset != oldOffset ||
 |  | 
 | 
											
												
													
														|  | -				scsiDev.target->syncOffset != oldOffset ||
 |  | 
 | 
											
												
													
														|  | -				!wasNeedSyncNegotiationAck) // Don't get into infinite loops negotiating.
 |  | 
 | 
											
												
													
														|  | -			{
 |  | 
 | 
											
												
													
														|  | -				scsiEnterPhase(MESSAGE_IN);
 |  | 
 | 
											
												
													
														|  | -				uint8_t SDTR[] = {0x01, 0x03, 0x01, scsiDev.target->syncPeriod, scsiDev.target->syncOffset};
 |  | 
 | 
											
												
													
														|  | -				scsiWrite(SDTR, sizeof(SDTR));
 |  | 
 | 
											
												
													
														|  | -				scsiDev.needSyncNegotiationAck = 1; // Check if this message is rejected.
 |  | 
 | 
											
												
													
														|  | -				scsiDev.sdUnderrunCount = 0;  // reset counter, may work now.
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -				// Set to the theoretical speed, then adjust if we measure lower
 |  | 
 | 
											
												
													
														|  | -				// actual speeds.
 |  | 
 | 
											
												
													
														|  | -				scsiDev.hostSpeedKBs = s2s_getScsiRateKBs();
 |  | 
 | 
											
												
													
														|  | -				scsiDev.hostSpeedMeasured = 0;
 |  | 
 | 
											
												
													
														|  | -			}
 |  | 
 | 
											
												
													
														|  | -		}
 |  | 
 | 
											
												
													
														|  | -		else
 |  | 
 | 
											
												
													
														|  | -		{
 |  | 
 | 
											
												
													
														|  | -			// Not supported
 |  | 
 | 
											
												
													
														|  | -			messageReject();
 |  | 
 | 
											
												
													
														|  | -		}
 |  | 
 | 
											
												
													
														|  | -	}
 |  | 
 | 
											
												
													
														|  | -	else
 |  | 
 | 
											
												
													
														|  | -	{
 |  | 
 | 
											
												
													
														|  | -		messageReject();
 |  | 
 | 
											
												
													
														|  | -	}
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -	// Re-check the ATN flag in case it stays asserted.
 |  | 
 | 
											
												
													
														|  | -	scsiDev.atnFlag |= scsiStatusATN();
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -	if (!scsiDev.atnFlag)
 |  | 
 | 
											
												
													
														|  | -	{
 |  | 
 | 
											
												
													
														|  | -		// Message wasn't rejected!
 |  | 
 | 
											
												
													
														|  | -		scsiDev.needSyncNegotiationAck = 0;
 |  | 
 | 
											
												
													
														|  | -	}
 |  | 
 | 
											
												
													
														|  | -}
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -void scsiPoll(void)
 |  | 
 | 
											
												
													
														|  | -{
 |  | 
 | 
											
												
													
														|  | -	if (resetUntil != 0 && resetUntil > s2s_getTime_ms())
 |  | 
 | 
											
												
													
														|  | -	{
 |  | 
 | 
											
												
													
														|  | -		return;
 |  | 
 | 
											
												
													
														|  | -	}
 |  | 
 | 
											
												
													
														|  | -	resetUntil = 0;
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -	if (unlikely(scsiDev.resetFlag))
 |  | 
 | 
											
												
													
														|  | -	{
 |  | 
 | 
											
												
													
														|  | -		scsiReset();
 |  | 
 | 
											
												
													
														|  | -		// Still in reset phase for a few ms.
 |  | 
 | 
											
												
													
														|  | -		// Do not try and process any commands.
 |  | 
 | 
											
												
													
														|  | -		return;
 |  | 
 | 
											
												
													
														|  | -	}
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -	switch (scsiDev.phase)
 |  | 
 | 
											
												
													
														|  | -	{
 |  | 
 | 
											
												
													
														|  | -	case BUS_FREE:
 |  | 
 | 
											
												
													
														|  | -		if (scsiStatusBSY())
 |  | 
 | 
											
												
													
														|  | -		{
 |  | 
 | 
											
												
													
														|  | -			scsiDev.phase = BUS_BUSY;
 |  | 
 | 
											
												
													
														|  | -		}
 |  | 
 | 
											
												
													
														|  | -		// The Arbitration phase is optional for SCSI1/SASI hosts if there is only
 |  | 
 | 
											
												
													
														|  | -		// one initiator in the chain. Support this by moving
 |  | 
 | 
											
												
													
														|  | -		// straight to selection if SEL is asserted.
 |  | 
 | 
											
												
													
														|  | -		// ie. the initiator won't assert BSY and it's own ID before moving to selection.
 |  | 
 | 
											
												
													
														|  | -		else if (scsiDev.selFlag || *SCSI_STS_SELECTED)
 |  | 
 | 
											
												
													
														|  | -		{
 |  | 
 | 
											
												
													
														|  | -			enter_SelectionPhase();
 |  | 
 | 
											
												
													
														|  | -		}
 |  | 
 | 
											
												
													
														|  | -	break;
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -	case BUS_BUSY:
 |  | 
 | 
											
												
													
														|  | -		// Someone is using the bus. Perhaps they are trying to
 |  | 
 | 
											
												
													
														|  | -		// select us.
 |  | 
 | 
											
												
													
														|  | -		if (scsiDev.selFlag || *SCSI_STS_SELECTED)
 |  | 
 | 
											
												
													
														|  | -		{
 |  | 
 | 
											
												
													
														|  | -			enter_SelectionPhase();
 |  | 
 | 
											
												
													
														|  | -		}
 |  | 
 | 
											
												
													
														|  | -		else if (!scsiStatusBSY())
 |  | 
 | 
											
												
													
														|  | -		{
 |  | 
 | 
											
												
													
														|  | -			scsiDev.phase = BUS_FREE;
 |  | 
 | 
											
												
													
														|  | -		}
 |  | 
 | 
											
												
													
														|  | -	break;
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -	case ARBITRATION:
 |  | 
 | 
											
												
													
														|  | -		// TODO Support reselection.
 |  | 
 | 
											
												
													
														|  | -		break;
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -	case SELECTION:
 |  | 
 | 
											
												
													
														|  | -		process_SelectionPhase();
 |  | 
 | 
											
												
													
														|  | -	break;
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -	case RESELECTION:
 |  | 
 | 
											
												
													
														|  | -		// Not currently supported!
 |  | 
 | 
											
												
													
														|  | -	break;
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -	case COMMAND:
 |  | 
 | 
											
												
													
														|  | -		// Do not check ATN here. SCSI 1 & 2 initiators must set ATN
 |  | 
 | 
											
												
													
														|  | -		// and SEL together upon entering the selection phase if they
 |  | 
 | 
											
												
													
														|  | -		// want to send a message (IDENTIFY) immediately.
 |  | 
 | 
											
												
													
														|  | -		if (scsiDev.atnFlag)
 |  | 
 | 
											
												
													
														|  | -		{
 |  | 
 | 
											
												
													
														|  | -			process_MessageOut();
 |  | 
 | 
											
												
													
														|  | -		}
 |  | 
 | 
											
												
													
														|  | -		else
 |  | 
 | 
											
												
													
														|  | -		{
 |  | 
 | 
											
												
													
														|  | -			process_Command();
 |  | 
 | 
											
												
													
														|  | -		}
 |  | 
 | 
											
												
													
														|  | -	break;
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -	case DATA_IN:
 |  | 
 | 
											
												
													
														|  | -		scsiDev.atnFlag |= scsiStatusATN();
 |  | 
 | 
											
												
													
														|  | -		if (scsiDev.atnFlag)
 |  | 
 | 
											
												
													
														|  | -		{
 |  | 
 | 
											
												
													
														|  | -			process_MessageOut();
 |  | 
 | 
											
												
													
														|  | -		}
 |  | 
 | 
											
												
													
														|  | -		else
 |  | 
 | 
											
												
													
														|  | -		{
 |  | 
 | 
											
												
													
														|  | -			process_DataIn();
 |  | 
 | 
											
												
													
														|  | -		}
 |  | 
 | 
											
												
													
														|  | -	break;
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -	case DATA_OUT:
 |  | 
 | 
											
												
													
														|  | -		scsiDev.atnFlag |= scsiStatusATN();
 |  | 
 | 
											
												
													
														|  | -		if (scsiDev.atnFlag)
 |  | 
 | 
											
												
													
														|  | -		{
 |  | 
 | 
											
												
													
														|  | -			process_MessageOut();
 |  | 
 | 
											
												
													
														|  | -		}
 |  | 
 | 
											
												
													
														|  | -		else
 |  | 
 | 
											
												
													
														|  | -		{
 |  | 
 | 
											
												
													
														|  | -			process_DataOut();
 |  | 
 | 
											
												
													
														|  | -		}
 |  | 
 | 
											
												
													
														|  | -	break;
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -	case STATUS:
 |  | 
 | 
											
												
													
														|  | -		scsiDev.atnFlag |= scsiStatusATN();
 |  | 
 | 
											
												
													
														|  | -		if (scsiDev.atnFlag)
 |  | 
 | 
											
												
													
														|  | -		{
 |  | 
 | 
											
												
													
														|  | -			process_MessageOut();
 |  | 
 | 
											
												
													
														|  | -		}
 |  | 
 | 
											
												
													
														|  | -		else
 |  | 
 | 
											
												
													
														|  | -		{
 |  | 
 | 
											
												
													
														|  | -			process_Status();
 |  | 
 | 
											
												
													
														|  | -		}
 |  | 
 | 
											
												
													
														|  | -	break;
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -	case MESSAGE_IN:
 |  | 
 | 
											
												
													
														|  | -		scsiDev.atnFlag |= scsiStatusATN();
 |  | 
 | 
											
												
													
														|  | -		if (scsiDev.atnFlag)
 |  | 
 | 
											
												
													
														|  | -		{
 |  | 
 | 
											
												
													
														|  | -			process_MessageOut();
 |  | 
 | 
											
												
													
														|  | -		}
 |  | 
 | 
											
												
													
														|  | -		else
 |  | 
 | 
											
												
													
														|  | -		{
 |  | 
 | 
											
												
													
														|  | -			process_MessageIn(1);
 |  | 
 | 
											
												
													
														|  | -		}
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -	break;
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -	case MESSAGE_OUT:
 |  | 
 | 
											
												
													
														|  | -		process_MessageOut();
 |  | 
 | 
											
												
													
														|  | -	break;
 |  | 
 | 
											
												
													
														|  | -	}
 |  | 
 | 
											
												
													
														|  | -}
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -void scsiInit()
 |  | 
 | 
											
												
													
														|  | -{
 |  | 
 | 
											
												
													
														|  | -	static int firstInit = 1;
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -	scsiDev.atnFlag = 0;
 |  | 
 | 
											
												
													
														|  | -	scsiDev.resetFlag = 1;
 |  | 
 | 
											
												
													
														|  | -	scsiDev.selFlag = 0;
 |  | 
 | 
											
												
													
														|  | -	scsiDev.phase = BUS_FREE;
 |  | 
 | 
											
												
													
														|  | -	scsiDev.target = NULL;
 |  | 
 | 
											
												
													
														|  | -	scsiDev.compatMode = COMPAT_UNKNOWN;
 |  | 
 | 
											
												
													
														|  | -	scsiDev.hostSpeedKBs = 0;
 |  | 
 | 
											
												
													
														|  | -	scsiDev.hostSpeedMeasured = 0;
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -	int i;
 |  | 
 | 
											
												
													
														|  | -	for (i = 0; i < S2S_MAX_TARGETS; ++i)
 |  | 
 | 
											
												
													
														|  | -	{
 |  | 
 | 
											
												
													
														|  | -		const S2S_TargetCfg* cfg = s2s_getConfigByIndex(i);
 |  | 
 | 
											
												
													
														|  | -		if (cfg && (cfg->scsiId & S2S_CFG_TARGET_ENABLED))
 |  | 
 | 
											
												
													
														|  | -		{
 |  | 
 | 
											
												
													
														|  | -			scsiDev.targets[i].targetId = cfg->scsiId & S2S_CFG_TARGET_ID_BITS;
 |  | 
 | 
											
												
													
														|  | -			scsiDev.targets[i].cfg = cfg;
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -			scsiDev.targets[i].liveCfg.bytesPerSector = cfg->bytesPerSector;
 |  | 
 | 
											
												
													
														|  | -		}
 |  | 
 | 
											
												
													
														|  | -		else
 |  | 
 | 
											
												
													
														|  | -		{
 |  | 
 | 
											
												
													
														|  | -			scsiDev.targets[i].targetId = 0xff;
 |  | 
 | 
											
												
													
														|  | -			scsiDev.targets[i].cfg = NULL;
 |  | 
 | 
											
												
													
														|  | -		}
 |  | 
 | 
											
												
													
														|  | -		scsiDev.targets[i].reservedId = -1;
 |  | 
 | 
											
												
													
														|  | -		scsiDev.targets[i].reserverId = -1;
 |  | 
 | 
											
												
													
														|  | -		if (firstInit)
 |  | 
 | 
											
												
													
														|  | -		{
 |  | 
 | 
											
												
													
														|  | -			scsiDev.targets[i].unitAttention = POWER_ON_RESET;
 |  | 
 | 
											
												
													
														|  | -		}
 |  | 
 | 
											
												
													
														|  | -		else
 |  | 
 | 
											
												
													
														|  | -		{
 |  | 
 | 
											
												
													
														|  | -			scsiDev.targets[i].unitAttention = PARAMETERS_CHANGED;
 |  | 
 | 
											
												
													
														|  | -		}
 |  | 
 | 
											
												
													
														|  | -		scsiDev.targets[i].sense.code = NO_SENSE;
 |  | 
 | 
											
												
													
														|  | -		scsiDev.targets[i].sense.asc = NO_ADDITIONAL_SENSE_INFORMATION;
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -		scsiDev.targets[i].syncOffset = 0;
 |  | 
 | 
											
												
													
														|  | -		scsiDev.targets[i].syncPeriod = 0;
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -		// Always "start" the device. Many systems (eg. Apple System 7)
 |  | 
 | 
											
												
													
														|  | -		// won't respond properly to
 |  | 
 | 
											
												
													
														|  | -		// LOGICAL_UNIT_NOT_READY_INITIALIZING_COMMAND_REQUIRED sense
 |  | 
 | 
											
												
													
														|  | -		// code
 |  | 
 | 
											
												
													
														|  | -		scsiDev.targets[i].started = 1;
 |  | 
 | 
											
												
													
														|  | -	}
 |  | 
 | 
											
												
													
														|  | -	firstInit = 0;
 |  | 
 | 
											
												
													
														|  | -}
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -/* TODO REENABLE
 |  | 
 | 
											
												
													
														|  | -void scsiDisconnect()
 |  | 
 | 
											
												
													
														|  | -{
 |  | 
 | 
											
												
													
														|  | -	scsiEnterPhase(MESSAGE_IN);
 |  | 
 | 
											
												
													
														|  | -	scsiWriteByte(0x02); // save data pointer
 |  | 
 | 
											
												
													
														|  | -	scsiWriteByte(0x04); // disconnect msg.
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -	// For now, the caller is responsible for tracking the disconnected
 |  | 
 | 
											
												
													
														|  | -	// state, and calling scsiReconnect.
 |  | 
 | 
											
												
													
														|  | -	// Ideally the client would exit their loop and we'd implement this
 |  | 
 | 
											
												
													
														|  | -	// as part of scsiPoll
 |  | 
 | 
											
												
													
														|  | -	int phase = scsiDev.phase;
 |  | 
 | 
											
												
													
														|  | -	enter_BusFree();
 |  | 
 | 
											
												
													
														|  | -	scsiDev.phase = phase;
 |  | 
 | 
											
												
													
														|  | -}
 |  | 
 | 
											
												
													
														|  | -*/
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -/* TODO REENABLE
 |  | 
 | 
											
												
													
														|  | -int scsiReconnect()
 |  | 
 | 
											
												
													
														|  | -{
 |  | 
 | 
											
												
													
														|  | -	int reconnected = 0;
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -	int sel = SCSI_ReadFilt(SCSI_Filt_SEL);
 |  | 
 | 
											
												
													
														|  | -	int bsy = SCSI_ReadFilt(SCSI_Filt_BSY);
 |  | 
 | 
											
												
													
														|  | -	if (!sel && !bsy)
 |  | 
 | 
											
												
													
														|  | -	{
 |  | 
 | 
											
												
													
														|  | -		s2s_delay_us(1);
 |  | 
 | 
											
												
													
														|  | -		sel = SCSI_ReadFilt(SCSI_Filt_SEL);
 |  | 
 | 
											
												
													
														|  | -		bsy = SCSI_ReadFilt(SCSI_Filt_BSY);
 |  | 
 | 
											
												
													
														|  | -	}
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -	if (!sel && !bsy)
 |  | 
 | 
											
												
													
														|  | -	{
 |  | 
 | 
											
												
													
														|  | -		// Arbitrate.
 |  | 
 | 
											
												
													
														|  | -		s2s_ledOn();
 |  | 
 | 
											
												
													
														|  | -		uint8_t scsiIdMask = 1 << scsiDev.target->targetId;
 |  | 
 | 
											
												
													
														|  | -		SCSI_Out_Bits_Write(scsiIdMask);
 |  | 
 | 
											
												
													
														|  | -		SCSI_Out_Ctl_Write(1); // Write bits manually.
 |  | 
 | 
											
												
													
														|  | -		SCSI_SetPin(SCSI_Out_BSY);
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -		s2s_delay_us(3); // arbitrate delay. 2.4us.
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -		uint8_t dbx = scsiReadDBxPins();
 |  | 
 | 
											
												
													
														|  | -		sel = SCSI_ReadFilt(SCSI_Filt_SEL);
 |  | 
 | 
											
												
													
														|  | -		if (sel || ((dbx ^ scsiIdMask) > scsiIdMask))
 |  | 
 | 
											
												
													
														|  | -		{
 |  | 
 | 
											
												
													
														|  | -			// Lost arbitration.
 |  | 
 | 
											
												
													
														|  | -			SCSI_Out_Ctl_Write(0);
 |  | 
 | 
											
												
													
														|  | -			SCSI_ClearPin(SCSI_Out_BSY);
 |  | 
 | 
											
												
													
														|  | -			s2s_ledOff();
 |  | 
 | 
											
												
													
														|  | -		}
 |  | 
 | 
											
												
													
														|  | -		else
 |  | 
 | 
											
												
													
														|  | -		{
 |  | 
 | 
											
												
													
														|  | -			// Won arbitration
 |  | 
 | 
											
												
													
														|  | -			SCSI_SetPin(SCSI_Out_SEL);
 |  | 
 | 
											
												
													
														|  | -			s2s_delay_us(1); // Bus clear + Bus settle.
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -			// Reselection phase
 |  | 
 | 
											
												
													
														|  | -			SCSI_CTL_PHASE_Write(__scsiphase_io);
 |  | 
 | 
											
												
													
														|  | -			SCSI_Out_Bits_Write(scsiIdMask | (1 << scsiDev.initiatorId));
 |  | 
 | 
											
												
													
														|  | -			scsiDeskewDelay(); // 2 deskew delays
 |  | 
 | 
											
												
													
														|  | -			scsiDeskewDelay(); // 2 deskew delays
 |  | 
 | 
											
												
													
														|  | -			SCSI_ClearPin(SCSI_Out_BSY);
 |  | 
 | 
											
												
													
														|  | -			s2s_delay_us(1);  // Bus Settle Delay
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -			uint32_t waitStart_ms = getTime_ms();
 |  | 
 | 
											
												
													
														|  | -			bsy = SCSI_ReadFilt(SCSI_Filt_BSY);
 |  | 
 | 
											
												
													
														|  | -			// Wait for initiator.
 |  | 
 | 
											
												
													
														|  | -			while (
 |  | 
 | 
											
												
													
														|  | -				!bsy &&
 |  | 
 | 
											
												
													
														|  | -				!scsiDev.resetFlag &&
 |  | 
 | 
											
												
													
														|  | -				(elapsedTime_ms(waitStart_ms) < 250))
 |  | 
 | 
											
												
													
														|  | -			{
 |  | 
 | 
											
												
													
														|  | -				bsy = SCSI_ReadFilt(SCSI_Filt_BSY);
 |  | 
 | 
											
												
													
														|  | -			}
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -			if (bsy)
 |  | 
 | 
											
												
													
														|  | -			{
 |  | 
 | 
											
												
													
														|  | -				SCSI_SetPin(SCSI_Out_BSY);
 |  | 
 | 
											
												
													
														|  | -				scsiDeskewDelay(); // 2 deskew delays
 |  | 
 | 
											
												
													
														|  | -				scsiDeskewDelay(); // 2 deskew delays
 |  | 
 | 
											
												
													
														|  | -				SCSI_ClearPin(SCSI_Out_SEL);
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -				// Prepare for the initial IDENTIFY message.
 |  | 
 | 
											
												
													
														|  | -				SCSI_Out_Ctl_Write(0);
 |  | 
 | 
											
												
													
														|  | -				scsiEnterPhase(MESSAGE_IN);
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -				// Send identify command
 |  | 
 | 
											
												
													
														|  | -				scsiWriteByte(0x80);
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -				scsiEnterPhase(scsiDev.phase);
 |  | 
 | 
											
												
													
														|  | -				reconnected = 1;
 |  | 
 | 
											
												
													
														|  | -			}
 |  | 
 | 
											
												
													
														|  | -			else
 |  | 
 | 
											
												
													
														|  | -			{
 |  | 
 | 
											
												
													
														|  | -				// reselect timeout.
 |  | 
 | 
											
												
													
														|  | -				SCSI_Out_Ctl_Write(0);
 |  | 
 | 
											
												
													
														|  | -				SCSI_ClearPin(SCSI_Out_SEL);
 |  | 
 | 
											
												
													
														|  | -				SCSI_CTL_PHASE_Write(0);
 |  | 
 | 
											
												
													
														|  | -				s2s_ledOff();
 |  | 
 | 
											
												
													
														|  | -			}
 |  | 
 | 
											
												
													
														|  | -		}
 |  | 
 | 
											
												
													
														|  | -	}
 |  | 
 | 
											
												
													
														|  | -	return reconnected;
 |  | 
 | 
											
												
													
														|  | -}
 |  | 
 | 
											
												
													
														|  | -*/
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | 
 |  | +//	Copyright (C) 2014 Michael McMaster <michael@codesrc.com>
 | 
											
												
													
														|  | 
 |  | +//
 | 
											
												
													
														|  | 
 |  | +//	This file is part of SCSI2SD.
 | 
											
												
													
														|  | 
 |  | +//
 | 
											
												
													
														|  | 
 |  | +//	SCSI2SD is free software: you can redistribute it and/or modify
 | 
											
												
													
														|  | 
 |  | +//	it under the terms of the GNU General Public License as published by
 | 
											
												
													
														|  | 
 |  | +//	the Free Software Foundation, either version 3 of the License, or
 | 
											
												
													
														|  | 
 |  | +//	(at your option) any later version.
 | 
											
												
													
														|  | 
 |  | +//
 | 
											
												
													
														|  | 
 |  | +//	SCSI2SD is distributed in the hope that it will be useful,
 | 
											
												
													
														|  | 
 |  | +//	but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
											
												
													
														|  | 
 |  | +//	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
											
												
													
														|  | 
 |  | +//	GNU General Public License for more details.
 | 
											
												
													
														|  | 
 |  | +//
 | 
											
												
													
														|  | 
 |  | +//	You should have received a copy of the GNU General Public License
 | 
											
												
													
														|  | 
 |  | +//	along with SCSI2SD.  If not, see <http://www.gnu.org/licenses/>.
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +#include "scsi.h"
 | 
											
												
													
														|  | 
 |  | +#include "scsiPhy.h"
 | 
											
												
													
														|  | 
 |  | +#include "config.h"
 | 
											
												
													
														|  | 
 |  | +#include "diagnostic.h"
 | 
											
												
													
														|  | 
 |  | +#include "disk.h"
 | 
											
												
													
														|  | 
 |  | +#include "inquiry.h"
 | 
											
												
													
														|  | 
 |  | +#include "led.h"
 | 
											
												
													
														|  | 
 |  | +#include "mode.h"
 | 
											
												
													
														|  | 
 |  | +#include "scsi2sd_time.h"
 | 
											
												
													
														|  | 
 |  | +#include "bsp.h"
 | 
											
												
													
														|  | 
 |  | +#include "cdrom.h"
 | 
											
												
													
														|  | 
 |  | +//#include "debug.h"
 | 
											
												
													
														|  | 
 |  | +#include "tape.h"
 | 
											
												
													
														|  | 
 |  | +#include "mo.h"
 | 
											
												
													
														|  | 
 |  | +#include "vendor.h"
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +#include <string.h>
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +// Global SCSI device state.
 | 
											
												
													
														|  | 
 |  | +ScsiDevice scsiDev S2S_DMA_ALIGN;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +static void enter_SelectionPhase(void);
 | 
											
												
													
														|  | 
 |  | +static void process_SelectionPhase(void);
 | 
											
												
													
														|  | 
 |  | +static void enter_MessageIn(uint8_t message);
 | 
											
												
													
														|  | 
 |  | +static void enter_Status(uint8_t status);
 | 
											
												
													
														|  | 
 |  | +static void enter_DataIn(int len);
 | 
											
												
													
														|  | 
 |  | +static void process_DataIn(void);
 | 
											
												
													
														|  | 
 |  | +static void process_DataOut(void);
 | 
											
												
													
														|  | 
 |  | +static void process_Command(void);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +static void doReserveRelease(void);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +void enter_BusFree()
 | 
											
												
													
														|  | 
 |  | +{
 | 
											
												
													
														|  | 
 |  | +	// This delay probably isn't needed for most SCSI hosts, but it won't
 | 
											
												
													
														|  | 
 |  | +	// hurt either. It's possible some of the samplers needed this delay.
 | 
											
												
													
														|  | 
 |  | +	if (scsiDev.compatMode < COMPAT_SCSI2)
 | 
											
												
													
														|  | 
 |  | +	{
 | 
											
												
													
														|  | 
 |  | +		s2s_delay_us(2);
 | 
											
												
													
														|  | 
 |  | +	}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +#if 0
 | 
											
												
													
														|  | 
 |  | +	if (scsiDev.status != GOOD)// && isDebugEnabled())
 | 
											
												
													
														|  | 
 |  | +	{
 | 
											
												
													
														|  | 
 |  | +		// We want to capture debug information for failure cases.
 | 
											
												
													
														|  | 
 |  | +		s2s_delay_ms(80);
 | 
											
												
													
														|  | 
 |  | +	}
 | 
											
												
													
														|  | 
 |  | +#endif
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +	scsiEnterBusFree();
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +	// Wait for the initiator to cease driving signals
 | 
											
												
													
														|  | 
 |  | +	// Bus settle delay + bus clear delay = 1200ns
 | 
											
												
													
														|  | 
 |  | +    // Just waiting the clear delay is sufficient.
 | 
											
												
													
														|  | 
 |  | +	s2s_delay_ns(800);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +	s2s_ledOff();
 | 
											
												
													
														|  | 
 |  | +	scsiDev.phase = BUS_FREE;
 | 
											
												
													
														|  | 
 |  | +	scsiDev.selFlag = 0;
 | 
											
												
													
														|  | 
 |  | +}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +static void enter_MessageIn(uint8_t message)
 | 
											
												
													
														|  | 
 |  | +{
 | 
											
												
													
														|  | 
 |  | +	scsiDev.msgIn = message;
 | 
											
												
													
														|  | 
 |  | +	scsiDev.phase = MESSAGE_IN;
 | 
											
												
													
														|  | 
 |  | +}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +int process_MessageIn(int releaseBusFree)
 | 
											
												
													
														|  | 
 |  | +{
 | 
											
												
													
														|  | 
 |  | +	scsiEnterPhase(MESSAGE_IN);
 | 
											
												
													
														|  | 
 |  | +	scsiWriteByte(scsiDev.msgIn);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +	if (unlikely(scsiDev.atnFlag))
 | 
											
												
													
														|  | 
 |  | +	{
 | 
											
												
													
														|  | 
 |  | +		// If there was a parity error, we go
 | 
											
												
													
														|  | 
 |  | +		// back to MESSAGE_OUT first, get out parity error message, then come
 | 
											
												
													
														|  | 
 |  | +		// back here.
 | 
											
												
													
														|  | 
 |  | +		return 0;
 | 
											
												
													
														|  | 
 |  | +	}
 | 
											
												
													
														|  | 
 |  | +	else if ((scsiDev.msgIn == MSG_LINKED_COMMAND_COMPLETE) ||
 | 
											
												
													
														|  | 
 |  | +		(scsiDev.msgIn == MSG_LINKED_COMMAND_COMPLETE_WITH_FLAG))
 | 
											
												
													
														|  | 
 |  | +	{
 | 
											
												
													
														|  | 
 |  | +		// Go back to the command phase and start again.
 | 
											
												
													
														|  | 
 |  | +		scsiDev.phase = COMMAND;
 | 
											
												
													
														|  | 
 |  | +		scsiDev.dataPtr = 0;
 | 
											
												
													
														|  | 
 |  | +		scsiDev.savedDataPtr = 0;
 | 
											
												
													
														|  | 
 |  | +		scsiDev.dataLen = 0;
 | 
											
												
													
														|  | 
 |  | +		scsiDev.status = GOOD;
 | 
											
												
													
														|  | 
 |  | +		transfer.blocks = 0;
 | 
											
												
													
														|  | 
 |  | +		transfer.currentBlock = 0;
 | 
											
												
													
														|  | 
 |  | +		return 0;
 | 
											
												
													
														|  | 
 |  | +	}
 | 
											
												
													
														|  | 
 |  | +	else if (releaseBusFree) /*if (scsiDev.msgIn == MSG_COMMAND_COMPLETE)*/
 | 
											
												
													
														|  | 
 |  | +	{
 | 
											
												
													
														|  | 
 |  | +		enter_BusFree();
 | 
											
												
													
														|  | 
 |  | +		return 1;
 | 
											
												
													
														|  | 
 |  | +	}
 | 
											
												
													
														|  | 
 |  | +	else
 | 
											
												
													
														|  | 
 |  | +	{
 | 
											
												
													
														|  | 
 |  | +		return 1;
 | 
											
												
													
														|  | 
 |  | +	}
 | 
											
												
													
														|  | 
 |  | +}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +static void messageReject()
 | 
											
												
													
														|  | 
 |  | +{
 | 
											
												
													
														|  | 
 |  | +	scsiEnterPhase(MESSAGE_IN);
 | 
											
												
													
														|  | 
 |  | +	scsiWriteByte(MSG_REJECT);
 | 
											
												
													
														|  | 
 |  | +}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +static void enter_Status(uint8_t status)
 | 
											
												
													
														|  | 
 |  | +{
 | 
											
												
													
														|  | 
 |  | +	scsiDev.status = status;
 | 
											
												
													
														|  | 
 |  | +	scsiDev.phase = STATUS;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +	scsiDev.lastStatus = scsiDev.status;
 | 
											
												
													
														|  | 
 |  | +	scsiDev.lastSense = scsiDev.target->sense.code;
 | 
											
												
													
														|  | 
 |  | +	scsiDev.lastSenseASC = scsiDev.target->sense.asc;
 | 
											
												
													
														|  | 
 |  | +}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +void process_Status()
 | 
											
												
													
														|  | 
 |  | +{
 | 
											
												
													
														|  | 
 |  | +	scsiEnterPhase(STATUS);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +	uint8_t message;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +	uint8_t control = scsiDev.cdb[scsiDev.cdbLen - 1];
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +	if (scsiDev.target->cfg->quirks == S2S_CFG_QUIRKS_OMTI)
 | 
											
												
													
														|  | 
 |  | +	{
 | 
											
												
													
														|  | 
 |  | +		// All commands have a control byte, except 0xC0
 | 
											
												
													
														|  | 
 |  | +		if (scsiDev.cdb[0] == 0xC0)
 | 
											
												
													
														|  | 
 |  | +		{
 | 
											
												
													
														|  | 
 |  | +			control = 0;
 | 
											
												
													
														|  | 
 |  | +		}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +		// OMTI non-standard LINK control
 | 
											
												
													
														|  | 
 |  | +		if (control & 0x01)
 | 
											
												
													
														|  | 
 |  | +		{
 | 
											
												
													
														|  | 
 |  | +			scsiDev.phase = COMMAND;
 | 
											
												
													
														|  | 
 |  | +			return;
 | 
											
												
													
														|  | 
 |  | +		}
 | 
											
												
													
														|  | 
 |  | +	}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +	if ((scsiDev.status == GOOD) && (control & 0x01) &&
 | 
											
												
													
														|  | 
 |  | +		scsiDev.target->cfg->quirks != S2S_CFG_QUIRKS_XEBEC)
 | 
											
												
													
														|  | 
 |  | +	{
 | 
											
												
													
														|  | 
 |  | +		// Linked command.
 | 
											
												
													
														|  | 
 |  | +		scsiDev.status = INTERMEDIATE;
 | 
											
												
													
														|  | 
 |  | +		if (control & 0x02)
 | 
											
												
													
														|  | 
 |  | +		{
 | 
											
												
													
														|  | 
 |  | +			message = MSG_LINKED_COMMAND_COMPLETE_WITH_FLAG;
 | 
											
												
													
														|  | 
 |  | +		}
 | 
											
												
													
														|  | 
 |  | +		else
 | 
											
												
													
														|  | 
 |  | +		{
 | 
											
												
													
														|  | 
 |  | +			message = MSG_LINKED_COMMAND_COMPLETE;
 | 
											
												
													
														|  | 
 |  | +		}
 | 
											
												
													
														|  | 
 |  | +	}
 | 
											
												
													
														|  | 
 |  | +	else
 | 
											
												
													
														|  | 
 |  | +	{
 | 
											
												
													
														|  | 
 |  | +		message = MSG_COMMAND_COMPLETE;
 | 
											
												
													
														|  | 
 |  | +	}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +	if (scsiDev.target->cfg->quirks == S2S_CFG_QUIRKS_XEBEC)
 | 
											
												
													
														|  | 
 |  | +	{
 | 
											
												
													
														|  | 
 |  | +		// More non-standardness. Expects 2 status bytes (really status + msg)
 | 
											
												
													
														|  | 
 |  | +		// 00 d 000 err 0
 | 
											
												
													
														|  | 
 |  | +		// d == disk number
 | 
											
												
													
														|  | 
 |  | +		// ERR = 1 if error.
 | 
											
												
													
														|  | 
 |  | +		if (scsiDev.status == GOOD)
 | 
											
												
													
														|  | 
 |  | +		{
 | 
											
												
													
														|  | 
 |  | +			scsiWriteByte(scsiDev.cdb[1] & 0x20);
 | 
											
												
													
														|  | 
 |  | +		}
 | 
											
												
													
														|  | 
 |  | +		else
 | 
											
												
													
														|  | 
 |  | +		{
 | 
											
												
													
														|  | 
 |  | +			scsiWriteByte((scsiDev.cdb[1] & 0x20) | 0x2);
 | 
											
												
													
														|  | 
 |  | +		}
 | 
											
												
													
														|  | 
 |  | +		s2s_delay_us(10); // Seems to need a delay before changing phase bits.
 | 
											
												
													
														|  | 
 |  | +	}
 | 
											
												
													
														|  | 
 |  | +	else if (scsiDev.target->cfg->quirks == S2S_CFG_QUIRKS_OMTI)
 | 
											
												
													
														|  | 
 |  | +	{
 | 
											
												
													
														|  | 
 |  | +		scsiDev.status |= (scsiDev.target->targetId & 0x03) << 5;
 | 
											
												
													
														|  | 
 |  | +		scsiWriteByte(scsiDev.status);
 | 
											
												
													
														|  | 
 |  | +	}
 | 
											
												
													
														|  | 
 |  | +	else
 | 
											
												
													
														|  | 
 |  | +	{
 | 
											
												
													
														|  | 
 |  | +		scsiWriteByte(scsiDev.status);
 | 
											
												
													
														|  | 
 |  | +	}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +	scsiDev.lastStatus = scsiDev.status;
 | 
											
												
													
														|  | 
 |  | +	scsiDev.lastSense = scsiDev.target->sense.code;
 | 
											
												
													
														|  | 
 |  | +	scsiDev.lastSenseASC = scsiDev.target->sense.asc;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +	// Command Complete occurs AFTER a valid status has been
 | 
											
												
													
														|  | 
 |  | +	// sent. then we go bus-free.
 | 
											
												
													
														|  | 
 |  | +	enter_MessageIn(message);
 | 
											
												
													
														|  | 
 |  | +}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +static void enter_DataIn(int len)
 | 
											
												
													
														|  | 
 |  | +{
 | 
											
												
													
														|  | 
 |  | +	scsiDev.dataLen = len;
 | 
											
												
													
														|  | 
 |  | +	scsiDev.phase = DATA_IN;
 | 
											
												
													
														|  | 
 |  | +}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +static void process_DataIn()
 | 
											
												
													
														|  | 
 |  | +{
 | 
											
												
													
														|  | 
 |  | +	uint32_t len;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +	if (scsiDev.dataLen > sizeof(scsiDev.data))
 | 
											
												
													
														|  | 
 |  | +	{
 | 
											
												
													
														|  | 
 |  | +		scsiDev.dataLen = sizeof(scsiDev.data);
 | 
											
												
													
														|  | 
 |  | +	}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +	len = scsiDev.dataLen - scsiDev.dataPtr;
 | 
											
												
													
														|  | 
 |  | +	if (len > 0)
 | 
											
												
													
														|  | 
 |  | +	{
 | 
											
												
													
														|  | 
 |  | +		scsiEnterPhase(DATA_IN);
 | 
											
												
													
														|  | 
 |  | +		scsiWrite(scsiDev.data + scsiDev.dataPtr, len);
 | 
											
												
													
														|  | 
 |  | +		scsiDev.dataPtr += len;
 | 
											
												
													
														|  | 
 |  | +	}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +	if ((scsiDev.dataPtr >= scsiDev.dataLen) &&
 | 
											
												
													
														|  | 
 |  | +		(transfer.currentBlock == transfer.blocks))
 | 
											
												
													
														|  | 
 |  | +	{
 | 
											
												
													
														|  | 
 |  | +		enter_Status(GOOD);
 | 
											
												
													
														|  | 
 |  | +	}
 | 
											
												
													
														|  | 
 |  | +}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +static void process_DataOut()
 | 
											
												
													
														|  | 
 |  | +{
 | 
											
												
													
														|  | 
 |  | +	uint32_t len;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +	if (scsiDev.dataLen > sizeof(scsiDev.data))
 | 
											
												
													
														|  | 
 |  | +	{
 | 
											
												
													
														|  | 
 |  | +		scsiDev.dataLen = sizeof(scsiDev.data);
 | 
											
												
													
														|  | 
 |  | +	}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +	len = scsiDev.dataLen - scsiDev.dataPtr;
 | 
											
												
													
														|  | 
 |  | +	if (len > 0)
 | 
											
												
													
														|  | 
 |  | +	{
 | 
											
												
													
														|  | 
 |  | +		scsiEnterPhase(DATA_OUT);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +		int parityError = 0;
 | 
											
												
													
														|  | 
 |  | +		scsiRead(scsiDev.data + scsiDev.dataPtr, len, &parityError);
 | 
											
												
													
														|  | 
 |  | +		scsiDev.dataPtr += len;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +		if (parityError &&
 | 
											
												
													
														|  | 
 |  | +			(scsiDev.boardCfg.flags & S2S_CFG_ENABLE_PARITY))
 | 
											
												
													
														|  | 
 |  | +		{
 | 
											
												
													
														|  | 
 |  | +			scsiDev.target->sense.code = ABORTED_COMMAND;
 | 
											
												
													
														|  | 
 |  | +			scsiDev.target->sense.asc = SCSI_PARITY_ERROR;
 | 
											
												
													
														|  | 
 |  | +			enter_Status(CHECK_CONDITION);
 | 
											
												
													
														|  | 
 |  | +		}
 | 
											
												
													
														|  | 
 |  | +	}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +	if ((scsiDev.dataPtr >= scsiDev.dataLen) &&
 | 
											
												
													
														|  | 
 |  | +		(transfer.currentBlock == transfer.blocks))
 | 
											
												
													
														|  | 
 |  | +	{
 | 
											
												
													
														|  | 
 |  | +		if (scsiDev.postDataOutHook != NULL)
 | 
											
												
													
														|  | 
 |  | +		{
 | 
											
												
													
														|  | 
 |  | +			scsiDev.postDataOutHook();
 | 
											
												
													
														|  | 
 |  | +		}
 | 
											
												
													
														|  | 
 |  | +		else
 | 
											
												
													
														|  | 
 |  | +		{
 | 
											
												
													
														|  | 
 |  | +			enter_Status(GOOD);
 | 
											
												
													
														|  | 
 |  | +		}
 | 
											
												
													
														|  | 
 |  | +	}
 | 
											
												
													
														|  | 
 |  | +}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +static const uint8_t CmdGroupBytes[] = {
 | 
											
												
													
														|  | 
 |  | +	6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
 | 
											
												
													
														|  | 
 |  | +	10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
 | 
											
												
													
														|  | 
 |  | +	10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
 | 
											
												
													
														|  | 
 |  | +	10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
 | 
											
												
													
														|  | 
 |  | +	10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
 | 
											
												
													
														|  | 
 |  | +	10,10,10,10,10,10,10,10,10,10,10,10,10,16,16,16,16,16,16,16,16,
 | 
											
												
													
														|  | 
 |  | +	16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,
 | 
											
												
													
														|  | 
 |  | +	16,16,16,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,
 | 
											
												
													
														|  | 
 |  | +	12,12,12,12,12,12,12,12,12,12,12,12,12,12,10,10,10,10,10,10,10,
 | 
											
												
													
														|  | 
 |  | +	10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
 | 
											
												
													
														|  | 
 |  | +	10,10,10,10,10,10,10,10,10,10,10,10,10,10
 | 
											
												
													
														|  | 
 |  | +};
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +static void process_Command()
 | 
											
												
													
														|  | 
 |  | +{
 | 
											
												
													
														|  | 
 |  | +	uint8_t command;
 | 
											
												
													
														|  | 
 |  | +	uint8_t control;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +	scsiEnterPhase(COMMAND);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +	memset(scsiDev.cdb + 6, 0, sizeof(scsiDev.cdb) - 6);
 | 
											
												
													
														|  | 
 |  | +	int parityError = 0;
 | 
											
												
													
														|  | 
 |  | +	scsiRead(scsiDev.cdb, 6, &parityError);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +	// Handle Atari ST ICD extended commands
 | 
											
												
													
														|  | 
 |  | +	if (scsiDev.cdb[0] == 0x1F)
 | 
											
												
													
														|  | 
 |  | +	{
 | 
											
												
													
														|  | 
 |  | +		scsiDev.cdb[0] = scsiDev.cdb[1];
 | 
											
												
													
														|  | 
 |  | +		scsiDev.cdb[1] = scsiDev.cdb[2];
 | 
											
												
													
														|  | 
 |  | +		scsiDev.cdb[2] = scsiDev.cdb[3];
 | 
											
												
													
														|  | 
 |  | +		scsiDev.cdb[3] = scsiDev.cdb[4];
 | 
											
												
													
														|  | 
 |  | +		scsiDev.cdb[4] = scsiDev.cdb[5];
 | 
											
												
													
														|  | 
 |  | +		scsiDev.cdb[5] = scsiReadByte();
 | 
											
												
													
														|  | 
 |  | +	}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +	scsiDev.cdbLen = CmdGroupBytes[scsiDev.cdb[0]];
 | 
											
												
													
														|  | 
 |  | +	if (parityError &&
 | 
											
												
													
														|  | 
 |  | +		(scsiDev.boardCfg.flags & S2S_CFG_ENABLE_PARITY))
 | 
											
												
													
														|  | 
 |  | +	{
 | 
											
												
													
														|  | 
 |  | +		// Don't try and read more bytes, as we cannot be sure what group
 | 
											
												
													
														|  | 
 |  | +		// the command should be.
 | 
											
												
													
														|  | 
 |  | +	}
 | 
											
												
													
														|  | 
 |  | +	else if (scsiDev.cdbLen - 6 > 0)
 | 
											
												
													
														|  | 
 |  | +	{
 | 
											
												
													
														|  | 
 |  | +		scsiRead(scsiDev.cdb + 6, scsiDev.cdbLen - 6, &parityError);
 | 
											
												
													
														|  | 
 |  | +	}
 | 
											
												
													
														|  | 
 |  | +	command = scsiDev.cdb[0];
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +	// Prefer LUN's set by IDENTIFY messages for newer hosts.
 | 
											
												
													
														|  | 
 |  | +	if (scsiDev.lun < 0)
 | 
											
												
													
														|  | 
 |  | +	{
 | 
											
												
													
														|  | 
 |  | +		if (command == 0xE0 || command == 0xE4) // XEBEC s1410
 | 
											
												
													
														|  | 
 |  | +		{
 | 
											
												
													
														|  | 
 |  | +			scsiDev.lun = 0;
 | 
											
												
													
														|  | 
 |  | +		}
 | 
											
												
													
														|  | 
 |  | +		else
 | 
											
												
													
														|  | 
 |  | +		{
 | 
											
												
													
														|  | 
 |  | +			scsiDev.lun = scsiDev.cdb[1] >> 5;
 | 
											
												
													
														|  | 
 |  | +		}
 | 
											
												
													
														|  | 
 |  | +	}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +	// For Philips P2000C with Xebec S1410 SASI/MFM adapter
 | 
											
												
													
														|  | 
 |  | +	// http://bitsavers.trailing-edge.com/pdf/xebec/104524C_S1410Man_Aug83.pdf
 | 
											
												
													
														|  | 
 |  | +	if ((scsiDev.lun > 0) && (scsiDev.boardCfg.flags & S2S_CFG_MAP_LUNS_TO_IDS))
 | 
											
												
													
														|  | 
 |  | +	{
 | 
											
												
													
														|  | 
 |  | +		int tgtIndex;
 | 
											
												
													
														|  | 
 |  | +		for (tgtIndex = 0; tgtIndex < S2S_MAX_TARGETS; ++tgtIndex)
 | 
											
												
													
														|  | 
 |  | +		{
 | 
											
												
													
														|  | 
 |  | +			if (scsiDev.targets[tgtIndex].targetId == scsiDev.lun)
 | 
											
												
													
														|  | 
 |  | +			{
 | 
											
												
													
														|  | 
 |  | +				scsiDev.target = &scsiDev.targets[tgtIndex];
 | 
											
												
													
														|  | 
 |  | +				scsiDev.lun = 0;
 | 
											
												
													
														|  | 
 |  | +				break;
 | 
											
												
													
														|  | 
 |  | +			}
 | 
											
												
													
														|  | 
 |  | +		}
 | 
											
												
													
														|  | 
 |  | +	}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +	control = scsiDev.cdb[scsiDev.cdbLen - 1];
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +	scsiDev.cmdCount++;
 | 
											
												
													
														|  | 
 |  | +	const S2S_TargetCfg* cfg = scsiDev.target->cfg;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +	if (unlikely(scsiDev.resetFlag))
 | 
											
												
													
														|  | 
 |  | +	{
 | 
											
												
													
														|  | 
 |  | +		// Don't log bogus commands
 | 
											
												
													
														|  | 
 |  | +		scsiDev.cmdCount--;
 | 
											
												
													
														|  | 
 |  | +		memset(scsiDev.cdb, 0xff, sizeof(scsiDev.cdb));
 | 
											
												
													
														|  | 
 |  | +		return;
 | 
											
												
													
														|  | 
 |  | +	}
 | 
											
												
													
														|  | 
 |  | +	else if (parityError &&
 | 
											
												
													
														|  | 
 |  | +		(scsiDev.boardCfg.flags & S2S_CFG_ENABLE_PARITY))
 | 
											
												
													
														|  | 
 |  | +	{
 | 
											
												
													
														|  | 
 |  | +		scsiDev.target->sense.code = ABORTED_COMMAND;
 | 
											
												
													
														|  | 
 |  | +		scsiDev.target->sense.asc = SCSI_PARITY_ERROR;
 | 
											
												
													
														|  | 
 |  | +		enter_Status(CHECK_CONDITION);
 | 
											
												
													
														|  | 
 |  | +	}
 | 
											
												
													
														|  | 
 |  | +	else if ((control & 0x02) && ((control & 0x01) == 0) &&
 | 
											
												
													
														|  | 
 |  | +		// used for head step options on xebec.
 | 
											
												
													
														|  | 
 |  | +		likely(scsiDev.target->cfg->quirks != S2S_CFG_QUIRKS_XEBEC))
 | 
											
												
													
														|  | 
 |  | +	{
 | 
											
												
													
														|  | 
 |  | +		// FLAG set without LINK flag.
 | 
											
												
													
														|  | 
 |  | +		scsiDev.target->sense.code = ILLEGAL_REQUEST;
 | 
											
												
													
														|  | 
 |  | +		scsiDev.target->sense.asc = INVALID_FIELD_IN_CDB;
 | 
											
												
													
														|  | 
 |  | +		enter_Status(CHECK_CONDITION);
 | 
											
												
													
														|  | 
 |  | +	}
 | 
											
												
													
														|  | 
 |  | +	else if (command == 0x12)
 | 
											
												
													
														|  | 
 |  | +	{
 | 
											
												
													
														|  | 
 |  | +		s2s_scsiInquiry();
 | 
											
												
													
														|  | 
 |  | +	}
 | 
											
												
													
														|  | 
 |  | +	else if (command == 0x03)
 | 
											
												
													
														|  | 
 |  | +	{
 | 
											
												
													
														|  | 
 |  | +		// REQUEST SENSE
 | 
											
												
													
														|  | 
 |  | +		uint32_t allocLength = scsiDev.cdb[4];
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +		if (scsiDev.target->cfg->quirks == S2S_CFG_QUIRKS_XEBEC)
 | 
											
												
													
														|  | 
 |  | +		{
 | 
											
												
													
														|  | 
 |  | +			// Completely non-standard
 | 
											
												
													
														|  | 
 |  | +			allocLength = 4;
 | 
											
												
													
														|  | 
 |  | +			if (scsiDev.target->sense.code == NO_SENSE)
 | 
											
												
													
														|  | 
 |  | +				scsiDev.data[0] = 0;
 | 
											
												
													
														|  | 
 |  | +			else if (scsiDev.target->sense.code == ILLEGAL_REQUEST)
 | 
											
												
													
														|  | 
 |  | +				scsiDev.data[0] = 0x20; // Illegal command
 | 
											
												
													
														|  | 
 |  | +			else if (scsiDev.target->sense.code == NOT_READY)
 | 
											
												
													
														|  | 
 |  | +				scsiDev.data[0] = 0x04; // Drive not ready
 | 
											
												
													
														|  | 
 |  | +			else
 | 
											
												
													
														|  | 
 |  | +				scsiDev.data[0] = 0x11;  // Uncorrectable data error
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +			scsiDev.data[1] = (scsiDev.cdb[1] & 0x20) | ((transfer.lba >> 16) & 0x1F);
 | 
											
												
													
														|  | 
 |  | +			scsiDev.data[2] = transfer.lba >> 8;
 | 
											
												
													
														|  | 
 |  | +			scsiDev.data[3] = transfer.lba;
 | 
											
												
													
														|  | 
 |  | +		}
 | 
											
												
													
														|  | 
 |  | +		else if (cfg->quirks == S2S_CFG_QUIRKS_OMTI)
 | 
											
												
													
														|  | 
 |  | +		{
 | 
											
												
													
														|  | 
 |  | +			// The response is completely non-standard.
 | 
											
												
													
														|  | 
 |  | +			if (likely(allocLength > 12))
 | 
											
												
													
														|  | 
 |  | +			    allocLength = 12;
 | 
											
												
													
														|  | 
 |  | +			else if (unlikely(allocLength < 4))
 | 
											
												
													
														|  | 
 |  | +				allocLength = 4;
 | 
											
												
													
														|  | 
 |  | +			if (cfg->deviceType != S2S_CFG_SEQUENTIAL)
 | 
											
												
													
														|  | 
 |  | +			    allocLength = 4;
 | 
											
												
													
														|  | 
 |  | +			memset(scsiDev.data, 0, allocLength);
 | 
											
												
													
														|  | 
 |  | +			if (scsiDev.target->sense.code == NO_SENSE)
 | 
											
												
													
														|  | 
 |  | +			{
 | 
											
												
													
														|  | 
 |  | +				// Nothing to report.
 | 
											
												
													
														|  | 
 |  | +			}
 | 
											
												
													
														|  | 
 |  | +			else if (scsiDev.target->sense.code == UNIT_ATTENTION &&
 | 
											
												
													
														|  | 
 |  | +			    cfg->deviceType == S2S_CFG_SEQUENTIAL)
 | 
											
												
													
														|  | 
 |  | +			{
 | 
											
												
													
														|  | 
 |  | +				scsiDev.data[0] = 0x10; // Tape exception
 | 
											
												
													
														|  | 
 |  | +			}
 | 
											
												
													
														|  | 
 |  | +			else if (scsiDev.target->sense.code == ILLEGAL_REQUEST)
 | 
											
												
													
														|  | 
 |  | +			{
 | 
											
												
													
														|  | 
 |  | +				if (scsiDev.target->sense.asc == LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE)
 | 
											
												
													
														|  | 
 |  | +				{
 | 
											
												
													
														|  | 
 |  | +					if (cfg->deviceType == S2S_CFG_SEQUENTIAL)
 | 
											
												
													
														|  | 
 |  | +						scsiDev.data[0] = 0x10; // Tape exception
 | 
											
												
													
														|  | 
 |  | +					else
 | 
											
												
													
														|  | 
 |  | +						scsiDev.data[0] = 0x21; // Illegal Parameters
 | 
											
												
													
														|  | 
 |  | +				}
 | 
											
												
													
														|  | 
 |  | +				else if (scsiDev.target->sense.asc == INVALID_COMMAND_OPERATION_CODE)
 | 
											
												
													
														|  | 
 |  | +				{
 | 
											
												
													
														|  | 
 |  | +					scsiDev.data[0] = 0x20; // Invalid Command
 | 
											
												
													
														|  | 
 |  | +				}
 | 
											
												
													
														|  | 
 |  | +			}
 | 
											
												
													
														|  | 
 |  | +			else if (scsiDev.target->sense.code == NOT_READY)
 | 
											
												
													
														|  | 
 |  | +			{
 | 
											
												
													
														|  | 
 |  | +				scsiDev.data[0] = 0x04; // Drive not ready
 | 
											
												
													
														|  | 
 |  | +			}
 | 
											
												
													
														|  | 
 |  | +			else if (scsiDev.target->sense.code == BLANK_CHECK)
 | 
											
												
													
														|  | 
 |  | +			{
 | 
											
												
													
														|  | 
 |  | +				scsiDev.data[0] = 0x10; // Tape exception
 | 
											
												
													
														|  | 
 |  | +			}
 | 
											
												
													
														|  | 
 |  | +			else
 | 
											
												
													
														|  | 
 |  | +			{
 | 
											
												
													
														|  | 
 |  | +				scsiDev.data[0] = 0x11; // Uncorrectable data error
 | 
											
												
													
														|  | 
 |  | +			}
 | 
											
												
													
														|  | 
 |  | +			scsiDev.data[1] = (scsiDev.cdb[1] & 0x60) | ((transfer.lba >> 16) & 0x1F);
 | 
											
												
													
														|  | 
 |  | +			scsiDev.data[2] = transfer.lba >> 8;
 | 
											
												
													
														|  | 
 |  | +			scsiDev.data[3] = transfer.lba;
 | 
											
												
													
														|  | 
 |  | +			if (cfg->deviceType == S2S_CFG_SEQUENTIAL)
 | 
											
												
													
														|  | 
 |  | +			{
 | 
											
												
													
														|  | 
 |  | +				// For the tape drive there are 8 extra sense bytes.
 | 
											
												
													
														|  | 
 |  | +				if (scsiDev.target->sense.code == BLANK_CHECK)
 | 
											
												
													
														|  | 
 |  | +					scsiDev.data[11] = 0x88; // End of data recorded on the tape
 | 
											
												
													
														|  | 
 |  | +				else if (scsiDev.target->sense.code == UNIT_ATTENTION)
 | 
											
												
													
														|  | 
 |  | +					scsiDev.data[5] = 0x81; // Power On Reset occurred
 | 
											
												
													
														|  | 
 |  | +				else if (scsiDev.target->sense.code == ILLEGAL_REQUEST &&
 | 
											
												
													
														|  | 
 |  | +					 scsiDev.target->sense.asc == LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE)
 | 
											
												
													
														|  | 
 |  | +					scsiDev.data[4] = 0x81; // File Mark detected
 | 
											
												
													
														|  | 
 |  | +			}
 | 
											
												
													
														|  | 
 |  | +		}
 | 
											
												
													
														|  | 
 |  | +		else
 | 
											
												
													
														|  | 
 |  | +		{
 | 
											
												
													
														|  | 
 |  | +			// As specified by the SASI and SCSI1 standard.
 | 
											
												
													
														|  | 
 |  | +			// Newer initiators won't be specifying 0 anyway.
 | 
											
												
													
														|  | 
 |  | +			if (allocLength == 0) allocLength = 4;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +			memset(scsiDev.data, 0, 256); // Max possible alloc length
 | 
											
												
													
														|  | 
 |  | +			scsiDev.data[0] = 0xF0;
 | 
											
												
													
														|  | 
 |  | +			scsiDev.data[2] = scsiDev.target->sense.code & 0x0F;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +			scsiDev.data[3] = transfer.lba >> 24;
 | 
											
												
													
														|  | 
 |  | +			scsiDev.data[4] = transfer.lba >> 16;
 | 
											
												
													
														|  | 
 |  | +			scsiDev.data[5] = transfer.lba >> 8;
 | 
											
												
													
														|  | 
 |  | +			scsiDev.data[6] = transfer.lba;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +			// Additional bytes if there are errors to report
 | 
											
												
													
														|  | 
 |  | +			scsiDev.data[7] = 10; // additional length
 | 
											
												
													
														|  | 
 |  | +			scsiDev.data[12] = scsiDev.target->sense.asc >> 8;
 | 
											
												
													
														|  | 
 |  | +			scsiDev.data[13] = scsiDev.target->sense.asc;
 | 
											
												
													
														|  | 
 |  | +		}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +		// Silently truncate results. SCSI-2 spec 8.2.14.
 | 
											
												
													
														|  | 
 |  | +		enter_DataIn(allocLength);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +		// This is a good time to clear out old sense information.
 | 
											
												
													
														|  | 
 |  | +		scsiDev.target->sense.code = NO_SENSE;
 | 
											
												
													
														|  | 
 |  | +		scsiDev.target->sense.asc = NO_ADDITIONAL_SENSE_INFORMATION;
 | 
											
												
													
														|  | 
 |  | +	}
 | 
											
												
													
														|  | 
 |  | +	// Some old SCSI drivers do NOT properly support
 | 
											
												
													
														|  | 
 |  | +	// unitAttention. eg. the Mac Plus would trigger a SCSI reset
 | 
											
												
													
														|  | 
 |  | +	// on receiving the unit attention response on boot, thus
 | 
											
												
													
														|  | 
 |  | +	// triggering another unit attention condition.
 | 
											
												
													
														|  | 
 |  | +	else if (scsiDev.target->unitAttention &&
 | 
											
												
													
														|  | 
 |  | +		(scsiDev.boardCfg.flags & S2S_CFG_ENABLE_UNIT_ATTENTION))
 | 
											
												
													
														|  | 
 |  | +	{
 | 
											
												
													
														|  | 
 |  | +		scsiDev.target->sense.code = UNIT_ATTENTION;
 | 
											
												
													
														|  | 
 |  | +		scsiDev.target->sense.asc = scsiDev.target->unitAttention;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +		// If initiator doesn't do REQUEST SENSE for the next command, then
 | 
											
												
													
														|  | 
 |  | +		// data is lost.
 | 
											
												
													
														|  | 
 |  | +		scsiDev.target->unitAttention = 0;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +		enter_Status(CHECK_CONDITION);
 | 
											
												
													
														|  | 
 |  | +	}
 | 
											
												
													
														|  | 
 |  | +	else if (scsiDev.lun)
 | 
											
												
													
														|  | 
 |  | +	{
 | 
											
												
													
														|  | 
 |  | +		scsiDev.target->sense.code = ILLEGAL_REQUEST;
 | 
											
												
													
														|  | 
 |  | +		scsiDev.target->sense.asc = LOGICAL_UNIT_NOT_SUPPORTED;
 | 
											
												
													
														|  | 
 |  | +		enter_Status(CHECK_CONDITION);
 | 
											
												
													
														|  | 
 |  | +	}
 | 
											
												
													
														|  | 
 |  | +	else if (command == 0x17 || command == 0x16)
 | 
											
												
													
														|  | 
 |  | +	{
 | 
											
												
													
														|  | 
 |  | +		doReserveRelease();
 | 
											
												
													
														|  | 
 |  | +	}
 | 
											
												
													
														|  | 
 |  | +	else if ((scsiDev.target->reservedId >= 0) &&
 | 
											
												
													
														|  | 
 |  | +		(scsiDev.target->reservedId != scsiDev.initiatorId))
 | 
											
												
													
														|  | 
 |  | +	{
 | 
											
												
													
														|  | 
 |  | +		enter_Status(CONFLICT);
 | 
											
												
													
														|  | 
 |  | +	}
 | 
											
												
													
														|  | 
 |  | +	// Handle odd device types first that may override basic read and
 | 
											
												
													
														|  | 
 |  | +	// write commands. Will fall-through to generic disk handling.
 | 
											
												
													
														|  | 
 |  | +	else if (((cfg->deviceType == S2S_CFG_OPTICAL) && scsiCDRomCommand()) ||
 | 
											
												
													
														|  | 
 |  | +		((cfg->deviceType == S2S_CFG_SEQUENTIAL) && scsiTapeCommand()) ||
 | 
											
												
													
														|  | 
 |  | +		((cfg->deviceType == S2S_CFG_MO) && scsiMOCommand()))
 | 
											
												
													
														|  | 
 |  | +	{
 | 
											
												
													
														|  | 
 |  | +		// Already handled.
 | 
											
												
													
														|  | 
 |  | +	}
 | 
											
												
													
														|  | 
 |  | +	else if (scsiDiskCommand())
 | 
											
												
													
														|  | 
 |  | +	{
 | 
											
												
													
														|  | 
 |  | +		// Already handled.
 | 
											
												
													
														|  | 
 |  | +		// check for the performance-critical read/write
 | 
											
												
													
														|  | 
 |  | +		// commands ASAP.
 | 
											
												
													
														|  | 
 |  | +	}
 | 
											
												
													
														|  | 
 |  | +	else if (command == 0x1C)
 | 
											
												
													
														|  | 
 |  | +	{
 | 
											
												
													
														|  | 
 |  | +		scsiReceiveDiagnostic();
 | 
											
												
													
														|  | 
 |  | +	}
 | 
											
												
													
														|  | 
 |  | +	else if (command == 0x1D)
 | 
											
												
													
														|  | 
 |  | +	{
 | 
											
												
													
														|  | 
 |  | +		scsiSendDiagnostic();
 | 
											
												
													
														|  | 
 |  | +	}
 | 
											
												
													
														|  | 
 |  | +	else if (command == 0x3B)
 | 
											
												
													
														|  | 
 |  | +	{
 | 
											
												
													
														|  | 
 |  | +		scsiWriteBuffer();
 | 
											
												
													
														|  | 
 |  | +	}
 | 
											
												
													
														|  | 
 |  | +	else if (command == 0x0f &&
 | 
											
												
													
														|  | 
 |  | +		scsiDev.target->cfg->quirks == S2S_CFG_QUIRKS_XEBEC)
 | 
											
												
													
														|  | 
 |  | +	{
 | 
											
												
													
														|  | 
 |  | +		scsiWriteSectorBuffer();
 | 
											
												
													
														|  | 
 |  | +	}
 | 
											
												
													
														|  | 
 |  | +	else if (command == 0x3C)
 | 
											
												
													
														|  | 
 |  | +	{
 | 
											
												
													
														|  | 
 |  | +		scsiReadBuffer();
 | 
											
												
													
														|  | 
 |  | +	}
 | 
											
												
													
														|  | 
 |  | +	else if (!scsiModeCommand() && !scsiVendorCommand())
 | 
											
												
													
														|  | 
 |  | +	{
 | 
											
												
													
														|  | 
 |  | +		scsiDev.target->sense.code = ILLEGAL_REQUEST;
 | 
											
												
													
														|  | 
 |  | +		scsiDev.target->sense.asc = INVALID_COMMAND_OPERATION_CODE;
 | 
											
												
													
														|  | 
 |  | +		enter_Status(CHECK_CONDITION);
 | 
											
												
													
														|  | 
 |  | +	}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +	// Successful
 | 
											
												
													
														|  | 
 |  | +	if (scsiDev.phase == COMMAND) // No status set, and not in DATA_IN
 | 
											
												
													
														|  | 
 |  | +	{
 | 
											
												
													
														|  | 
 |  | +		enter_Status(GOOD);
 | 
											
												
													
														|  | 
 |  | +	}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +static void doReserveRelease()
 | 
											
												
													
														|  | 
 |  | +{
 | 
											
												
													
														|  | 
 |  | +	int extentReservation = scsiDev.cdb[1] & 1;
 | 
											
												
													
														|  | 
 |  | +	int thirdPty = scsiDev.cdb[1] & 0x10;
 | 
											
												
													
														|  | 
 |  | +	int thirdPtyId = (scsiDev.cdb[1] >> 1) & 0x7;
 | 
											
												
													
														|  | 
 |  | +	uint8_t command = scsiDev.cdb[0];
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +	int canRelease =
 | 
											
												
													
														|  | 
 |  | +		(!thirdPty && (scsiDev.initiatorId == scsiDev.target->reservedId)) ||
 | 
											
												
													
														|  | 
 |  | +			(thirdPty &&
 | 
											
												
													
														|  | 
 |  | +				(scsiDev.target->reserverId == scsiDev.initiatorId) &&
 | 
											
												
													
														|  | 
 |  | +				(scsiDev.target->reservedId == thirdPtyId)
 | 
											
												
													
														|  | 
 |  | +			);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +	if (extentReservation)
 | 
											
												
													
														|  | 
 |  | +	{
 | 
											
												
													
														|  | 
 |  | +		// Not supported.
 | 
											
												
													
														|  | 
 |  | +		scsiDev.target->sense.code = ILLEGAL_REQUEST;
 | 
											
												
													
														|  | 
 |  | +		scsiDev.target->sense.asc = INVALID_FIELD_IN_CDB;
 | 
											
												
													
														|  | 
 |  | +		enter_Status(CHECK_CONDITION);
 | 
											
												
													
														|  | 
 |  | +	}
 | 
											
												
													
														|  | 
 |  | +	else if (command == 0x17) // release
 | 
											
												
													
														|  | 
 |  | +	{
 | 
											
												
													
														|  | 
 |  | +		if ((scsiDev.target->reservedId < 0) || canRelease)
 | 
											
												
													
														|  | 
 |  | +		{
 | 
											
												
													
														|  | 
 |  | +			scsiDev.target->reservedId = -1;
 | 
											
												
													
														|  | 
 |  | +			scsiDev.target->reserverId = -1;
 | 
											
												
													
														|  | 
 |  | +		}
 | 
											
												
													
														|  | 
 |  | +		else
 | 
											
												
													
														|  | 
 |  | +		{
 | 
											
												
													
														|  | 
 |  | +			enter_Status(CONFLICT);
 | 
											
												
													
														|  | 
 |  | +		}
 | 
											
												
													
														|  | 
 |  | +	}
 | 
											
												
													
														|  | 
 |  | +	else // assume reserve.
 | 
											
												
													
														|  | 
 |  | +	{
 | 
											
												
													
														|  | 
 |  | +		if ((scsiDev.target->reservedId < 0) || canRelease)
 | 
											
												
													
														|  | 
 |  | +		{
 | 
											
												
													
														|  | 
 |  | +			scsiDev.target->reserverId = scsiDev.initiatorId;
 | 
											
												
													
														|  | 
 |  | +			if (thirdPty)
 | 
											
												
													
														|  | 
 |  | +			{
 | 
											
												
													
														|  | 
 |  | +				scsiDev.target->reservedId = thirdPtyId;
 | 
											
												
													
														|  | 
 |  | +			}
 | 
											
												
													
														|  | 
 |  | +			else
 | 
											
												
													
														|  | 
 |  | +			{
 | 
											
												
													
														|  | 
 |  | +				scsiDev.target->reservedId = scsiDev.initiatorId;
 | 
											
												
													
														|  | 
 |  | +			}
 | 
											
												
													
														|  | 
 |  | +		}
 | 
											
												
													
														|  | 
 |  | +		else
 | 
											
												
													
														|  | 
 |  | +		{
 | 
											
												
													
														|  | 
 |  | +			// Already reserved by someone else!
 | 
											
												
													
														|  | 
 |  | +			enter_Status(CONFLICT);
 | 
											
												
													
														|  | 
 |  | +		}
 | 
											
												
													
														|  | 
 |  | +	}
 | 
											
												
													
														|  | 
 |  | +}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +static uint32_t resetUntil = 0;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +static void scsiReset()
 | 
											
												
													
														|  | 
 |  | +{
 | 
											
												
													
														|  | 
 |  | +	scsiDev.rstCount++;
 | 
											
												
													
														|  | 
 |  | +	s2s_ledOff();
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +	scsiPhyReset();
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +	scsiDev.phase = BUS_FREE;
 | 
											
												
													
														|  | 
 |  | +	scsiDev.atnFlag = 0;
 | 
											
												
													
														|  | 
 |  | +	scsiDev.resetFlag = 0;
 | 
											
												
													
														|  | 
 |  | +	scsiDev.selFlag = 0;
 | 
											
												
													
														|  | 
 |  | +	scsiDev.lun = -1;
 | 
											
												
													
														|  | 
 |  | +	scsiDev.compatMode = COMPAT_UNKNOWN;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +	if (scsiDev.target)
 | 
											
												
													
														|  | 
 |  | +	{
 | 
											
												
													
														|  | 
 |  | +		if (scsiDev.target->unitAttention != POWER_ON_RESET)
 | 
											
												
													
														|  | 
 |  | +		{
 | 
											
												
													
														|  | 
 |  | +			scsiDev.target->unitAttention = SCSI_BUS_RESET;
 | 
											
												
													
														|  | 
 |  | +		}
 | 
											
												
													
														|  | 
 |  | +		scsiDev.target->reservedId = -1;
 | 
											
												
													
														|  | 
 |  | +		scsiDev.target->reserverId = -1;
 | 
											
												
													
														|  | 
 |  | +		scsiDev.target->sense.code = NO_SENSE;
 | 
											
												
													
														|  | 
 |  | +		scsiDev.target->sense.asc = NO_ADDITIONAL_SENSE_INFORMATION;
 | 
											
												
													
														|  | 
 |  | +	}
 | 
											
												
													
														|  | 
 |  | +	scsiDev.target = NULL;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +	for (int i = 0; i < S2S_MAX_TARGETS; ++i)
 | 
											
												
													
														|  | 
 |  | +	{
 | 
											
												
													
														|  | 
 |  | +		scsiDev.targets[i].syncOffset = 0;
 | 
											
												
													
														|  | 
 |  | +		scsiDev.targets[i].syncPeriod = 0;
 | 
											
												
													
														|  | 
 |  | +	}
 | 
											
												
													
														|  | 
 |  | +	scsiDev.minSyncPeriod = 0;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +	scsiDiskReset();
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +	scsiDev.postDataOutHook = NULL;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +	scsiDev.sdUnderrunCount = 0;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +	// Sleep to allow the bus to settle down a bit.
 | 
											
												
													
														|  | 
 |  | +	// We must be ready again within the "Reset to selection time" of
 | 
											
												
													
														|  | 
 |  | +	// 250ms.
 | 
											
												
													
														|  | 
 |  | +	// There is no guarantee that the RST line will be negated by then.
 | 
											
												
													
														|  | 
 |  | +	// NOTE: We could be connected and powered by USB for configuration,
 | 
											
												
													
														|  | 
 |  | +	// in which case TERMPWR cannot be supplied, and reset will ALWAYS
 | 
											
												
													
														|  | 
 |  | +	// be true. Therefore, the sleep here must be slow to avoid slowing
 | 
											
												
													
														|  | 
 |  | +	// USB comms
 | 
											
												
													
														|  | 
 |  | +	resetUntil = s2s_getTime_ms() + 2; // At least 1ms.
 | 
											
												
													
														|  | 
 |  | +}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +static void enter_SelectionPhase()
 | 
											
												
													
														|  | 
 |  | +{
 | 
											
												
													
														|  | 
 |  | +	// Ignore stale versions of this flag, but ensure we know the
 | 
											
												
													
														|  | 
 |  | +	// current value if the flag is still set.
 | 
											
												
													
														|  | 
 |  | +	scsiDev.atnFlag = 0;
 | 
											
												
													
														|  | 
 |  | +	scsiDev.dataPtr = 0;
 | 
											
												
													
														|  | 
 |  | +	scsiDev.savedDataPtr = 0;
 | 
											
												
													
														|  | 
 |  | +	scsiDev.dataLen = 0;
 | 
											
												
													
														|  | 
 |  | +	scsiDev.status = GOOD;
 | 
											
												
													
														|  | 
 |  | +	scsiDev.phase = SELECTION;
 | 
											
												
													
														|  | 
 |  | +	scsiDev.lun = -1;
 | 
											
												
													
														|  | 
 |  | +	scsiDev.discPriv = 0;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +	scsiDev.initiatorId = -1;
 | 
											
												
													
														|  | 
 |  | +	scsiDev.target = NULL;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +	transfer.blocks = 0;
 | 
											
												
													
														|  | 
 |  | +	transfer.currentBlock = 0;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +	scsiDev.postDataOutHook = NULL;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +	scsiDev.needSyncNegotiationAck = 0;
 | 
											
												
													
														|  | 
 |  | +}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +static void process_SelectionPhase()
 | 
											
												
													
														|  | 
 |  | +{
 | 
											
												
													
														|  | 
 |  | +	// Selection delays.
 | 
											
												
													
														|  | 
 |  | +	// Many SCSI1 samplers that use a 5380 chip need a delay of at least 1ms.
 | 
											
												
													
														|  | 
 |  | +	// The Mac Plus boot-time (ie. rom code) selection abort time
 | 
											
												
													
														|  | 
 |  | +	// is < 1ms and must have no delay (standard suggests 250ms abort time)
 | 
											
												
													
														|  | 
 |  | +	// Most newer SCSI2 hosts don't care either way.
 | 
											
												
													
														|  | 
 |  | +	if (scsiDev.target->cfg->quirks == S2S_CFG_QUIRKS_XEBEC)
 | 
											
												
													
														|  | 
 |  | +	{
 | 
											
												
													
														|  | 
 |  | +		s2s_delay_ms(1); // Simply won't work if set to 0.
 | 
											
												
													
														|  | 
 |  | +	}
 | 
											
												
													
														|  | 
 |  | +	else if (scsiDev.boardCfg.selectionDelay == 255) // auto
 | 
											
												
													
														|  | 
 |  | +	{
 | 
											
												
													
														|  | 
 |  | +		if (scsiDev.compatMode < COMPAT_SCSI2)
 | 
											
												
													
														|  | 
 |  | +		{
 | 
											
												
													
														|  | 
 |  | +			s2s_delay_ms(1);
 | 
											
												
													
														|  | 
 |  | +		}
 | 
											
												
													
														|  | 
 |  | +	}
 | 
											
												
													
														|  | 
 |  | +	else if (scsiDev.boardCfg.selectionDelay != 0)
 | 
											
												
													
														|  | 
 |  | +	{
 | 
											
												
													
														|  | 
 |  | +		s2s_delay_ms(scsiDev.boardCfg.selectionDelay);
 | 
											
												
													
														|  | 
 |  | +	}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +	uint8_t selStatus = *SCSI_STS_SELECTED;
 | 
											
												
													
														|  | 
 |  | +	if ((selStatus == 0) && (scsiDev.boardCfg.flags & S2S_CFG_ENABLE_SEL_LATCH))
 | 
											
												
													
														|  | 
 |  | +	{
 | 
											
												
													
														|  | 
 |  | +		selStatus = scsiDev.selFlag;
 | 
											
												
													
														|  | 
 |  | +	}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +	int tgtIndex;
 | 
											
												
													
														|  | 
 |  | +	TargetState* target = NULL;
 | 
											
												
													
														|  | 
 |  | +	for (tgtIndex = 0; tgtIndex < S2S_MAX_TARGETS; ++tgtIndex)
 | 
											
												
													
														|  | 
 |  | +	{
 | 
											
												
													
														|  | 
 |  | +		if (scsiDev.targets[tgtIndex].targetId == (selStatus & 7))
 | 
											
												
													
														|  | 
 |  | +		{
 | 
											
												
													
														|  | 
 |  | +			target = &scsiDev.targets[tgtIndex];
 | 
											
												
													
														|  | 
 |  | +			break;
 | 
											
												
													
														|  | 
 |  | +		}
 | 
											
												
													
														|  | 
 |  | +	}
 | 
											
												
													
														|  | 
 |  | +	if ((target != NULL) && (selStatus & 0x40))
 | 
											
												
													
														|  | 
 |  | +	{
 | 
											
												
													
														|  | 
 |  | +		// We've been selected!
 | 
											
												
													
														|  | 
 |  | +		// Assert BSY - Selection success!
 | 
											
												
													
														|  | 
 |  | +		// must happen within 200us (Selection abort time) of seeing our
 | 
											
												
													
														|  | 
 |  | +		// ID + SEL.
 | 
											
												
													
														|  | 
 |  | +		// (Note: the initiator will be waiting the "Selection time-out delay"
 | 
											
												
													
														|  | 
 |  | +		// for our BSY response, which is actually a very generous 250ms)
 | 
											
												
													
														|  | 
 |  | +		*SCSI_CTRL_BSY = 1;
 | 
											
												
													
														|  | 
 |  | +		s2s_ledOn();
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +		scsiDev.target = target;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +		// Do we enter MESSAGE OUT immediately ? SCSI 1 and 2 standards says
 | 
											
												
													
														|  | 
 |  | +		// move to MESSAGE OUT if ATN is true before we assert BSY.
 | 
											
												
													
														|  | 
 |  | +		// The initiator should assert ATN with SEL.
 | 
											
												
													
														|  | 
 |  | +		scsiDev.atnFlag = selStatus & 0x80;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +		// Unit attention breaks many older SCSI hosts. Disable it completely
 | 
											
												
													
														|  | 
 |  | +		// for SCSI-1 (and older) hosts, regardless of our configured setting.
 | 
											
												
													
														|  | 
 |  | +		// Enable the compatability mode also as many SASI and SCSI1
 | 
											
												
													
														|  | 
 |  | +		// controllers don't generate parity bits.
 | 
											
												
													
														|  | 
 |  | +		if (!scsiDev.atnFlag)
 | 
											
												
													
														|  | 
 |  | +		{
 | 
											
												
													
														|  | 
 |  | +			target->unitAttention = 0;
 | 
											
												
													
														|  | 
 |  | +			scsiDev.compatMode = COMPAT_SCSI1;
 | 
											
												
													
														|  | 
 |  | +		}
 | 
											
												
													
														|  | 
 |  | +		else if (!(scsiDev.boardCfg.flags & S2S_CFG_ENABLE_SCSI2))
 | 
											
												
													
														|  | 
 |  | +		{
 | 
											
												
													
														|  | 
 |  | +			scsiDev.compatMode = COMPAT_SCSI2_DISABLED;
 | 
											
												
													
														|  | 
 |  | +		}
 | 
											
												
													
														|  | 
 |  | +		else
 | 
											
												
													
														|  | 
 |  | +		{
 | 
											
												
													
														|  | 
 |  | +			scsiDev.compatMode = COMPAT_SCSI2;
 | 
											
												
													
														|  | 
 |  | +		}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +		scsiDev.selCount++;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +		// Save our initiator now that we're no longer in a time-critical
 | 
											
												
													
														|  | 
 |  | +		// section.
 | 
											
												
													
														|  | 
 |  | +		// SCSI1/SASI initiators may not set their own ID.
 | 
											
												
													
														|  | 
 |  | +		scsiDev.initiatorId = (selStatus >> 3) & 0x7;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +		// Wait until the end of the selection phase.
 | 
											
												
													
														|  | 
 |  | +		uint32_t selTimerBegin = s2s_getTime_ms();
 | 
											
												
													
														|  | 
 |  | +		while (likely(!scsiDev.resetFlag))
 | 
											
												
													
														|  | 
 |  | +		{
 | 
											
												
													
														|  | 
 |  | +			if (!scsiStatusSEL())
 | 
											
												
													
														|  | 
 |  | +			{
 | 
											
												
													
														|  | 
 |  | +				break;
 | 
											
												
													
														|  | 
 |  | +			}
 | 
											
												
													
														|  | 
 |  | +			else if (s2s_elapsedTime_ms(selTimerBegin) >= 10 &&
 | 
											
												
													
														|  | 
 |  | +				scsiDev.target->cfg->quirks == S2S_CFG_QUIRKS_XEBEC)
 | 
											
												
													
														|  | 
 |  | +			{
 | 
											
												
													
														|  | 
 |  | +				// XEBEC hosts may not bother releasing SEL at all until
 | 
											
												
													
														|  | 
 |  | +				// just before the command ends.
 | 
											
												
													
														|  | 
 |  | +				break;
 | 
											
												
													
														|  | 
 |  | +			}
 | 
											
												
													
														|  | 
 |  | +			else if (s2s_elapsedTime_ms(selTimerBegin) >= 250)
 | 
											
												
													
														|  | 
 |  | +			{
 | 
											
												
													
														|  | 
 |  | +				*SCSI_CTRL_BSY = 0;
 | 
											
												
													
														|  | 
 |  | +				scsiDev.resetFlag = 1;
 | 
											
												
													
														|  | 
 |  | +				break;
 | 
											
												
													
														|  | 
 |  | +			}
 | 
											
												
													
														|  | 
 |  | +		}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +		scsiDev.phase = COMMAND;
 | 
											
												
													
														|  | 
 |  | +	}
 | 
											
												
													
														|  | 
 |  | +	else if (!selStatus)
 | 
											
												
													
														|  | 
 |  | +	{
 | 
											
												
													
														|  | 
 |  | +		scsiDev.phase = BUS_BUSY;
 | 
											
												
													
														|  | 
 |  | +	}
 | 
											
												
													
														|  | 
 |  | +	scsiDev.selFlag = 0;
 | 
											
												
													
														|  | 
 |  | +}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +static void process_MessageOut()
 | 
											
												
													
														|  | 
 |  | +{
 | 
											
												
													
														|  | 
 |  | +	int wasNeedSyncNegotiationAck = scsiDev.needSyncNegotiationAck;
 | 
											
												
													
														|  | 
 |  | +	scsiDev.needSyncNegotiationAck = 0; // Successful on -most- messages.
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +	scsiEnterPhase(MESSAGE_OUT);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +	scsiDev.atnFlag = 0;
 | 
											
												
													
														|  | 
 |  | +	scsiDev.msgOut = scsiReadByte();
 | 
											
												
													
														|  | 
 |  | +	scsiDev.msgCount++;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +	if (scsiParityError() &&
 | 
											
												
													
														|  | 
 |  | +		(scsiDev.boardCfg.flags & S2S_CFG_ENABLE_PARITY))
 | 
											
												
													
														|  | 
 |  | +	{
 | 
											
												
													
														|  | 
 |  | +		// Skip the remaining message bytes, and then start the MESSAGE_OUT
 | 
											
												
													
														|  | 
 |  | +		// phase again from the start. The initiator will re-send the
 | 
											
												
													
														|  | 
 |  | +		// same set of messages.
 | 
											
												
													
														|  | 
 |  | +		while (scsiStatusATN() && !scsiDev.resetFlag)
 | 
											
												
													
														|  | 
 |  | +		{
 | 
											
												
													
														|  | 
 |  | +			scsiReadByte();
 | 
											
												
													
														|  | 
 |  | +		}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +		// Go-back and try the message again.
 | 
											
												
													
														|  | 
 |  | +		scsiDev.atnFlag = 1;
 | 
											
												
													
														|  | 
 |  | +	}
 | 
											
												
													
														|  | 
 |  | +	else if (scsiDev.msgOut == 0x00)
 | 
											
												
													
														|  | 
 |  | +	{
 | 
											
												
													
														|  | 
 |  | +		// COMMAND COMPLETE. but why would the target be receiving this ? nfi.
 | 
											
												
													
														|  | 
 |  | +		enter_BusFree();
 | 
											
												
													
														|  | 
 |  | +	}
 | 
											
												
													
														|  | 
 |  | +	else if (scsiDev.msgOut == 0x06)
 | 
											
												
													
														|  | 
 |  | +	{
 | 
											
												
													
														|  | 
 |  | +		// ABORT
 | 
											
												
													
														|  | 
 |  | +		scsiDiskReset();
 | 
											
												
													
														|  | 
 |  | +		enter_BusFree();
 | 
											
												
													
														|  | 
 |  | +	}
 | 
											
												
													
														|  | 
 |  | +	else if (scsiDev.msgOut == 0x0C)
 | 
											
												
													
														|  | 
 |  | +	{
 | 
											
												
													
														|  | 
 |  | +		// BUS DEVICE RESET
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +		scsiDiskReset();
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +		scsiDev.target->unitAttention = SCSI_BUS_RESET;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +		// ANY initiator can reset the reservation state via this message.
 | 
											
												
													
														|  | 
 |  | +		scsiDev.target->reservedId = -1;
 | 
											
												
													
														|  | 
 |  | +		scsiDev.target->reserverId = -1;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +		// Cancel any sync negotiation
 | 
											
												
													
														|  | 
 |  | +		scsiDev.target->syncOffset = 0;
 | 
											
												
													
														|  | 
 |  | +		scsiDev.target->syncPeriod = 0;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +		enter_BusFree();
 | 
											
												
													
														|  | 
 |  | +	}
 | 
											
												
													
														|  | 
 |  | +	else if (scsiDev.msgOut == 0x05)
 | 
											
												
													
														|  | 
 |  | +	{
 | 
											
												
													
														|  | 
 |  | +		// Initiate Detected Error
 | 
											
												
													
														|  | 
 |  | +		// Ignore for now
 | 
											
												
													
														|  | 
 |  | +	}
 | 
											
												
													
														|  | 
 |  | +	else if (scsiDev.msgOut == 0x0F)
 | 
											
												
													
														|  | 
 |  | +	{
 | 
											
												
													
														|  | 
 |  | +		// INITIATE RECOVERY
 | 
											
												
													
														|  | 
 |  | +		// Ignore for now
 | 
											
												
													
														|  | 
 |  | +	}
 | 
											
												
													
														|  | 
 |  | +	else if (scsiDev.msgOut == 0x10)
 | 
											
												
													
														|  | 
 |  | +	{
 | 
											
												
													
														|  | 
 |  | +		// RELEASE RECOVERY
 | 
											
												
													
														|  | 
 |  | +		// Ignore for now
 | 
											
												
													
														|  | 
 |  | +		enter_BusFree();
 | 
											
												
													
														|  | 
 |  | +	}
 | 
											
												
													
														|  | 
 |  | +	else if (scsiDev.msgOut == MSG_REJECT)
 | 
											
												
													
														|  | 
 |  | +	{
 | 
											
												
													
														|  | 
 |  | +		// Message Reject
 | 
											
												
													
														|  | 
 |  | +		// Oh well.
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +		if (wasNeedSyncNegotiationAck)
 | 
											
												
													
														|  | 
 |  | +		{
 | 
											
												
													
														|  | 
 |  | +			scsiDev.target->syncOffset = 0;
 | 
											
												
													
														|  | 
 |  | +			scsiDev.target->syncPeriod = 0;
 | 
											
												
													
														|  | 
 |  | +		}
 | 
											
												
													
														|  | 
 |  | +	}
 | 
											
												
													
														|  | 
 |  | +	else if (scsiDev.msgOut == 0x08)
 | 
											
												
													
														|  | 
 |  | +	{
 | 
											
												
													
														|  | 
 |  | +		// NOP
 | 
											
												
													
														|  | 
 |  | +	}
 | 
											
												
													
														|  | 
 |  | +	else if (scsiDev.msgOut == 0x09)
 | 
											
												
													
														|  | 
 |  | +	{
 | 
											
												
													
														|  | 
 |  | +		// Message Parity Error
 | 
											
												
													
														|  | 
 |  | +		// Go back and re-send the last message.
 | 
											
												
													
														|  | 
 |  | +		scsiDev.phase = MESSAGE_IN;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +		if (wasNeedSyncNegotiationAck)
 | 
											
												
													
														|  | 
 |  | +		{
 | 
											
												
													
														|  | 
 |  | +			scsiDev.target->syncOffset = 0;
 | 
											
												
													
														|  | 
 |  | +			scsiDev.target->syncPeriod = 0;
 | 
											
												
													
														|  | 
 |  | +		}
 | 
											
												
													
														|  | 
 |  | +	}
 | 
											
												
													
														|  | 
 |  | +	else if (scsiDev.msgOut & 0x80) // 0x80 -> 0xFF
 | 
											
												
													
														|  | 
 |  | +	{
 | 
											
												
													
														|  | 
 |  | +		// IDENTIFY
 | 
											
												
													
														|  | 
 |  | +		if ((scsiDev.msgOut & 0x18) || // Reserved bits set.
 | 
											
												
													
														|  | 
 |  | +			(scsiDev.msgOut & 0x20))  // We don't have any target routines!
 | 
											
												
													
														|  | 
 |  | +		{
 | 
											
												
													
														|  | 
 |  | +			messageReject();
 | 
											
												
													
														|  | 
 |  | +		}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +		scsiDev.lun = scsiDev.msgOut & 0x7;
 | 
											
												
													
														|  | 
 |  | +		scsiDev.discPriv = 
 | 
											
												
													
														|  | 
 |  | +			((scsiDev.msgOut & 0x40) && (scsiDev.initiatorId >= 0))
 | 
											
												
													
														|  | 
 |  | +				? 1 : 0;
 | 
											
												
													
														|  | 
 |  | +	}
 | 
											
												
													
														|  | 
 |  | +	else if (scsiDev.msgOut >= 0x20 && scsiDev.msgOut <= 0x2F)
 | 
											
												
													
														|  | 
 |  | +	{
 | 
											
												
													
														|  | 
 |  | +		// Two byte message. We don't support these. read and discard.
 | 
											
												
													
														|  | 
 |  | +		scsiReadByte();
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +		if (scsiDev.msgOut == 0x23) {
 | 
											
												
													
														|  | 
 |  | +			// Ignore Wide Residue. We're only 8 bit anyway.
 | 
											
												
													
														|  | 
 |  | +		} else {
 | 
											
												
													
														|  | 
 |  | +			messageReject();
 | 
											
												
													
														|  | 
 |  | +		}
 | 
											
												
													
														|  | 
 |  | +	}
 | 
											
												
													
														|  | 
 |  | +	else if (scsiDev.msgOut == 0x01)
 | 
											
												
													
														|  | 
 |  | +	{
 | 
											
												
													
														|  | 
 |  | +		int i;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +		// Extended message.
 | 
											
												
													
														|  | 
 |  | +		int msgLen = scsiReadByte();
 | 
											
												
													
														|  | 
 |  | +		if (msgLen == 0) msgLen = 256;
 | 
											
												
													
														|  | 
 |  | +		uint8_t extmsg[256];
 | 
											
												
													
														|  | 
 |  | +		for (i = 0; i < msgLen && !scsiDev.resetFlag; ++i)
 | 
											
												
													
														|  | 
 |  | +		{
 | 
											
												
													
														|  | 
 |  | +			// Discard bytes.
 | 
											
												
													
														|  | 
 |  | +			extmsg[i] = scsiReadByte();
 | 
											
												
													
														|  | 
 |  | +		}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +		if (extmsg[0] == 3 && msgLen == 2) // Wide Data Request
 | 
											
												
													
														|  | 
 |  | +		{
 | 
											
												
													
														|  | 
 |  | +			// Negotiate down to 8bit
 | 
											
												
													
														|  | 
 |  | +			scsiEnterPhase(MESSAGE_IN);
 | 
											
												
													
														|  | 
 |  | +			static const uint8_t WDTR[] = {0x01, 0x02, 0x03, 0x00};
 | 
											
												
													
														|  | 
 |  | +			scsiWrite(WDTR, sizeof(WDTR));
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +			// SDTR becomes invalidated.
 | 
											
												
													
														|  | 
 |  | +			scsiDev.target->syncOffset = 0;
 | 
											
												
													
														|  | 
 |  | +			scsiDev.target->syncPeriod = 0;
 | 
											
												
													
														|  | 
 |  | +		}
 | 
											
												
													
														|  | 
 |  | +		else if (extmsg[0] == 1 && msgLen == 3) // Synchronous data request
 | 
											
												
													
														|  | 
 |  | +		{
 | 
											
												
													
														|  | 
 |  | +			int oldPeriod = scsiDev.target->syncPeriod;
 | 
											
												
													
														|  | 
 |  | +			int oldOffset = scsiDev.target->syncOffset;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +			int transferPeriod = extmsg[1];
 | 
											
												
													
														|  | 
 |  | +			int offset = extmsg[2];
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +			if ((
 | 
											
												
													
														|  | 
 |  | +					(transferPeriod > 0) &&
 | 
											
												
													
														|  | 
 |  | +					(transferPeriod < scsiDev.minSyncPeriod)) ||
 | 
											
												
													
														|  | 
 |  | +				(scsiDev.minSyncPeriod == 0))
 | 
											
												
													
														|  | 
 |  | +			{
 | 
											
												
													
														|  | 
 |  | +				scsiDev.minSyncPeriod = transferPeriod;
 | 
											
												
													
														|  | 
 |  | +			}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +			if ((transferPeriod > 80) || // 320ns, 3.125MB/s
 | 
											
												
													
														|  | 
 |  | +				// Amiga A590 (WD33C93 chip) only does 3.5MB/s sync
 | 
											
												
													
														|  | 
 |  | +				// After 80 we start to run out of bits in the fpga timing
 | 
											
												
													
														|  | 
 |  | +				// register.
 | 
											
												
													
														|  | 
 |  | +				(transferPeriod == 0) ||
 | 
											
												
													
														|  | 
 |  | +				(offset == 0) ||
 | 
											
												
													
														|  | 
 |  | +				((scsiDev.boardCfg.scsiSpeed != S2S_CFG_SPEED_NoLimit) &&
 | 
											
												
													
														|  | 
 |  | +					(scsiDev.boardCfg.scsiSpeed <= S2S_CFG_SPEED_ASYNC_50)))
 | 
											
												
													
														|  | 
 |  | +			{
 | 
											
												
													
														|  | 
 |  | +				scsiDev.target->syncOffset = 0;
 | 
											
												
													
														|  | 
 |  | +				scsiDev.target->syncPeriod = 0;
 | 
											
												
													
														|  | 
 |  | +			} else {
 | 
											
												
													
														|  | 
 |  | +				scsiDev.target->syncOffset = offset <= 15 ? offset : 15;
 | 
											
												
													
														|  | 
 |  | +				// FAST20 / 50ns / 20MHz is disabled for now due to
 | 
											
												
													
														|  | 
 |  | +				// data corruption while reading data. We can count the
 | 
											
												
													
														|  | 
 |  | +				// ACK's correctly, but can't save the data to a register
 | 
											
												
													
														|  | 
 |  | +				// before it changes. (ie. transferPeriod == 12)
 | 
											
												
													
														|  | 
 |  | +				if ((scsiDev.boardCfg.scsiSpeed == S2S_CFG_SPEED_TURBO) &&
 | 
											
												
													
														|  | 
 |  | +					(transferPeriod <= 16))
 | 
											
												
													
														|  | 
 |  | +				{
 | 
											
												
													
														|  | 
 |  | +					scsiDev.target->syncPeriod = 16; // 15.6MB/s
 | 
											
												
													
														|  | 
 |  | +				}
 | 
											
												
													
														|  | 
 |  | +				else if (scsiDev.boardCfg.scsiSpeed == S2S_CFG_SPEED_TURBO)
 | 
											
												
													
														|  | 
 |  | +				{
 | 
											
												
													
														|  | 
 |  | +					scsiDev.target->syncPeriod = transferPeriod;
 | 
											
												
													
														|  | 
 |  | +				}
 | 
											
												
													
														|  | 
 |  | +				else if (transferPeriod <= 25 &&
 | 
											
												
													
														|  | 
 |  | +					((scsiDev.boardCfg.scsiSpeed == S2S_CFG_SPEED_NoLimit) ||
 | 
											
												
													
														|  | 
 |  | +						(scsiDev.boardCfg.scsiSpeed >= S2S_CFG_SPEED_SYNC_10)))
 | 
											
												
													
														|  | 
 |  | +				{
 | 
											
												
													
														|  | 
 |  | +					scsiDev.target->syncPeriod = 25; // 100ns, 10MB/s
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +				} else if (transferPeriod < 50 &&
 | 
											
												
													
														|  | 
 |  | +					((scsiDev.boardCfg.scsiSpeed == S2S_CFG_SPEED_NoLimit) ||
 | 
											
												
													
														|  | 
 |  | +						(scsiDev.boardCfg.scsiSpeed >= S2S_CFG_SPEED_SYNC_10)))
 | 
											
												
													
														|  | 
 |  | +				{
 | 
											
												
													
														|  | 
 |  | +					scsiDev.target->syncPeriod = transferPeriod;
 | 
											
												
													
														|  | 
 |  | +				} else if (transferPeriod >= 50)
 | 
											
												
													
														|  | 
 |  | +				{
 | 
											
												
													
														|  | 
 |  | +					scsiDev.target->syncPeriod = transferPeriod;
 | 
											
												
													
														|  | 
 |  | +				} else {
 | 
											
												
													
														|  | 
 |  | +					scsiDev.target->syncPeriod = 50;
 | 
											
												
													
														|  | 
 |  | +				}
 | 
											
												
													
														|  | 
 |  | +			}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +			if (transferPeriod != oldPeriod ||
 | 
											
												
													
														|  | 
 |  | +				scsiDev.target->syncPeriod != oldPeriod ||
 | 
											
												
													
														|  | 
 |  | +				offset != oldOffset ||
 | 
											
												
													
														|  | 
 |  | +				scsiDev.target->syncOffset != oldOffset ||
 | 
											
												
													
														|  | 
 |  | +				!wasNeedSyncNegotiationAck) // Don't get into infinite loops negotiating.
 | 
											
												
													
														|  | 
 |  | +			{
 | 
											
												
													
														|  | 
 |  | +				scsiEnterPhase(MESSAGE_IN);
 | 
											
												
													
														|  | 
 |  | +				uint8_t SDTR[] = {0x01, 0x03, 0x01, scsiDev.target->syncPeriod, scsiDev.target->syncOffset};
 | 
											
												
													
														|  | 
 |  | +				scsiWrite(SDTR, sizeof(SDTR));
 | 
											
												
													
														|  | 
 |  | +				scsiDev.needSyncNegotiationAck = 1; // Check if this message is rejected.
 | 
											
												
													
														|  | 
 |  | +				scsiDev.sdUnderrunCount = 0;  // reset counter, may work now.
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +				// Set to the theoretical speed, then adjust if we measure lower
 | 
											
												
													
														|  | 
 |  | +				// actual speeds.
 | 
											
												
													
														|  | 
 |  | +				scsiDev.hostSpeedKBs = s2s_getScsiRateKBs();
 | 
											
												
													
														|  | 
 |  | +				scsiDev.hostSpeedMeasured = 0;
 | 
											
												
													
														|  | 
 |  | +			}
 | 
											
												
													
														|  | 
 |  | +		}
 | 
											
												
													
														|  | 
 |  | +		else
 | 
											
												
													
														|  | 
 |  | +		{
 | 
											
												
													
														|  | 
 |  | +			// Not supported
 | 
											
												
													
														|  | 
 |  | +			messageReject();
 | 
											
												
													
														|  | 
 |  | +		}
 | 
											
												
													
														|  | 
 |  | +	}
 | 
											
												
													
														|  | 
 |  | +	else
 | 
											
												
													
														|  | 
 |  | +	{
 | 
											
												
													
														|  | 
 |  | +		messageReject();
 | 
											
												
													
														|  | 
 |  | +	}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +	// Re-check the ATN flag in case it stays asserted.
 | 
											
												
													
														|  | 
 |  | +	scsiDev.atnFlag |= scsiStatusATN();
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +	if (!scsiDev.atnFlag)
 | 
											
												
													
														|  | 
 |  | +	{
 | 
											
												
													
														|  | 
 |  | +		// Message wasn't rejected!
 | 
											
												
													
														|  | 
 |  | +		scsiDev.needSyncNegotiationAck = 0;
 | 
											
												
													
														|  | 
 |  | +	}
 | 
											
												
													
														|  | 
 |  | +}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +void scsiPoll(void)
 | 
											
												
													
														|  | 
 |  | +{
 | 
											
												
													
														|  | 
 |  | +	if (resetUntil != 0 && resetUntil > s2s_getTime_ms())
 | 
											
												
													
														|  | 
 |  | +	{
 | 
											
												
													
														|  | 
 |  | +		return;
 | 
											
												
													
														|  | 
 |  | +	}
 | 
											
												
													
														|  | 
 |  | +	resetUntil = 0;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +	if (unlikely(scsiDev.resetFlag))
 | 
											
												
													
														|  | 
 |  | +	{
 | 
											
												
													
														|  | 
 |  | +		scsiReset();
 | 
											
												
													
														|  | 
 |  | +		// Still in reset phase for a few ms.
 | 
											
												
													
														|  | 
 |  | +		// Do not try and process any commands.
 | 
											
												
													
														|  | 
 |  | +		return;
 | 
											
												
													
														|  | 
 |  | +	}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +	switch (scsiDev.phase)
 | 
											
												
													
														|  | 
 |  | +	{
 | 
											
												
													
														|  | 
 |  | +	case BUS_FREE:
 | 
											
												
													
														|  | 
 |  | +		if (scsiStatusBSY())
 | 
											
												
													
														|  | 
 |  | +		{
 | 
											
												
													
														|  | 
 |  | +			scsiDev.phase = BUS_BUSY;
 | 
											
												
													
														|  | 
 |  | +		}
 | 
											
												
													
														|  | 
 |  | +		// The Arbitration phase is optional for SCSI1/SASI hosts if there is only
 | 
											
												
													
														|  | 
 |  | +		// one initiator in the chain. Support this by moving
 | 
											
												
													
														|  | 
 |  | +		// straight to selection if SEL is asserted.
 | 
											
												
													
														|  | 
 |  | +		// ie. the initiator won't assert BSY and it's own ID before moving to selection.
 | 
											
												
													
														|  | 
 |  | +		else if (scsiDev.selFlag || *SCSI_STS_SELECTED)
 | 
											
												
													
														|  | 
 |  | +		{
 | 
											
												
													
														|  | 
 |  | +			enter_SelectionPhase();
 | 
											
												
													
														|  | 
 |  | +		}
 | 
											
												
													
														|  | 
 |  | +	break;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +	case BUS_BUSY:
 | 
											
												
													
														|  | 
 |  | +		// Someone is using the bus. Perhaps they are trying to
 | 
											
												
													
														|  | 
 |  | +		// select us.
 | 
											
												
													
														|  | 
 |  | +		if (scsiDev.selFlag || *SCSI_STS_SELECTED)
 | 
											
												
													
														|  | 
 |  | +		{
 | 
											
												
													
														|  | 
 |  | +			enter_SelectionPhase();
 | 
											
												
													
														|  | 
 |  | +		}
 | 
											
												
													
														|  | 
 |  | +		else if (!scsiStatusBSY())
 | 
											
												
													
														|  | 
 |  | +		{
 | 
											
												
													
														|  | 
 |  | +			scsiDev.phase = BUS_FREE;
 | 
											
												
													
														|  | 
 |  | +		}
 | 
											
												
													
														|  | 
 |  | +	break;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +	case ARBITRATION:
 | 
											
												
													
														|  | 
 |  | +		// TODO Support reselection.
 | 
											
												
													
														|  | 
 |  | +		break;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +	case SELECTION:
 | 
											
												
													
														|  | 
 |  | +		process_SelectionPhase();
 | 
											
												
													
														|  | 
 |  | +	break;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +	case RESELECTION:
 | 
											
												
													
														|  | 
 |  | +		// Not currently supported!
 | 
											
												
													
														|  | 
 |  | +	break;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +	case COMMAND:
 | 
											
												
													
														|  | 
 |  | +		// Do not check ATN here. SCSI 1 & 2 initiators must set ATN
 | 
											
												
													
														|  | 
 |  | +		// and SEL together upon entering the selection phase if they
 | 
											
												
													
														|  | 
 |  | +		// want to send a message (IDENTIFY) immediately.
 | 
											
												
													
														|  | 
 |  | +		if (scsiDev.atnFlag)
 | 
											
												
													
														|  | 
 |  | +		{
 | 
											
												
													
														|  | 
 |  | +			process_MessageOut();
 | 
											
												
													
														|  | 
 |  | +		}
 | 
											
												
													
														|  | 
 |  | +		else
 | 
											
												
													
														|  | 
 |  | +		{
 | 
											
												
													
														|  | 
 |  | +			process_Command();
 | 
											
												
													
														|  | 
 |  | +		}
 | 
											
												
													
														|  | 
 |  | +	break;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +	case DATA_IN:
 | 
											
												
													
														|  | 
 |  | +		scsiDev.atnFlag |= scsiStatusATN();
 | 
											
												
													
														|  | 
 |  | +		if (scsiDev.atnFlag)
 | 
											
												
													
														|  | 
 |  | +		{
 | 
											
												
													
														|  | 
 |  | +			process_MessageOut();
 | 
											
												
													
														|  | 
 |  | +		}
 | 
											
												
													
														|  | 
 |  | +		else
 | 
											
												
													
														|  | 
 |  | +		{
 | 
											
												
													
														|  | 
 |  | +			process_DataIn();
 | 
											
												
													
														|  | 
 |  | +		}
 | 
											
												
													
														|  | 
 |  | +	break;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +	case DATA_OUT:
 | 
											
												
													
														|  | 
 |  | +		scsiDev.atnFlag |= scsiStatusATN();
 | 
											
												
													
														|  | 
 |  | +		if (scsiDev.atnFlag)
 | 
											
												
													
														|  | 
 |  | +		{
 | 
											
												
													
														|  | 
 |  | +			process_MessageOut();
 | 
											
												
													
														|  | 
 |  | +		}
 | 
											
												
													
														|  | 
 |  | +		else
 | 
											
												
													
														|  | 
 |  | +		{
 | 
											
												
													
														|  | 
 |  | +			process_DataOut();
 | 
											
												
													
														|  | 
 |  | +		}
 | 
											
												
													
														|  | 
 |  | +	break;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +	case STATUS:
 | 
											
												
													
														|  | 
 |  | +		scsiDev.atnFlag |= scsiStatusATN();
 | 
											
												
													
														|  | 
 |  | +		if (scsiDev.atnFlag)
 | 
											
												
													
														|  | 
 |  | +		{
 | 
											
												
													
														|  | 
 |  | +			process_MessageOut();
 | 
											
												
													
														|  | 
 |  | +		}
 | 
											
												
													
														|  | 
 |  | +		else
 | 
											
												
													
														|  | 
 |  | +		{
 | 
											
												
													
														|  | 
 |  | +			process_Status();
 | 
											
												
													
														|  | 
 |  | +		}
 | 
											
												
													
														|  | 
 |  | +	break;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +	case MESSAGE_IN:
 | 
											
												
													
														|  | 
 |  | +		scsiDev.atnFlag |= scsiStatusATN();
 | 
											
												
													
														|  | 
 |  | +		if (scsiDev.atnFlag)
 | 
											
												
													
														|  | 
 |  | +		{
 | 
											
												
													
														|  | 
 |  | +			process_MessageOut();
 | 
											
												
													
														|  | 
 |  | +		}
 | 
											
												
													
														|  | 
 |  | +		else
 | 
											
												
													
														|  | 
 |  | +		{
 | 
											
												
													
														|  | 
 |  | +			process_MessageIn(1);
 | 
											
												
													
														|  | 
 |  | +		}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +	break;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +	case MESSAGE_OUT:
 | 
											
												
													
														|  | 
 |  | +		process_MessageOut();
 | 
											
												
													
														|  | 
 |  | +	break;
 | 
											
												
													
														|  | 
 |  | +	}
 | 
											
												
													
														|  | 
 |  | +}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +void scsiInit()
 | 
											
												
													
														|  | 
 |  | +{
 | 
											
												
													
														|  | 
 |  | +	static int firstInit = 1;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +	scsiDev.atnFlag = 0;
 | 
											
												
													
														|  | 
 |  | +	scsiDev.resetFlag = 1;
 | 
											
												
													
														|  | 
 |  | +	scsiDev.selFlag = 0;
 | 
											
												
													
														|  | 
 |  | +	scsiDev.phase = BUS_FREE;
 | 
											
												
													
														|  | 
 |  | +	scsiDev.target = NULL;
 | 
											
												
													
														|  | 
 |  | +	scsiDev.compatMode = COMPAT_UNKNOWN;
 | 
											
												
													
														|  | 
 |  | +	scsiDev.hostSpeedKBs = 0;
 | 
											
												
													
														|  | 
 |  | +	scsiDev.hostSpeedMeasured = 0;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +	int i;
 | 
											
												
													
														|  | 
 |  | +	for (i = 0; i < S2S_MAX_TARGETS; ++i)
 | 
											
												
													
														|  | 
 |  | +	{
 | 
											
												
													
														|  | 
 |  | +		const S2S_TargetCfg* cfg = s2s_getConfigByIndex(i);
 | 
											
												
													
														|  | 
 |  | +		if (cfg && (cfg->scsiId & S2S_CFG_TARGET_ENABLED))
 | 
											
												
													
														|  | 
 |  | +		{
 | 
											
												
													
														|  | 
 |  | +			scsiDev.targets[i].targetId = cfg->scsiId & S2S_CFG_TARGET_ID_BITS;
 | 
											
												
													
														|  | 
 |  | +			scsiDev.targets[i].cfg = cfg;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +			scsiDev.targets[i].liveCfg.bytesPerSector = cfg->bytesPerSector;
 | 
											
												
													
														|  | 
 |  | +		}
 | 
											
												
													
														|  | 
 |  | +		else
 | 
											
												
													
														|  | 
 |  | +		{
 | 
											
												
													
														|  | 
 |  | +			scsiDev.targets[i].targetId = 0xff;
 | 
											
												
													
														|  | 
 |  | +			scsiDev.targets[i].cfg = NULL;
 | 
											
												
													
														|  | 
 |  | +		}
 | 
											
												
													
														|  | 
 |  | +		scsiDev.targets[i].reservedId = -1;
 | 
											
												
													
														|  | 
 |  | +		scsiDev.targets[i].reserverId = -1;
 | 
											
												
													
														|  | 
 |  | +		if (firstInit)
 | 
											
												
													
														|  | 
 |  | +		{
 | 
											
												
													
														|  | 
 |  | +			scsiDev.targets[i].unitAttention = POWER_ON_RESET;
 | 
											
												
													
														|  | 
 |  | +		}
 | 
											
												
													
														|  | 
 |  | +		else
 | 
											
												
													
														|  | 
 |  | +		{
 | 
											
												
													
														|  | 
 |  | +			scsiDev.targets[i].unitAttention = PARAMETERS_CHANGED;
 | 
											
												
													
														|  | 
 |  | +		}
 | 
											
												
													
														|  | 
 |  | +		scsiDev.targets[i].sense.code = NO_SENSE;
 | 
											
												
													
														|  | 
 |  | +		scsiDev.targets[i].sense.asc = NO_ADDITIONAL_SENSE_INFORMATION;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +		scsiDev.targets[i].syncOffset = 0;
 | 
											
												
													
														|  | 
 |  | +		scsiDev.targets[i].syncPeriod = 0;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +		// Always "start" the device. Many systems (eg. Apple System 7)
 | 
											
												
													
														|  | 
 |  | +		// won't respond properly to
 | 
											
												
													
														|  | 
 |  | +		// LOGICAL_UNIT_NOT_READY_INITIALIZING_COMMAND_REQUIRED sense
 | 
											
												
													
														|  | 
 |  | +		// code
 | 
											
												
													
														|  | 
 |  | +		scsiDev.targets[i].started = 1;
 | 
											
												
													
														|  | 
 |  | +	}
 | 
											
												
													
														|  | 
 |  | +	firstInit = 0;
 | 
											
												
													
														|  | 
 |  | +}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +/* TODO REENABLE
 | 
											
												
													
														|  | 
 |  | +void scsiDisconnect()
 | 
											
												
													
														|  | 
 |  | +{
 | 
											
												
													
														|  | 
 |  | +	scsiEnterPhase(MESSAGE_IN);
 | 
											
												
													
														|  | 
 |  | +	scsiWriteByte(0x02); // save data pointer
 | 
											
												
													
														|  | 
 |  | +	scsiWriteByte(0x04); // disconnect msg.
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +	// For now, the caller is responsible for tracking the disconnected
 | 
											
												
													
														|  | 
 |  | +	// state, and calling scsiReconnect.
 | 
											
												
													
														|  | 
 |  | +	// Ideally the client would exit their loop and we'd implement this
 | 
											
												
													
														|  | 
 |  | +	// as part of scsiPoll
 | 
											
												
													
														|  | 
 |  | +	int phase = scsiDev.phase;
 | 
											
												
													
														|  | 
 |  | +	enter_BusFree();
 | 
											
												
													
														|  | 
 |  | +	scsiDev.phase = phase;
 | 
											
												
													
														|  | 
 |  | +}
 | 
											
												
													
														|  | 
 |  | +*/
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +/* TODO REENABLE
 | 
											
												
													
														|  | 
 |  | +int scsiReconnect()
 | 
											
												
													
														|  | 
 |  | +{
 | 
											
												
													
														|  | 
 |  | +	int reconnected = 0;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +	int sel = SCSI_ReadFilt(SCSI_Filt_SEL);
 | 
											
												
													
														|  | 
 |  | +	int bsy = SCSI_ReadFilt(SCSI_Filt_BSY);
 | 
											
												
													
														|  | 
 |  | +	if (!sel && !bsy)
 | 
											
												
													
														|  | 
 |  | +	{
 | 
											
												
													
														|  | 
 |  | +		s2s_delay_us(1);
 | 
											
												
													
														|  | 
 |  | +		sel = SCSI_ReadFilt(SCSI_Filt_SEL);
 | 
											
												
													
														|  | 
 |  | +		bsy = SCSI_ReadFilt(SCSI_Filt_BSY);
 | 
											
												
													
														|  | 
 |  | +	}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +	if (!sel && !bsy)
 | 
											
												
													
														|  | 
 |  | +	{
 | 
											
												
													
														|  | 
 |  | +		// Arbitrate.
 | 
											
												
													
														|  | 
 |  | +		s2s_ledOn();
 | 
											
												
													
														|  | 
 |  | +		uint8_t scsiIdMask = 1 << scsiDev.target->targetId;
 | 
											
												
													
														|  | 
 |  | +		SCSI_Out_Bits_Write(scsiIdMask);
 | 
											
												
													
														|  | 
 |  | +		SCSI_Out_Ctl_Write(1); // Write bits manually.
 | 
											
												
													
														|  | 
 |  | +		SCSI_SetPin(SCSI_Out_BSY);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +		s2s_delay_us(3); // arbitrate delay. 2.4us.
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +		uint8_t dbx = scsiReadDBxPins();
 | 
											
												
													
														|  | 
 |  | +		sel = SCSI_ReadFilt(SCSI_Filt_SEL);
 | 
											
												
													
														|  | 
 |  | +		if (sel || ((dbx ^ scsiIdMask) > scsiIdMask))
 | 
											
												
													
														|  | 
 |  | +		{
 | 
											
												
													
														|  | 
 |  | +			// Lost arbitration.
 | 
											
												
													
														|  | 
 |  | +			SCSI_Out_Ctl_Write(0);
 | 
											
												
													
														|  | 
 |  | +			SCSI_ClearPin(SCSI_Out_BSY);
 | 
											
												
													
														|  | 
 |  | +			s2s_ledOff();
 | 
											
												
													
														|  | 
 |  | +		}
 | 
											
												
													
														|  | 
 |  | +		else
 | 
											
												
													
														|  | 
 |  | +		{
 | 
											
												
													
														|  | 
 |  | +			// Won arbitration
 | 
											
												
													
														|  | 
 |  | +			SCSI_SetPin(SCSI_Out_SEL);
 | 
											
												
													
														|  | 
 |  | +			s2s_delay_us(1); // Bus clear + Bus settle.
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +			// Reselection phase
 | 
											
												
													
														|  | 
 |  | +			SCSI_CTL_PHASE_Write(__scsiphase_io);
 | 
											
												
													
														|  | 
 |  | +			SCSI_Out_Bits_Write(scsiIdMask | (1 << scsiDev.initiatorId));
 | 
											
												
													
														|  | 
 |  | +			scsiDeskewDelay(); // 2 deskew delays
 | 
											
												
													
														|  | 
 |  | +			scsiDeskewDelay(); // 2 deskew delays
 | 
											
												
													
														|  | 
 |  | +			SCSI_ClearPin(SCSI_Out_BSY);
 | 
											
												
													
														|  | 
 |  | +			s2s_delay_us(1);  // Bus Settle Delay
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +			uint32_t waitStart_ms = getTime_ms();
 | 
											
												
													
														|  | 
 |  | +			bsy = SCSI_ReadFilt(SCSI_Filt_BSY);
 | 
											
												
													
														|  | 
 |  | +			// Wait for initiator.
 | 
											
												
													
														|  | 
 |  | +			while (
 | 
											
												
													
														|  | 
 |  | +				!bsy &&
 | 
											
												
													
														|  | 
 |  | +				!scsiDev.resetFlag &&
 | 
											
												
													
														|  | 
 |  | +				(elapsedTime_ms(waitStart_ms) < 250))
 | 
											
												
													
														|  | 
 |  | +			{
 | 
											
												
													
														|  | 
 |  | +				bsy = SCSI_ReadFilt(SCSI_Filt_BSY);
 | 
											
												
													
														|  | 
 |  | +			}
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +			if (bsy)
 | 
											
												
													
														|  | 
 |  | +			{
 | 
											
												
													
														|  | 
 |  | +				SCSI_SetPin(SCSI_Out_BSY);
 | 
											
												
													
														|  | 
 |  | +				scsiDeskewDelay(); // 2 deskew delays
 | 
											
												
													
														|  | 
 |  | +				scsiDeskewDelay(); // 2 deskew delays
 | 
											
												
													
														|  | 
 |  | +				SCSI_ClearPin(SCSI_Out_SEL);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +				// Prepare for the initial IDENTIFY message.
 | 
											
												
													
														|  | 
 |  | +				SCSI_Out_Ctl_Write(0);
 | 
											
												
													
														|  | 
 |  | +				scsiEnterPhase(MESSAGE_IN);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +				// Send identify command
 | 
											
												
													
														|  | 
 |  | +				scsiWriteByte(0x80);
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +				scsiEnterPhase(scsiDev.phase);
 | 
											
												
													
														|  | 
 |  | +				reconnected = 1;
 | 
											
												
													
														|  | 
 |  | +			}
 | 
											
												
													
														|  | 
 |  | +			else
 | 
											
												
													
														|  | 
 |  | +			{
 | 
											
												
													
														|  | 
 |  | +				// reselect timeout.
 | 
											
												
													
														|  | 
 |  | +				SCSI_Out_Ctl_Write(0);
 | 
											
												
													
														|  | 
 |  | +				SCSI_ClearPin(SCSI_Out_SEL);
 | 
											
												
													
														|  | 
 |  | +				SCSI_CTL_PHASE_Write(0);
 | 
											
												
													
														|  | 
 |  | +				s2s_ledOff();
 | 
											
												
													
														|  | 
 |  | +			}
 | 
											
												
													
														|  | 
 |  | +		}
 | 
											
												
													
														|  | 
 |  | +	}
 | 
											
												
													
														|  | 
 |  | +	return reconnected;
 | 
											
												
													
														|  | 
 |  | +}
 | 
											
												
													
														|  | 
 |  | +*/
 | 
											
												
													
														|  | 
 |  | +
 |