| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247 | 
							- //	Copyright (C) 2013 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 "diagnostic.h"
 
- #include <string.h>
 
- static const uint8_t SupportedDiagnosticPages[] =
 
- {
 
- 0x00, // Page Code
 
- 0x00, // Reserved
 
- 0x02, // Page length
 
- 0x00, // Support "Supported diagnostic page"
 
- 0x40  // Support "Translate address page"
 
- };
 
- void scsiSendDiagnostic()
 
- {
 
- 	// SEND DIAGNOSTIC
 
- 	// Pretend to do self-test. Actual data is returned via the
 
- 	// RECEIVE DIAGNOSTIC RESULTS command.
 
- 	int selfTest = scsiDev.cdb[1] & 0x04;
 
- 	uint32_t paramLength =
 
- 		(((uint32_t) scsiDev.cdb[3]) << 8) +
 
- 		scsiDev.cdb[4];
 
- 	if (!selfTest)
 
- 	{
 
- 		// Initiator sends us page data.
 
- 		scsiDev.dataLen = paramLength;
 
- 		scsiDev.phase = DATA_OUT;
 
- 		if (scsiDev.dataLen > sizeof (scsiDev.data))
 
- 		{
 
- 			// Nowhere to store this data!
 
- 			// Shouldn't happen - our buffer should be many magnitudes larger
 
- 			// than the required size for diagnostic parameters.
 
- 			scsiDev.target->sense.code = ILLEGAL_REQUEST;
 
- 			scsiDev.target->sense.asc = INVALID_FIELD_IN_CDB;
 
- 			scsiDev.status = CHECK_CONDITION;
 
- 			scsiDev.phase = STATUS;
 
- 		}
 
- 	}
 
- 	else
 
- 	{
 
- 		// Default command result will be a status of GOOD anyway.
 
- 	}
 
- }
 
- void scsiReceiveDiagnostic()
 
- {
 
- 	// RECEIVE DIAGNOSTIC RESULTS
 
- 	// We assume scsiDev.data contains the contents of a previous
 
- 	// SEND DIAGNOSTICS command.  We only care about the page-code part
 
- 	// of the parameter list.
 
- 	uint8_t pageCode = scsiDev.data[0];
 
- 	int allocLength =
 
- 		(((uint16_t) scsiDev.cdb[3]) << 8) +
 
- 		scsiDev.cdb[4];
 
- 	if (pageCode == 0x00)
 
- 	{
 
- 		memcpy(
 
- 			scsiDev.data,
 
- 			SupportedDiagnosticPages,
 
- 			sizeof(SupportedDiagnosticPages));
 
- 		scsiDev.dataLen = sizeof(SupportedDiagnosticPages);
 
- 		scsiDev.phase = DATA_IN;
 
- 	}
 
- 	else if (pageCode == 0x40)
 
- 	{
 
- 		// Translate between logical block address, physical sector address, or
 
- 		// physical bytes.
 
- 		uint8_t suppliedFmt = scsiDev.data[4] & 0x7;
 
- 		uint8_t translateFmt = scsiDev.data[5] & 0x7;
 
- 		// Convert each supplied address back to a simple
 
- 		// 64bit linear address, then convert back again.
 
- 		uint64_t fromByteAddr =
 
- 			scsiByteAddress(
 
- 				scsiDev.target->liveCfg.bytesPerSector,
 
- 				scsiDev.target->cfg->headsPerCylinder,
 
- 				scsiDev.target->cfg->sectorsPerTrack,
 
- 				suppliedFmt,
 
- 				&scsiDev.data[6]);
 
- 		scsiSaveByteAddress(
 
- 			scsiDev.target->liveCfg.bytesPerSector,
 
- 			scsiDev.target->cfg->headsPerCylinder,
 
- 			scsiDev.target->cfg->sectorsPerTrack,
 
- 			translateFmt,
 
- 			fromByteAddr,
 
- 			&scsiDev.data[6]);
 
- 		// Fill out the rest of the response.
 
- 		// (Clear out any optional bits).
 
- 		scsiDev.data[4] = suppliedFmt;
 
- 		scsiDev.data[5] = translateFmt;
 
- 		scsiDev.dataLen = 14;
 
- 		scsiDev.phase = DATA_IN;
 
- 	}
 
- 	else
 
- 	{
 
- 		// error.
 
- 		scsiDev.status = CHECK_CONDITION;
 
- 		scsiDev.target->sense.code = ILLEGAL_REQUEST;
 
- 		scsiDev.target->sense.asc = INVALID_FIELD_IN_CDB;
 
- 		scsiDev.phase = STATUS;
 
- 	}
 
- 	if (scsiDev.phase == DATA_IN && scsiDev.dataLen > allocLength)
 
- 	{
 
- 		// simply truncate the response.
 
- 		scsiDev.dataLen = allocLength;
 
- 	}
 
- 	{
 
- 		// Set the first byte to indicate LUN presence.
 
- 		if (scsiDev.lun) // We only support lun 0
 
- 		{
 
- 			scsiDev.data[0] = 0x7F;
 
- 		}
 
- 	}
 
- }
 
