| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338 | 
							- //	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 "device.h"
 
- #include "scsi.h"
 
- #include "mode.h"
 
- #include "disk.h"
 
- #include <string.h>
 
- static const uint8 DisconnectReconnectPage[] =
 
- {
 
- 0x02, // Page code
 
- 0x0E, // Page length
 
- 0, // Buffer full ratio
 
- 0, // Buffer empty ratio
 
- 0x00, 10, // Bus inactivity limit, 100us increments. Allow 1ms.
 
- 0x00, 0x00, // Disconnect time limit
 
- 0x00, 0x00, // Connect time limit
 
- 0x00, 0x00, // Maximum burst size
 
- 0x00 ,// DTDC. Not used.
 
- 0x00, 0x00, 0x00 // Reserved
 
- };
 
- static const uint8 FormatDevicePage[] =
 
- {
 
- 0x03, // Page code 
 
- 0x16, // Page length
 
- 0x00, 0x00, // Single zone
 
- 0x00, 0x00, // No alternate sectors
 
- 0x00, 0x00, // No alternate tracks
 
- 0x00, 0x00, // No alternate tracks per lun
 
- 0x00, SCSI_SECTORS_PER_TRACK, // Sectors per track
 
- SCSI_SECTOR_SIZE >> 8, SCSI_SECTOR_SIZE & 0xFF, // Data bytes per physical sector
 
- 0x00, 0x01, // Interleave
 
- 0x00, 0x00, // Track skew factor
 
- 0x00, 0x00, // Cylinder skew factor
 
- 0xC0, // SSEC(set) HSEC(set) RMB SURF
 
- 0x00, 0x00, 0x00 // Reserved
 
- };
 
- static const uint8 RigidDiskDriveGeometry[] =
 
- {
 
- 0x04, // Page code
 
- 0x16, // Page length
 
- 0xFF, 0xFF, 0xFF, // Number of cylinders
 
- SCSI_HEADS_PER_CYLINDER, // Number of heads
 
- 0xFF, 0xFF, 0xFF, // Starting cylinder-write precompensation
 
- 0xFF, 0xFF, 0xFF, // Starting cylinder-reduced write current
 
- 0x00, 0x1, // Drive step rate (units of 100ns)
 
- 0x00, 0x00, 0x00, // Landing zone cylinder
 
- 0x00, // RPL
 
- 0x00, // Rotational offset
 
- 0x00, // Reserved
 
- 5400 >> 8, 5400 & 0xFF, // Medium rotation rate (RPM)
 
- 0x00, 0x00 // Reserved
 
- };
 
- static const uint8 CachingPage[] =
 
- {
 
- 0x08, // Page Code
 
- 0x0A, // Page length
 
- 0x01, // Read cache disable
 
- 0x00, // No useful rention policy.
 
- 0x00, 0x00, // Pre-fetch always disabled
 
- 0x00, 0x00, // Minimum pre-fetch
 
- 0x00, 0x00, // Maximum pre-fetch
 
- 0x00, 0x00, // Maximum pre-fetch ceiling
 
- };
 
- static const uint8 ControlModePage[] =
 
- {
 
- 0x0A, // Page code
 
- 0x06, // Page length
 
- 0x00, // No logging
 
- 0x01, // Disable tagged queuing
 
- 0x00, // No async event notifications
 
- 0x00, // Reserved
 
- 0x00, 0x00 // AEN holdoff period.
 
- };
 
- // Allow Apple 68k Drive Setup to format this drive.
 
- // Code
 
- // TODO make this string configurable.
 
- static const uint8 AppleVendorPage[] =
 
- {
 
- 0x30, // Page code
 
- 28, // Page length
 
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
 
- 'A','P','P','L','E',' ','C','O','M','P','U','T','E','R',',',' ','I','N','C','.'
 
- };
 
- static void pageIn(int pc, int dataIdx, const uint8* pageData, int pageLen)
 
- {
 
- 	memcpy(&scsiDev.data[dataIdx], pageData, pageLen);
 
- 	if (pc == 0x01) // Mask out (un)changable values
 
- 	{
 
- 		memset(&scsiDev.data[dataIdx+2], 0, pageLen - 2);
 
- 	}
 
- }
 
- static void doModeSense(
 
- 	int sixByteCmd, int dbd, int pc, int pageCode, int allocLength)
 
