|
|
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 {};
};
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.