- void scsiReadBuffer()
 
- {
 
- 	// READ BUFFER
 
- 	// Used for testing the speed of the SCSI interface.
 
- 	uint8_t mode = scsiDev.data[1] & 7;
 
- 	int allocLength =
 
- 		(((uint32_t) scsiDev.cdb[6]) << 16) +
 
- 		(((uint32_t) scsiDev.cdb[7]) << 8) +
 
- 		scsiDev.cdb[8];
 
- 	if (mode == 0)
 
- 	{
 
- 		uint32_t maxSize = sizeof(scsiDev.data) - 4;
 
- 		// 4 byte header
 
- 		scsiDev.data[0] = 0;
 
- 		scsiDev.data[1] = (maxSize >> 16) & 0xff;
 
- 		scsiDev.data[2] = (maxSize >> 8) & 0xff;
 
- 		scsiDev.data[3] = maxSize & 0xff;
 
- 		scsiDev.dataLen =
 
- 			(allocLength > sizeof(scsiDev.data)) ? sizeof(scsiDev.data) : allocLength;
 
- 		scsiDev.phase = DATA_IN;
 
- 	}
 
- 	else if (mode == 0x2 && (scsiDev.cdb[2] == 0))
 
- 	{
 
- 		// TODO support BUFFER OFFSET fields in CDB
 
- 		scsiDev.dataLen =
 
- 			(allocLength > sizeof(scsiDev.data)) ? sizeof(scsiDev.data) : allocLength;
 
- 		scsiDev.phase = DATA_IN;
 
- 	}
 
- 	else if (mode == 0x3)
 
- 	{
 
- 		uint32_t maxSize = sizeof(scsiDev.data) - 4;
 
- 		// 4 byte header
 
- 		scsiDev.data[0] = 0;
 
- 		scsiDev.data[1] = (maxSize >> 16) & 0xff;
 
- 		scsiDev.data[2] = (maxSize >> 8) & 0xff;
 
- 		scsiDev.data[3] = maxSize & 0xff;
 
- 		scsiDev.dataLen =
 
- 			(allocLength > 4) ? 4: allocLength;
 
- 		scsiDev.phase = DATA_IN;
 
- 	}
 
- 	else
 
- 	{
 
- 		// error.
 
- 		scsiDev.status = CHECK_CONDITION;
 
- 		scsiDev.target->sense.code = ILLEGAL_REQUEST;
 
- 		scsiDev.target->sense.asc = INVALID_FIELD_IN_CDB;
 
- 		scsiDev.phase = STATUS;
 
- 	}
 
- }
 
- // Callback after the DATA OUT phase is complete.
 
- static void doWriteBuffer(void)
 
- {
 
- 	if (scsiDev.status == GOOD) // skip if we've already encountered an error
 
- 	{
 
- 		// scsiDev.dataLen bytes are in scsiDev.data
 
- 		// Don't shift it down 4 bytes ... this space is taken by
 
- 		// the read buffer header anyway
 
- 		scsiDev.phase = STATUS;
 
- 	}
 
- }
 
- void scsiWriteBuffer()
 
- {
 
- 	// WRITE BUFFER
 
- 	// Used for testing the speed of the SCSI interface.
 
- 	uint8_t mode = scsiDev.data[1] & 7;
 
- 	int allocLength =
 
- 		(((uint32_t) scsiDev.cdb[6]) << 16) +
 
- 		(((uint32_t) scsiDev.cdb[7]) << 8) +
 
- 		scsiDev.cdb[8];
 
- 	if ((mode == 0 || mode == 2) && allocLength <= sizeof(scsiDev.data))
 
- 	{
 
- 		scsiDev.dataLen = allocLength;
 
- 		scsiDev.phase = DATA_OUT;
 
- 		scsiDev.postDataOutHook = doWriteBuffer;
 
- 	}
 
- 	else
 
- 	{
 
- 		// error.
 
- 		scsiDev.status = CHECK_CONDITION;
 
- 		scsiDev.target->sense.code = ILLEGAL_REQUEST;
 
- 		scsiDev.target->sense.asc = INVALID_FIELD_IN_CDB;
 
- 		scsiDev.phase = STATUS;
 
- 	}
 
- }
 
- // XEBEC specific command. See
 
- // http://www.bitsavers.org/pdf/westernDigital/WD100x/79-000004_WD1002-SHD_OEM_Manual_Aug1984.pdf
 
- // Section 4.3.14
 
- void scsiWriteSectorBuffer()
 
- {
 
- 	scsiDev.dataLen = scsiDev.target->liveCfg.bytesPerSector;
 
- 	scsiDev.phase = DATA_OUT;
 
- 	scsiDev.postDataOutHook = doWriteBuffer;
 
- }
 
 
  |