- {
 
- 	// TODO Apple HD SC Drive Setup requests Page 3 (FormatDevicePage) with an
 
- 	// allocLength of 0x20. We need 0x24 if we include a block descriptor, and
 
- 	// thus return CHECK CONDITION. A block descriptor is optional, so we
 
- 	// chose to ignore it.
 
- 	// TODO make configurable
 
- 	dbd = 1;
 
- 	
 
- 	if (pc == 0x03) // Saved Values not supported.
 
- 	{
 
- 		scsiDev.status = CHECK_CONDITION;
 
- 		scsiDev.sense.code = ILLEGAL_REQUEST;
 
- 		scsiDev.sense.asc = SAVING_PARAMETERS_NOT_SUPPORTED;
 
- 		scsiDev.phase = STATUS;
 
- 	}
 
- 	else
 
- 	{
 
- 		////////////// Mode Parameter Header
 
- 		////////////////////////////////////
 
- 		// Skip the Mode Data Length, we set that last.
 
- 		int idx = 1;
 
- 		if (!sixByteCmd) ++idx;
 
- 		scsiDev.data[idx++] = 0; // Medium type. 0 = default
 
- 		// Device-specific parameter. Contains cache bits (0) and
 
- 		// a Write-Protect bit.
 
- 		scsiDev.data[idx++] = (blockDev.state & DISK_WP) ? 0x80 : 0;
 
- 		if (sixByteCmd)
 
- 		{
 
- 			if (dbd)
 
- 			{
 
- 				scsiDev.data[idx++] = 0; // No block descriptor
 
- 			}
 
- 			else
 
- 			{
 
- 				// One block descriptor of length 8 bytes.
 
- 				scsiDev.data[idx++] = 8;
 
- 			}
 
- 		}
 
- 		else
 
- 		{
 
- 			scsiDev.data[idx++] = 0; // Reserved
 
- 			scsiDev.data[idx++] = 0; // Reserved
 
- 			if (dbd)
 
- 			{
 
- 				scsiDev.data[idx++] = 0; // No block descriptor
 
- 				scsiDev.data[idx++] = 0; // No block descriptor
 
- 			}
 
- 			else
 
- 			{
 
- 				// One block descriptor of length 8 bytes.
 
- 				scsiDev.data[idx++] = 0;
 
- 				scsiDev.data[idx++] = 8;
 
- 			}
 
- 		}
 
- 		////////////// Block Descriptor
 
- 		////////////////////////////////////
 
- 		if (!dbd)
 
- 		{
 
- 			scsiDev.data[idx++] = 0; // Density code. Reserved for direct-access
 
- 			// Number of blocks
 
- 			// Zero == all remaining blocks shall have the medium
 
- 			// characteristics specified.
 
- 			scsiDev.data[idx++] = 0;
 
- 			scsiDev.data[idx++] = 0;
 
- 			scsiDev.data[idx++] = 0;
 
- 			scsiDev.data[idx++] = 0; // reserved
 
- 			// Block length
 
- 			scsiDev.data[idx++] = SCSI_BLOCK_SIZE >> 16;
 
- 			scsiDev.data[idx++] = SCSI_BLOCK_SIZE >> 8;
 
- 			scsiDev.data[idx++] = SCSI_BLOCK_SIZE & 0xFF;
 
- 		}
 
- 		int pageFound = 1;
 
- 		switch (pageCode)
 
- 		{
 
- 		case 0x3F:
 
- 			// EVERYTHING
 
- 		case 0x02:
 
- 			pageIn(pc, idx, DisconnectReconnectPage, sizeof(DisconnectReconnectPage));
 
- 			idx += sizeof(DisconnectReconnectPage);
 
- 			if (pageCode != 0x3f) break;
 
- 		case 0x03:
 
- 			pageIn(pc, idx, FormatDevicePage, sizeof(FormatDevicePage));
 
- 			idx += sizeof(FormatDevicePage);
 
- 			if (pageCode != 0x3f) break;
 
- 		case 0x04:
 
- 		{
 
- 			pageIn(pc, idx, RigidDiskDriveGeometry, sizeof(RigidDiskDriveGeometry));
 
- 			if (pc != 0x01)
 
- 			{
 
- 				// Need to fill out the number of cylinders.
 
- 				uint32 cyl;
 
- 				uint8 head;
 
- 				uint32 sector;
 
- 				LBA2CHS(blockDev.capacity, &cyl, &head, §or);
 
- 				scsiDev.data[idx+2] = cyl >> 16;
 
- 				scsiDev.data[idx+3] = cyl >> 8;
 
- 				scsiDev.data[idx+4] = cyl;
 
- 				memcpy(&scsiDev.data[idx+6], &scsiDev.data[idx+2], 3);
 
- 				memcpy(&scsiDev.data[idx+9], &scsiDev.data[idx+2], 3);
 
- 			}
 
- 			idx += sizeof(RigidDiskDriveGeometry);
 
- 			if (pageCode != 0x3f) break;
 
- 		}
 
- 		case 0x08:
 
- 			pageIn(pc, idx, CachingPage, sizeof(CachingPage));
 
- 			idx += sizeof(CachingPage);
 
- 			if (pageCode != 0x3f) break;
 
- 		case 0x0A:
 
- 			pageIn(pc, idx, ControlModePage, sizeof(ControlModePage));
 
- 			idx += sizeof(ControlModePage);
 
- 			break;
 
- 		case 0x30:
 
- 			pageIn(pc, idx, AppleVendorPage, sizeof(AppleVendorPage));
 
- 			idx += sizeof(AppleVendorPage);
 
- 			break;
 
- 			
 
- 		default:
 
- 			// Unknown Page Code
 
- 			pageFound = 0;
 
- 			scsiDev.status = CHECK_CONDITION;
 
- 			scsiDev.sense.code = ILLEGAL_REQUEST;
 
- 			scsiDev.sense.asc = INVALID_FIELD_IN_CDB;
 
- 			scsiDev.phase = STATUS;
 
- 		}
 
- 		if (idx > allocLength)
 
- 		{
 
- 			// Initiator may not have space to receive results.
 
- 			scsiDev.status = CHECK_CONDITION;
 
- 			scsiDev.sense.code = ILLEGAL_REQUEST;
 
- 			scsiDev.sense.asc = INVALID_FIELD_IN_CDB;
 
- 			scsiDev.phase = STATUS;
 
- 		}
 
- 		else if (pageFound)
 
- 		{
 
- 			// Go back and fill out the mode data length
 
- 			if (sixByteCmd)
 
- 			{
 
- 				// Cannot currently exceed limits. yay
 
- 				scsiDev.data[0] = idx - 1;
 
- 			}
 
- 			else
 
- 			{
 
- 				scsiDev.data[0] = ((idx - 2) >> 8);
 
- 				scsiDev.data[1] = (idx - 2);
 
- 			}
 
- 			scsiDev.dataLen = idx;
 
- 			scsiDev.phase = DATA_IN;
 
- 		}
 
- 		else
 
- 		{
 
- 			// Initiator may not have space to receive results.
 
- 			scsiDev.status = CHECK_CONDITION;
 
- 			scsiDev.sense.code = ILLEGAL_REQUEST;
 
- 			scsiDev.sense.asc = INVALID_FIELD_IN_CDB;
 
- 			scsiDev.phase = STATUS;
 
- 		}
 
- 	}
 
- }
 
