File:  [Isaki's NoNo m68k/m88k emulator] / nono / vm / scsicmd.h
Revision 1.1.1.9 (vendor branch): download - view: text, annotated - select for diffs
Wed Apr 29 17:06:01 2026 UTC (2 months, 3 weeks ago) by root
Branches: MAIN, Isaki
CVS tags: v027, HEAD
nono 1.7.0

//
// nono
// Copyright (C) 2021 nono project
// Licensed under nono-license.txt
//

//
// SCSI コマンド
//

#pragma once

#include "scsi.h"
#include <vector>

// READ/WRITE は多すぎるのでログを省略したい場合に定義。
//#define NO_READWRITE_LOG

class SCSIDisk;
class SCSITarget;

//
// SCSI コマンドの基本クラス
// (黙って成功するコマンドとしても使用可能)
//
class SCSICmd
{
 public:
	explicit SCSICmd(SCSITarget *parent_);
	virtual ~SCSICmd();

	// 転送バッファと転送バイト数。
	// IN (ターゲットが送出側)なら、各フェーズ開始までに送出バイト数分の
	// バッファを buf に用意すること。recvbytes は操作不要。
	//
	// OUT(ターゲットが受信側)なら、各フェーズ開始前までに受信バイト数を
	// recvbytes にセットすること。buf は操作不要。
	// なお parent は OUT(受信)フェーズ中にこの recvbytes を変更しない。
	std::vector<uint8> buf {};
	uint32 recvbytes {};

	// このコマンドの動作時間 [tsec]
	// シークタイムとかを簡易的に再現するため、次フェーズ遷移時の最初の
	// REQ アサートを引き延ばすために使う。
	// 主にコマンドフェーズで使うことになると思う。
	uint64 optime {};

	// 以下いずれも戻り値は遷移先のフェーズ。

	// コマンドフェーズを処理する。
	// コマンドが確定したところで呼ばれる。戻り値に遷移先フェーズを返すこと。
	// また、コマンド開始時に各自で ClearSense() を呼ぶこと。センスというか
	// CA 状態は次のコマンド実行でクリアされるが (ネクサスはとりあえず無視)、
	// RequestSense の場合は現在保持しているセンス情報をホストに返すので、
	// つまり RequestSense 以外のコマンドが全員各自でクリアする必要がある。
	virtual SCSI::XferPhase ExecCommand(std::vector<uint8>& cmdseq);

	// データインフェーズを完了する。
	virtual SCSI::XferPhase DoneDataIn() {
		return SCSI::XferPhase::Status;
	}

	// データアウトフェーズを完了する。
	virtual SCSI::XferPhase DoneDataOut() {
		return SCSI::XferPhase::Status;
	}

	// ステータスフェーズを開始する。
	void BeginStatus() {
		buf.clear();
		buf.push_back(status_byte);
	}

	// ステータスフェーズを完了する。
	virtual SCSI::XferPhase DoneStatus() {
		return SCSI::XferPhase::MsgIn;
	}

	// メッセージインフェーズを開始する。
	// デフォルトでは Command Complete を返す実装を用意しておく。
	virtual void BeginMsgIn() {
		buf.clear();
		buf.push_back((uint8)SCSI::MsgByte::CommandComplete);
	}

	// メッセージインフェーズを完了する。
	virtual SCSI::XferPhase DoneMsgIn() {
		return SCSI::XferPhase::End;
	}

	// メッセージアウトフェーズを開始する。
	virtual void BeginMsgOut() { }

	// メッセージアウトフェーズを完了する。
	virtual SCSI::XferPhase DoneMsgOut() {
		return SCSI::XferPhase::End;
	}

	// ターゲットデバイスを取得。
	SCSITarget *GetTarget() const noexcept { return parent; }

 protected:
	// このコマンドを実行しているターゲットデバイス。
	SCSITarget *parent {};

	// ステータスバイト (デフォルトは 0 = Good)
	uint8 status_byte {};
};

//
// SCSI コマンド: サポートしていないコマンド
//
class SCSICmdNotSupportedCommand : public SCSICmd
{
	using inherited = SCSICmd;
 public:
	explicit SCSICmdNotSupportedCommand(SCSITarget *);
	~SCSICmdNotSupportedCommand() override = default;

	SCSI::XferPhase ExecCommand(std::vector<uint8>& cmdseq) override;
};

//
// SCSI コマンド 0x03 RequestSense (共通)
//
class SCSICmdRequestSense : public SCSICmd
{
	using inherited = SCSICmd;
 public:
	explicit SCSICmdRequestSense(SCSITarget *);
	~SCSICmdRequestSense() override = default;

	SCSI::XferPhase ExecCommand(std::vector<uint8>& cmdseq) override;
};

//
// SCSI コマンド 0x08 Read(6)  (DA / CD-ROM)
//               0x28 Read(10) (DA / CD-ROM)
//
class SCSICmdRead : public SCSICmd
{
	using inherited = SCSICmd;
 public:
	explicit SCSICmdRead(SCSIDisk *);
	~SCSICmdRead() override = default;

	SCSI::XferPhase ExecCommand(std::vector<uint8>& cmdseq) override;

 private:
	SCSIDisk *disk {};
};

//
// SCSI コマンド 0x0a Write(6)  (DA / CD-ROM)
//               0x2a Write(10) (DA / CD-ROM)
//
class SCSICmdWrite : public SCSICmd
{
	using inherited = SCSICmd;
 public:
	explicit SCSICmdWrite(SCSIDisk *);
	~SCSICmdWrite() override = default;

	SCSI::XferPhase ExecCommand(std::vector<uint8>& cmdseq) override;
	SCSI::XferPhase DoneDataOut() override;

 private:
	uint8 cmd {};
	SCSIDisk *disk {};
	uint32 lba {};
	uint32 blks {};
};

//
// SCSI コマンド 0x12 Inquiry (共通)
//
class SCSICmdInquiry : public SCSICmd
{
	using inherited = SCSICmd;
 public:
	explicit SCSICmdInquiry(SCSITarget *);
	~SCSICmdInquiry() override = default;

	SCSI::XferPhase ExecCommand(std::vector<uint8>& cmdseq) override;
};

//
// SCSI コマンド 0x15 ModeSelect(6)  (共通)
//               0x55 ModeSelect(10) (共通)
//
class SCSICmdModeSelect : public SCSICmd
{
	using inherited = SCSICmd;
 public:
	explicit SCSICmdModeSelect(SCSITarget *);
	~SCSICmdModeSelect() override = default;

	SCSI::XferPhase ExecCommand(std::vector<uint8>& cmdseq) override;
	SCSI::XferPhase DoneDataOut() override;

 private:
	uint8 cmd {};
};

//
// SCSI コマンド 0x1a ModeSense(6)  (共通)
//               0x5a ModeSense(10) (共通)
//
class SCSICmdModeSense : public SCSICmd
{
	using inherited = SCSICmd;
 public:
	explicit SCSICmdModeSense(SCSITarget *);
	~SCSICmdModeSense() override = default;

	SCSI::XferPhase ExecCommand(std::vector<uint8>& cmdseq) override;

 private:
	// Page Control
	enum PC {
		Current		= 0x00,	// 現在値
		Changeable	= 0x01,	// 変更可能値
		Default		= 0x02,	// デフォルト値
		Saved		= 0x03,	// セーブ値
	};
	// ページ処理関数の戻り値 (この値は大小比較する)
	enum ModePageResult {
		NotSupported	= -1,	// 未実装や知らないページ
		Failed			= 0,	// 対応しない/出来ないと分かっているページ
		Success			= 1,	// 成功
	};

	using PageFunc = ModePageResult (SCSICmdModeSense::*)();

	// 個別ページ処理
	ModePageResult AddNotSupportedPage();
	ModePageResult AddEmptyPage();
	ModePageResult AddCachingPage();

	// ページ処理関数のため
	uint pagecode {};
	PC pc {};

	// ログ用の文字列
	std::string log {};

	static const std::vector<std::pair<uint8, PageFunc>> Pagelist;
};

//
// SCSI コマンド 0x1b StartStopUnit (DA / CD-ROM)
//
class SCSICmdStartStopUnit : public SCSICmd
{
	using inherited = SCSICmd;
 public:
	explicit SCSICmdStartStopUnit(SCSIDisk *);
	~SCSICmdStartStopUnit() override = default;

	SCSI::XferPhase ExecCommand(std::vector<uint8>& cmdseq) override;

 private:
	SCSIDisk *disk {};
};

//
// SCSI コマンド 0x1e PreventAllowMediumRemoval (DA / CD-ROM)
//
class SCSICmdPreventAllowMediumRemoval : public SCSICmd
{
	using inherited = SCSICmd;
 public:
	explicit SCSICmdPreventAllowMediumRemoval(SCSIDisk *);
	~SCSICmdPreventAllowMediumRemoval() override = default;

	SCSI::XferPhase ExecCommand(std::vector<uint8>& cmdseq) override;

 private:
	SCSIDisk *disk {};
};

//
// SCSI コマンド 0x25 ReadCapacity        (DA)
//               0x25 Read CDROM Capacity (CD-ROM)
// (ここでは ReadCapacity として同一視する)
//
class SCSICmdReadCapacity : public SCSICmd
{
	using inherited = SCSICmd;
 public:
	explicit SCSICmdReadCapacity(SCSIDisk *);
	~SCSICmdReadCapacity() override = default;

	SCSI::XferPhase ExecCommand(std::vector<uint8>& cmdseq) override;

 private:
	SCSIDisk *disk {};
};

//
// SCSI コマンド 0x43 ReadTOC (CD-ROM)
//
class SCSICmdReadTOC : public SCSICmd
{
	using inherited = SCSICmd;
 public:
	explicit SCSICmdReadTOC(SCSIDisk *);
	~SCSICmdReadTOC() override = default;

	SCSI::XferPhase ExecCommand(std::vector<uint8>& cmdseq) override;

 private:
	SCSIDisk *disk {};
};

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.