Files
RASCSI/src/raspberrypi/devices/scsihd.cpp
2021-01-30 14:08:09 -06:00

269 lines
6.2 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//---------------------------------------------------------------------------
//
// SCSI Target Emulator RaSCSI (*^..^*)
// for Raspberry Pi
//
// Copyright (C) 2001-2006 (ytanaka@ipc-tokai.or.jp)
// Copyright (C) 2014-2020 GIMONS
// Copyright (C) akuker
//
// Licensed under the BSD 3-Clause License.
// See LICENSE file in the project root folder.
//
// [ SCSI hard disk ]
//
//---------------------------------------------------------------------------
#include "scsihd.h"
#include "xm6.h"
#include "fileio.h"
//===========================================================================
//
// SCSI Hard Disk
//
//===========================================================================
//---------------------------------------------------------------------------
//
// Constructor
//
//---------------------------------------------------------------------------
SCSIHD::SCSIHD() : Disk()
{
// SCSI Hard Disk
disk.id = MAKEID('S', 'C', 'H', 'D');
}
//---------------------------------------------------------------------------
//
// Reset
//
//---------------------------------------------------------------------------
void FASTCALL SCSIHD::Reset()
{
// Unlock and release attention
disk.lock = FALSE;
disk.attn = FALSE;
// No reset, clear code
disk.reset = FALSE;
disk.code = 0x00;
}
//---------------------------------------------------------------------------
//
// Open
//
//---------------------------------------------------------------------------
BOOL FASTCALL SCSIHD::Open(const Filepath& path, BOOL /*attn*/)
{
Fileio fio;
off64_t size;
ASSERT(this);
ASSERT(!disk.ready);
// read open required
if (!fio.Open(path, Fileio::ReadOnly)) {
return FALSE;
}
// Get file size
size = fio.GetFileSize();
fio.Close();
// Must be 512 bytes
if (size & 0x1ff) {
return FALSE;
}
// 10MB or more
if (size < 0x9f5400) {
return FALSE;
}
// 2TB according to xm6i
// There is a similar one in wxw/wxw_cfg.cpp
if (size > 2LL * 1024 * 1024 * 1024 * 1024) {
return FALSE;
}
// sector size and number of blocks
disk.size = 9;
disk.blocks = (DWORD)(size >> 9);
// Call base class
return Disk::Open(path);
}
//---------------------------------------------------------------------------
//
// INQUIRY
//
//---------------------------------------------------------------------------
int FASTCALL SCSIHD:: Inquiry(
const DWORD *cdb, BYTE *buf, DWORD major, DWORD minor)
{
char vendor[32];
char product[32];
char rev[32];
int size;
ASSERT(this);
ASSERT(cdb);
ASSERT(buf);
ASSERT(cdb[0] == 0x12);
// EVPD check
if (cdb[1] & 0x01) {
disk.code = DISK_INVALIDCDB;
return 0;
}
// Ready check (Error if no image file)
if (!disk.ready) {
disk.code = DISK_NOTREADY;
return 0;
}
// Basic data
// buf[0] ... Direct Access Device
// buf[2] ... SCSI-2 compliant command system
// buf[3] ... SCSI-2 compliant Inquiry response
// buf[4] ... Inquiry additional data
memset(buf, 0, 8);
// SCSI-2 p.104 4.4.3 Incorrect logical unit handling
if (((cdb[1] >> 5) & 0x07) != disk.lun) {
buf[0] = 0x7f;
}
buf[2] = 0x02;
buf[3] = 0x02;
buf[4] = 122 + 3; // Value close to real HDD
// Fill with blanks
memset(&buf[8], 0x20, buf[4] - 3);
// Determine vendor name/product name
sprintf(vendor, BENDER_SIGNATURE);
size = disk.blocks >> 11;
if (size < 300)
sprintf(product, "PRODRIVE LPS%dS", size);
else if (size < 600)
sprintf(product, "MAVERICK%dS", size);
else if (size < 800)
sprintf(product, "LIGHTNING%dS", size);
else if (size < 1000)
sprintf(product, "TRAILBRAZER%dS", size);
else if (size < 2000)
sprintf(product, "FIREBALL%dS", size);
else
sprintf(product, "FBSE%d.%dS", size / 1000, (size % 1000) / 100);
// Vendor name
memcpy(&buf[8], vendor, strlen(vendor));
// Product name
memcpy(&buf[16], product, strlen(product));
// Revision
sprintf(rev, "0%01d%01d%01d",
(int)major, (int)(minor >> 4), (int)(minor & 0x0f));
memcpy(&buf[32], rev, 4);
// Size of data that can be returned
size = (buf[4] + 5);
// Limit if the other buffer is small
if (size > (int)cdb[4]) {
size = (int)cdb[4];
}
// Success
disk.code = DISK_NOERROR;
return size;
}
//---------------------------------------------------------------------------
//
// MODE SELECT
// *Not affected by disk.code
//
//---------------------------------------------------------------------------
BOOL FASTCALL SCSIHD::ModeSelect(const DWORD *cdb, const BYTE *buf, int length)
{
BYTE page;
int size;
ASSERT(this);
ASSERT(buf);
ASSERT(length >= 0);
// PF
if (cdb[1] & 0x10) {
// Mode Parameter header
if (length >= 12) {
// Check the block length bytes
size = 1 << disk.size;
if (buf[9] != (BYTE)(size >> 16) ||
buf[10] != (BYTE)(size >> 8) ||
buf[11] != (BYTE)size) {
// currently does not allow changing sector length
disk.code = DISK_INVALIDPRM;
return FALSE;
}
buf += 12;
length -= 12;
}
// Parsing the page
while (length > 0) {
// Get page
page = buf[0];
switch (page) {
// format device
case 0x03:
// check the number of bytes in the physical sector
size = 1 << disk.size;
if (buf[0xc] != (BYTE)(size >> 8) ||
buf[0xd] != (BYTE)size) {
// currently does not allow changing sector length
disk.code = DISK_INVALIDPRM;
return FALSE;
}
break;
// CD-ROM Parameters
// According to the SONY CDU-541 manual, Page code 8 is supposed
// to set the Logical Block Adress Format, as well as the
// inactivity timer multiplier
case 0x08:
// Debug code for Issue #2:
// https://github.com/akuker/RASCSI/issues/2
LOGWARN("[Unhandled page code] Received mode page code 8 with total length %d\n ", length);
for (int i = 0; i<length; i++)
{
printf("%02X ", buf[i]);
}
printf("\n");
break;
// Other page
default:
printf("Unknown Mode Select page code received: %02X\n",page);
break;
}
// Advance to the next page
size = buf[1] + 2;
length -= size;
buf += size;
}
}
// Do not generate an error for the time being (MINIX)
disk.code = DISK_NOERROR;
return TRUE;
}