mirror of
https://github.com/akuker/RASCSI.git
synced 2024-11-26 13:49:21 +00:00
422 lines
8.5 KiB
C++
422 lines
8.5 KiB
C++
|
//---------------------------------------------------------------------------
|
|||
|
//
|
|||
|
// SCSI Target Emulator RaSCSI (*^..^*)
|
|||
|
// for Raspberry Pi
|
|||
|
//
|
|||
|
// Copyright (C) 2001-2006 PI.(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 Magneto-Optical Disk]
|
|||
|
//
|
|||
|
//---------------------------------------------------------------------------
|
|||
|
|
|||
|
#include "scsimo.h"
|
|||
|
#include "xm6.h"
|
|||
|
#include "fileio.h"
|
|||
|
|
|||
|
//===========================================================================
|
|||
|
//
|
|||
|
// SCSI magneto-optical disk
|
|||
|
//
|
|||
|
//===========================================================================
|
|||
|
|
|||
|
//---------------------------------------------------------------------------
|
|||
|
//
|
|||
|
// Constructor
|
|||
|
//
|
|||
|
//---------------------------------------------------------------------------
|
|||
|
SCSIMO::SCSIMO() : Disk()
|
|||
|
{
|
|||
|
// SCSI magneto-optical disk
|
|||
|
disk.id = MAKEID('S', 'C', 'M', 'O');
|
|||
|
|
|||
|
// Set as removable
|
|||
|
disk.removable = TRUE;
|
|||
|
}
|
|||
|
|
|||
|
//---------------------------------------------------------------------------
|
|||
|
//
|
|||
|
// Open
|
|||
|
//
|
|||
|
//---------------------------------------------------------------------------
|
|||
|
BOOL FASTCALL SCSIMO::Open(const Filepath& path, BOOL attn)
|
|||
|
{
|
|||
|
Fileio fio;
|
|||
|
off64_t size;
|
|||
|
|
|||
|
ASSERT(this);
|
|||
|
ASSERT(!disk.ready);
|
|||
|
|
|||
|
// Open as read-only
|
|||
|
if (!fio.Open(path, Fileio::ReadOnly)) {
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
// Get file size
|
|||
|
size = fio.GetFileSize();
|
|||
|
fio.Close();
|
|||
|
|
|||
|
switch (size) {
|
|||
|
// 128MB
|
|||
|
case 0x797f400:
|
|||
|
disk.size = 9;
|
|||
|
disk.blocks = 248826;
|
|||
|
break;
|
|||
|
|
|||
|
// 230MB
|
|||
|
case 0xd9eea00:
|
|||
|
disk.size = 9;
|
|||
|
disk.blocks = 446325;
|
|||
|
break;
|
|||
|
|
|||
|
// 540MB
|
|||
|
case 0x1fc8b800:
|
|||
|
disk.size = 9;
|
|||
|
disk.blocks = 1041500;
|
|||
|
break;
|
|||
|
|
|||
|
// 640MB
|
|||
|
case 0x25e28000:
|
|||
|
disk.size = 11;
|
|||
|
disk.blocks = 310352;
|
|||
|
break;
|
|||
|
|
|||
|
// Other (this is an error)
|
|||
|
default:
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
// Call the base class
|
|||
|
Disk::Open(path);
|
|||
|
|
|||
|
// Attention if ready
|
|||
|
if (disk.ready && attn) {
|
|||
|
disk.attn = TRUE;
|
|||
|
}
|
|||
|
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
|
|||
|
#ifndef RASCSI
|
|||
|
//---------------------------------------------------------------------------
|
|||
|
//
|
|||
|
// Load
|
|||
|
//
|
|||
|
//---------------------------------------------------------------------------
|
|||
|
BOOL FASTCALL SCSIMO::Load(Fileio *fio, int ver)
|
|||
|
{
|
|||
|
DWORD sz;
|
|||
|
disk_t buf;
|
|||
|
DWORD padding;
|
|||
|
Filepath path;
|
|||
|
|
|||
|
ASSERT(this);
|
|||
|
ASSERT(fio);
|
|||
|
ASSERT(ver >= 0x0200);
|
|||
|
|
|||
|
// Prior to version 2.03, the disk was not saved
|
|||
|
if (ver <= 0x0202) {
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
|
|||
|
// load size, match
|
|||
|
if (!fio->Read(&sz, sizeof(sz))) {
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
if (sz != 52) {
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
// load into buffer
|
|||
|
PROP_IMPORT(fio, buf.id);
|
|||
|
PROP_IMPORT(fio, buf.ready);
|
|||
|
PROP_IMPORT(fio, buf.writep);
|
|||
|
PROP_IMPORT(fio, buf.readonly);
|
|||
|
PROP_IMPORT(fio, buf.removable);
|
|||
|
PROP_IMPORT(fio, buf.lock);
|
|||
|
PROP_IMPORT(fio, buf.attn);
|
|||
|
PROP_IMPORT(fio, buf.reset);
|
|||
|
PROP_IMPORT(fio, buf.size);
|
|||
|
PROP_IMPORT(fio, buf.blocks);
|
|||
|
PROP_IMPORT(fio, buf.lun);
|
|||
|
PROP_IMPORT(fio, buf.code);
|
|||
|
PROP_IMPORT(fio, padding);
|
|||
|
|
|||
|
// Load path
|
|||
|
if (!path.Load(fio, ver)) {
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
// Always eject
|
|||
|
Eject(TRUE);
|
|||
|
|
|||
|
// Move only if IDs match
|
|||
|
if (disk.id != buf.id) {
|
|||
|
// Not MO at the time of save. Maintain eject status
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
|
|||
|
// Re-try opening
|
|||
|
if (!Open(path, FALSE)) {
|
|||
|
// Cannot reopen. Maintain eject status
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
|
|||
|
// Disk cache is created in Open. Move property only
|
|||
|
if (!disk.readonly) {
|
|||
|
disk.writep = buf.writep;
|
|||
|
}
|
|||
|
disk.lock = buf.lock;
|
|||
|
disk.attn = buf.attn;
|
|||
|
disk.reset = buf.reset;
|
|||
|
disk.lun = buf.lun;
|
|||
|
disk.code = buf.code;
|
|||
|
|
|||
|
// loaded successfully
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
#endif // RASCSI
|
|||
|
|
|||
|
//---------------------------------------------------------------------------
|
|||
|
//
|
|||
|
// INQUIRY
|
|||
|
//
|
|||
|
//---------------------------------------------------------------------------
|
|||
|
int FASTCALL SCSIMO::Inquiry(
|
|||
|
const DWORD *cdb, BYTE *buf, DWORD major, DWORD minor)
|
|||
|
{
|
|||
|
int size;
|
|||
|
char rev[32];
|
|||
|
|
|||
|
ASSERT(this);
|
|||
|
ASSERT(cdb);
|
|||
|
ASSERT(buf);
|
|||
|
ASSERT(cdb[0] == 0x12);
|
|||
|
|
|||
|
// EVPD check
|
|||
|
if (cdb[1] & 0x01) {
|
|||
|
disk.code = DISK_INVALIDCDB;
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
// 基本データ
|
|||
|
// buf[0] ... Optical Memory Device
|
|||
|
// buf[1] ... Removable
|
|||
|
// buf[2] ... SCSI-2 compliant command system
|
|||
|
// buf[3] ... SCSI-2 compliant Inquiry response
|
|||
|
// buf[4] ... Inquiry additional data
|
|||
|
memset(buf, 0, 8);
|
|||
|
buf[0] = 0x07;
|
|||
|
|
|||
|
// SCSI-2 p.104 4.4.3 Incorrect logical unit handling
|
|||
|
if (((cdb[1] >> 5) & 0x07) != disk.lun) {
|
|||
|
buf[0] = 0x7f;
|
|||
|
}
|
|||
|
|
|||
|
buf[1] = 0x80;
|
|||
|
buf[2] = 0x02;
|
|||
|
buf[3] = 0x02;
|
|||
|
buf[4] = 36 - 5; // required
|
|||
|
|
|||
|
// Fill with blanks
|
|||
|
memset(&buf[8], 0x20, buf[4] - 3);
|
|||
|
|
|||
|
// Vendor name
|
|||
|
memcpy(&buf[8], BENDER_SIGNATURE, strlen(BENDER_SIGNATURE));
|
|||
|
|
|||
|
// Product name
|
|||
|
memcpy(&buf[16], "M2513A", 6);
|
|||
|
|
|||
|
// Revision (XM6 version number)
|
|||
|
sprintf(rev, "0%01d%01d%01d",
|
|||
|
(int)major, (int)(minor >> 4), (int)(minor & 0x0f));
|
|||
|
memcpy(&buf[32], rev, 4);
|
|||
|
|
|||
|
// Size return data
|
|||
|
size = (buf[4] + 5);
|
|||
|
|
|||
|
// Limit the size if the buffer is too 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 SCSIMO::ModeSelect(const DWORD *cdb, const BYTE *buf, int length)
|
|||
|
{
|
|||
|
int 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 (in 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 the 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;
|
|||
|
// vendor unique format
|
|||
|
case 0x20:
|
|||
|
// just ignore, for now
|
|||
|
break;
|
|||
|
|
|||
|
// Other page
|
|||
|
default:
|
|||
|
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;
|
|||
|
}
|
|||
|
|
|||
|
//---------------------------------------------------------------------------
|
|||
|
//
|
|||
|
// Vendor Unique Format Page 20h (MO)
|
|||
|
//
|
|||
|
//---------------------------------------------------------------------------
|
|||
|
int FASTCALL SCSIMO::AddVendor(int page, BOOL change, BYTE *buf)
|
|||
|
{
|
|||
|
ASSERT(this);
|
|||
|
ASSERT(buf);
|
|||
|
|
|||
|
// Page code 20h
|
|||
|
if ((page != 0x20) && (page != 0x3f)) {
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
// Set the message length
|
|||
|
buf[0] = 0x20;
|
|||
|
buf[1] = 0x0a;
|
|||
|
|
|||
|
// No changeable area
|
|||
|
if (change) {
|
|||
|
return 12;
|
|||
|
}
|
|||
|
|
|||
|
/*
|
|||
|
mode page code 20h - Vendor Unique Format Page
|
|||
|
format mode XXh type 0
|
|||
|
information: http://h20628.www2.hp.com/km-ext/kmcsdirect/emr_na-lpg28560-1.pdf
|
|||
|
|
|||
|
offset description
|
|||
|
02h format mode
|
|||
|
03h type of format (0)
|
|||
|
04~07h size of user band (total sectors?)
|
|||
|
08~09h size of spare band (spare sectors?)
|
|||
|
0A~0Bh number of bands
|
|||
|
|
|||
|
actual value of each 3.5inches optical medium (grabbed by Fujitsu M2513EL)
|
|||
|
|
|||
|
128M 230M 540M 640M
|
|||
|
---------------------------------------------------
|
|||
|
size of user band 3CBFAh 6CF75h FE45Ch 4BC50h
|
|||
|
size of spare band 0400h 0401h 08CAh 08C4h
|
|||
|
number of bands 0001h 000Ah 0012h 000Bh
|
|||
|
|
|||
|
further information: http://r2089.blog36.fc2.com/blog-entry-177.html
|
|||
|
*/
|
|||
|
|
|||
|
if (disk.ready) {
|
|||
|
unsigned spare = 0;
|
|||
|
unsigned bands = 0;
|
|||
|
|
|||
|
if (disk.size == 9) switch (disk.blocks) {
|
|||
|
// 128MB
|
|||
|
case 248826:
|
|||
|
spare = 1024;
|
|||
|
bands = 1;
|
|||
|
break;
|
|||
|
|
|||
|
// 230MB
|
|||
|
case 446325:
|
|||
|
spare = 1025;
|
|||
|
bands = 10;
|
|||
|
break;
|
|||
|
|
|||
|
// 540MB
|
|||
|
case 1041500:
|
|||
|
spare = 2250;
|
|||
|
bands = 18;
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
if (disk.size == 11) switch (disk.blocks) {
|
|||
|
// 640MB
|
|||
|
case 310352:
|
|||
|
spare = 2244;
|
|||
|
bands = 11;
|
|||
|
break;
|
|||
|
|
|||
|
// 1.3GB (lpproj: not tested with real device)
|
|||
|
case 605846:
|
|||
|
spare = 4437;
|
|||
|
bands = 18;
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
buf[2] = 0; // format mode
|
|||
|
buf[3] = 0; // type of format
|
|||
|
buf[4] = (BYTE)(disk.blocks >> 24);
|
|||
|
buf[5] = (BYTE)(disk.blocks >> 16);
|
|||
|
buf[6] = (BYTE)(disk.blocks >> 8);
|
|||
|
buf[7] = (BYTE)disk.blocks;
|
|||
|
buf[8] = (BYTE)(spare >> 8);
|
|||
|
buf[9] = (BYTE)spare;
|
|||
|
buf[10] = (BYTE)(bands >> 8);
|
|||
|
buf[11] = (BYTE)bands;
|
|||
|
}
|
|||
|
|
|||
|
return 12;
|
|||
|
}
|