- int scsiModeCommand()
 
- {
 
- 	int commandHandled = 1;
 
- 	uint8 command = scsiDev.cdb[0];
 
- 	// We don't currently support the setting of any parameters.
 
- 	// (ie. no MODE SELECT(6) or MODE SELECT(10) commands)
 
- 	if (command == 0x1A)
 
- 	{
 
- 		// MODE SENSE(6)
 
- 		int dbd = scsiDev.cdb[1] & 0x08; // Disable block descriptors
 
- 		int pc = scsiDev.cdb[2] >> 6; // Page Control
 
- 		int pageCode = scsiDev.cdb[2] & 0x3F;
 
- 		int allocLength = scsiDev.cdb[4];
 
- 		if (allocLength == 0) allocLength = 256;
 
- 		doModeSense(1, dbd, pc, pageCode, allocLength);
 
- 	}
 
- 	else if (command == 0x5A)
 
- 	{
 
- 		// MODE SENSE(10)
 
- 		int dbd = scsiDev.cdb[1] & 0x08; // Disable block descriptors
 
- 		int pc = scsiDev.cdb[2] >> 6; // Page Control
 
- 		int pageCode = scsiDev.cdb[2] & 0x3F;
 
- 		int allocLength =
 
- 			(((uint16) scsiDev.cdb[7]) << 8) +
 
- 			scsiDev.cdb[8];
 
- 		doModeSense(0, dbd, pc, pageCode, allocLength);
 
- 	}
 
- 	else
 
- 	{
 
- 		commandHandled = 0;
 
- 	}
 
- 	return commandHandled;
 
- }
 
 
  |