Annotation of nono/vm/scsidev.cpp, revision 1.1.1.1

1.1       root        1: //
                      2: // nono
                      3: // Copyright (C) 2020 [email protected]
                      4: //
                      5: 
                      6: // SCSI デバイス共通部分
                      7: 
                      8: #include "scsidev.h"
                      9: #include "configfile.h"
                     10: #include "mystring.h"
                     11: #include <fcntl.h>
                     12: #include <sys/mman.h>
                     13: #include <sys/stat.h>
                     14: 
                     15: //
                     16: // SCSI デバイス
                     17: //
                     18: 
                     19: // コンストラクタ
                     20: SCSIDevice::SCSIDevice()
                     21: {
                     22: }
                     23: 
                     24: // デストラクタ
                     25: SCSIDevice::~SCSIDevice()
                     26: {
                     27: }
                     28: 
                     29: //
                     30: // SCSI ホストデバイス
                     31: //
                     32: 
                     33: // コンストラクタ
                     34: SCSIHostDevice::SCSIHostDevice()
                     35: {
                     36:        // バスデバイスを作成する。
                     37:        // ただし自身がバスに参加するのは継承側で行う
                     38:        // (例えば SPC なら BDID 書き込みで ID が決まった後、など)。
                     39:        scsibus.reset(new SCSIBus());
                     40: }
                     41: 
                     42: // デストラクタ
                     43: SCSIHostDevice::~SCSIHostDevice()
                     44: {
                     45: }
                     46: 
                     47: bool
                     48: SCSIHostDevice::Create()
                     49: {
                     50:        // 設定を読み込む。
                     51:        for (int id = 0; id < 8; id++) {
                     52:                const std::string key = string_format("%s_id%d_devtype",
                     53:                        GetConfigName(), id);
                     54:                int devtype = gConfig->ReadInt(key);
                     55:                switch (devtype) {
                     56:                 case SCSI::HD:
                     57:                        target[id].reset(new SCSIHD(this, id));
                     58:                        scsibus->Attach(target[id].get(), id);
                     59:                        break;
                     60:                }
                     61:        }
                     62: 
                     63:        return true;
                     64: }
                     65: 
                     66: bool
                     67: SCSIHostDevice::Init()
                     68: {
                     69:        // 初期化ではないけどログレベルがセットできたここでデバッグ表示。
                     70:        // -L オプションの処理は Create() の後なので。
                     71: 
                     72:        if (loglevel >= 1) {
                     73:                for (int id = 0; id < 8; id++) {
                     74:                        std::string typestr;
                     75:                        if (target[id]) {
                     76:                                switch (target[id]->GetDevType()) {
                     77:                                 case SCSI::None:
                     78:                                        break;
                     79:                                 case SCSI::HD:
                     80:                                        typestr = "HD";
                     81:                                        break;
                     82:                                }
                     83:                        }
                     84:                        if (!typestr.empty()) {
                     85:                                putmsg("%s target #%d %s", GetConfigName(), id,
                     86:                                        typestr.c_str());
                     87:                        }
                     88:                }
                     89:        }
                     90: 
                     91:        return true;
                     92: }
                     93: 
                     94: // バスフリーコールバック (SCSIBus から呼ばれる)
                     95: void
                     96: SCSIHostDevice::BusFreeCB(int id)
                     97: {
                     98:        // 実際にはバスフリーを検出したデバイスは各自自身が送出している信号を
                     99:        // 下げるのだが、色々面倒なので、ここではホストのバスフリーコールバックが
                    100:        // 一括して全部の線を下げる。
                    101:        // ただしさすがにログがうるさいので、上がってる線だけ下げる。
                    102: 
                    103:        uint32 data;
                    104:        while ((data = GetBSY()) != 0) {
                    105:                bus->NegateBSY(DecodeID(data));
                    106:        }
                    107:        while ((data = GetSEL()) != 0) {
                    108:                bus->NegateSEL(DecodeID(data));
                    109:        }
                    110:        if (GetREQ()) {
                    111:                NegateREQ();
                    112:        }
                    113:        if (GetACK()) {
                    114:                NegateACK();
                    115:        }
                    116:        if (GetATN()) {
                    117:                NegateATN();
                    118:        }
                    119:        SetXfer(0);
                    120:        SetData(0);
                    121: }
                    122: 
                    123: //
                    124: // SCSI コマンドの共通部分
                    125: //
                    126: class SCSICmd
                    127: {
                    128:  public:
                    129:        SCSICmd(SCSITarget *p) {
                    130:                parent = p;
                    131:        }
                    132:        virtual ~SCSICmd() { }
                    133: 
                    134:        // 転送バッファと転送バイト数。
                    135:        // IN (ターゲットが送出側)なら、各フェーズ開始までに送出バイト数分の
                    136:        // バッファを buf に用意すること。recvbytes は操作不要。
                    137:        //
                    138:        // OUT(ターゲットが受信側)なら、各フェーズ開始前までに受信バイト数を
                    139:        // recvbytes にセットすること。buf は操作不要。
                    140:        // なお parent は OUT(受信)フェーズ中にこの recvbytes を変更しない。
                    141:        std::vector<uint8> buf;
                    142:        uint32 recvbytes;
                    143: 
                    144:        // 以下いずれも戻り値は遷移先のフェーズ。
                    145: 
                    146:        // コマンドフェーズを処理する。
                    147:        // コマンドが確定したところで呼ばれる。遷移先フェーズを返すこと。
                    148:        virtual SCSI::XferPhase Command(std::vector<uint8>& cmdseq) {
                    149:                return SCSI::XferPhase::Status;
                    150:        }
                    151: 
                    152:        // データインフェーズを開始する。
                    153:        virtual void BeginDataIn() { }
                    154: 
                    155:        // データインフェーズを完了する。
                    156:        virtual SCSI::XferPhase DoneDataIn() { return SCSI::XferPhase::Status; }
                    157: 
                    158:        // データアウトフェーズを開始する。
                    159:        virtual void BeginDataOut() { }
                    160: 
                    161:        // データアウトフェーズを完了する。
                    162:        virtual SCSI::XferPhase DoneDataOut() { return SCSI::XferPhase::Status; }
                    163: 
                    164:        // ステータスフェーズを開始する。
                    165:        // デフォルトでは Good を返す実装を用意しておく。
                    166:        virtual void BeginStatus() {
                    167:                buf.clear();
                    168:                buf.push_back((uint8)SCSI::StatusByte::Good);
                    169:        }
                    170: 
                    171:        // ステータスフェーズを完了する。
                    172:        virtual SCSI::XferPhase DoneStatus() { return SCSI::XferPhase::MsgIn; }
                    173: 
                    174:        // メッセージインフェーズを開始する。
                    175:        // デフォルトでは Command Complete を返す実装を用意しておく。
                    176:        virtual void BeginMsgIn() {
                    177:                buf.clear();
                    178:                buf.push_back((uint8)SCSI::MsgByte::CommandComplete);
                    179:        }
                    180: 
                    181:        // メッセージインフェーズを完了する。
                    182:        virtual SCSI::XferPhase DoneMsgIn() { return SCSI::XferPhase::End; }
                    183: 
                    184:        // メッセージアウトフェーズを開始する。
                    185:        virtual void BeginMsgOut() { }
                    186: 
                    187:        // メッセージアウトフェーズを完了する。
                    188:        virtual SCSI::XferPhase DoneMsgOut() { return SCSI::XferPhase::End; }
                    189: 
                    190:  protected:
                    191:        // このコマンドを実行しているターゲットデバイス。
                    192:        SCSITarget *parent;
                    193: };
                    194: 
                    195: //
                    196: // SCSI コマンド 0x00: TestUnitReady (共通)
                    197: //
                    198: class SCSICmdTestUnitReady : public SCSICmd
                    199: {
                    200:        typedef SCSICmd inherited;
                    201:  public:
                    202:        SCSICmdTestUnitReady(SCSITarget *p) : inherited(p) { }
                    203:        virtual ~SCSICmdTestUnitReady() { }
                    204: };
                    205: 
                    206: //
                    207: // SCSI コマンド 0x03: RequestSense (共通)
                    208: //
                    209: class SCSICmdRequestSense : public SCSICmd
                    210: {
                    211:        typedef SCSICmd inherited;
                    212:  public:
                    213:        SCSICmdRequestSense(SCSITarget *p) : inherited(p) { }
                    214:        virtual ~SCSICmdRequestSense() { }
                    215: 
                    216:        virtual SCSI::XferPhase Command(std::vector<uint8>& cmdseq) {
                    217:                // この内容は全く不正。でっちあげである。
                    218:                // まず 8バイトのバッファに応答を作成
                    219:                buf.clear();
                    220:                buf.resize(8);
                    221:                buf[0] = 0xf0;  // Valid, エラークラス7, エラーコード0
                    222:                buf[1] = 0;
                    223:                buf[2] = 0;             // No Sense
                    224:                buf[3] = 0;
                    225:                buf[4] = 0;
                    226:                buf[5] = 0;
                    227:                buf[6] = 0;
                    228:                buf[7] = 0;             // 追加センスデータ長 0
                    229: 
                    230:                // それからバッファを指定の長さに変更
                    231:                buf.resize((uint)cmdseq[4]);
                    232: 
                    233:                return SCSI::XferPhase::DataIn;
                    234:        }
                    235: };
                    236: 
                    237: //
                    238: // SCSI コマンド 0x08: Read(6) (共通)
                    239: //
                    240: class SCSICmdRead6 : public SCSICmd
                    241: {
                    242:        typedef SCSICmd inherited;
                    243:  public:
                    244:        SCSICmdRead6(SCSITarget *p) : inherited(p) { }
                    245:        virtual ~SCSICmdRead6() { }
                    246: 
                    247:        virtual SCSI::XferPhase Command(std::vector<uint8>& cmdseq) {
                    248:                SCSIHD *hdparent = dynamic_cast<SCSIHD*>(parent);
                    249:                uint32 lba;
                    250:                uint32 blks;
                    251: 
                    252:                lba  = (cmdseq[1] & 0x1f) << 16;
                    253:                lba |= cmdseq[2] << 8;
                    254:                lba |= cmdseq[3];
                    255:                blks = cmdseq[4];
                    256: 
                    257:                // blks == 0 は 256 ブロック転送を意味する。
                    258:                if (blks == 0) {
                    259:                        blks = 256;
                    260:                }
                    261:                uint8 *start = hdparent->mem + lba * hdparent->blocksize;
                    262:                uint8 *end = start + blks * hdparent->blocksize;
                    263:                buf.assign(start, end);
                    264: 
                    265:                parent->putlog(1, "READ6 LBA=0x%x blks=0x%x", lba, blks);
                    266:                return SCSI::XferPhase::DataIn;
                    267:        }
                    268: };
                    269: 
                    270: //
                    271: // SCSI コマンド 0x0a: Write(6) (共通)
                    272: //
                    273: class SCSICmdWrite6 : public SCSICmd
                    274: {
                    275:        typedef SCSICmd inherited;
                    276:  public:
                    277:        SCSICmdWrite6(SCSITarget *p) : inherited(p) {
                    278:                hdparent = dynamic_cast<SCSIHD*>(parent);
                    279:        }
                    280:        virtual ~SCSICmdWrite6() { }
                    281: 
                    282:        virtual SCSI::XferPhase Command(std::vector<uint8>& cmdseq) {
                    283:                lba  = (cmdseq[1] & 0x1f) << 16;
                    284:                lba |= cmdseq[2] << 8;
                    285:                lba |= cmdseq[3];
                    286:                blks = cmdseq[4];
                    287: 
                    288:                // blks == 0 は 256 ブロック転送を意味する。
                    289:                if (blks == 0) {
                    290:                        blks = 256;
                    291:                }
                    292:                recvbytes = blks * hdparent->blocksize;
                    293: 
                    294:                return SCSI::XferPhase::DataOut;
                    295:        }
                    296: 
                    297:        virtual SCSI::XferPhase DoneDataOut() {
                    298:                parent->putlog(1, "WRITE6 LBA=0x%x blks=0x%x", lba, blks);
                    299:                if (hdparent->writeprotect == false) {
                    300:                        memcpy(hdparent->mem + (lba * hdparent->blocksize),
                    301:                                buf.data(), buf.size());
                    302:                }
                    303:                return SCSI::XferPhase::Status;
                    304:        }
                    305: 
                    306:  private:
                    307:        SCSIHD *hdparent;
                    308:        uint32 lba;
                    309:        uint32 blks;
                    310: };
                    311: 
                    312: //
                    313: // SCSI コマンド 0x12: Inquiry (共通)
                    314: //
                    315: class SCSICmdInquiry : public SCSICmd
                    316: {
                    317:        typedef SCSICmd inherited;
                    318:  public:
                    319:        SCSICmdInquiry(SCSITarget *p) : inherited(p) { }
                    320:        virtual ~SCSICmdInquiry() { }
                    321: 
                    322:        virtual SCSI::XferPhase Command(std::vector<uint8>& cmdseq) {
                    323:                // 応答データはターゲットデバイスが持っている
                    324:                buf = parent->inquiry_data;
                    325: 
                    326:                // 本来の応答データ長か reqlen の短いほうまで。
                    327:                uint reqlen = (uint)cmdseq[4];
                    328:                if (reqlen < buf.size()) {
                    329:                        buf.resize(reqlen);
                    330:                }
                    331:                return SCSI::XferPhase::DataIn;
                    332:        }
                    333: };
                    334: 
                    335: //
                    336: // SCSI コマンド 0x15 ModeSelect(6) (共通)
                    337: //
                    338: class SCSICmdModeSelect6 : public SCSICmd
                    339: {
                    340:        typedef SCSICmd inherited;
                    341:  public:
                    342:        SCSICmdModeSelect6(SCSITarget *p) : inherited(p) { }
                    343:        virtual ~SCSICmdModeSelect6() { }
                    344: 
                    345:        virtual SCSI::XferPhase Command(std::vector<uint8>& cmdseq) {
                    346:                recvbytes = cmdseq[4];
                    347:                return SCSI::XferPhase::DataOut;
                    348:        }
                    349: 
                    350:        virtual SCSI::XferPhase DoneDataOut() {
                    351:                // Mode Select(6) のデータは以下の構造で並んでいる。
                    352:                //  ヘッダ
                    353:                //  ブロックディスクリプタ#1
                    354:                //   :
                    355:                //  ブロックディスクリプタ#n
                    356:                //  パラメータページ #1
                    357:                //   :
                    358:                //  パラメータページ #m
                    359: 
                    360:                const SCSI::ModeParamHdr *hdr = (const SCSI::ModeParamHdr *)buf.data();
                    361: 
                    362:                if (hdr->block_desc_len > 0) {
                    363:                        const SCSI::BlockDesc *desc =
                    364:                                (const SCSI::BlockDesc *)(buf.data() + sizeof(*hdr));
                    365:                        uint blocksize;
                    366:                        blocksize  = (desc->block_size[0]) << 16;
                    367:                        blocksize |= (desc->block_size[1]) << 8;
                    368:                        blocksize |= (desc->block_size[2]);
                    369: 
                    370:                        // ブロック長を書き戻す
                    371:                        parent->blocksize = blocksize;
                    372:                }
                    373:                return SCSI::XferPhase::Status;
                    374:        }
                    375: };
                    376: 
                    377: //
                    378: // SCSI コマンド 0x25 ReadCapacity (ダイレクトアクセスデバイス)
                    379: //
                    380: class SCSICmdReadCapacity : public SCSICmd
                    381: {
                    382:        typedef SCSICmd inherited;
                    383:  public:
                    384:        SCSICmdReadCapacity(SCSITarget *p) : inherited(p) { }
                    385:        virtual ~SCSICmdReadCapacity() { }
                    386: 
                    387:        virtual SCSI::XferPhase Command(std::vector<uint8>& cmdseq) {
                    388:                SCSIHD *hdparent = dynamic_cast<SCSIHD*>(parent);
                    389: 
                    390:                // PMI=1 は未サポート
                    391:                if ((cmdseq[8] & 0x01) != 0) {
                    392:                        parent->putmsg("SCSI ReadCapacity PMI=1 not supported");
                    393:                }
                    394: 
                    395:                // 応答データは
                    396:                // +00.L 最終論理ブロックアドレス
                    397:                // +04.L ブロック長
                    398:                uint32 blksize = hdparent->blocksize;
                    399:                uint32 lastblk = (hdparent->memlen / blksize) - 1;
                    400:                buf.resize(8);
                    401:                buf[0] = lastblk >> 24;
                    402:                buf[1] = lastblk >> 16;
                    403:                buf[2] = lastblk >> 8;
                    404:                buf[3] = lastblk;
                    405:                buf[4] = blksize >> 24;
                    406:                buf[5] = blksize >> 16;
                    407:                buf[6] = blksize >> 8;
                    408:                buf[7] = blksize;
                    409: 
                    410:                return SCSI::XferPhase::DataIn;
                    411:        }
                    412: };
                    413: 
                    414: //
                    415: // SCSI コマンド 0x28 Read(10) (ダイレクトアクセスデバイス)
                    416: //
                    417: class SCSICmdRead10 : public SCSICmd
                    418: {
                    419:        typedef SCSICmd inherited;
                    420:  public:
                    421:        SCSICmdRead10(SCSITarget *p) : inherited(p) { }
                    422:        virtual ~SCSICmdRead10() { }
                    423: 
                    424:        virtual SCSI::XferPhase Command(std::vector<uint8>& cmdseq) {
                    425:                SCSIHD *hdparent = dynamic_cast<SCSIHD*>(parent);
                    426:                uint32 lba;
                    427:                uint32 blks;
                    428: 
                    429:                if ((cmdseq[1] & 0x01)) {
                    430:                        parent->putmsg("SCSI Read(10) RelAdr not supported");
                    431:                }
                    432: 
                    433:                lba  = cmdseq[2] << 24;
                    434:                lba |= cmdseq[3] << 16;
                    435:                lba |= cmdseq[4] << 8;
                    436:                lba |= cmdseq[5];
                    437:                blks  = cmdseq[7] << 8;
                    438:                blks |= cmdseq[8];
                    439: 
                    440:                // XXX 範囲チェック
                    441:                uint8 *start = hdparent->mem + lba * hdparent->blocksize;
                    442:                uint8 *end = start + blks * hdparent->blocksize;
                    443:                buf.assign(start, end);
                    444: 
                    445:                parent->putlog(1, "READ10 LBA=0x%x blks=0x%x", lba, blks);
                    446:                return SCSI::XferPhase::DataIn;
                    447:        }
                    448: };
                    449: 
                    450: //
                    451: // SCSI コマンド サポートしていないコマンド
                    452: //
                    453: class SCSICmdNotSupportedCommand : public SCSICmd
                    454: {
                    455:        typedef SCSICmd inherited;
                    456:  public:
                    457:        SCSICmdNotSupportedCommand(SCSITarget *p) : inherited(p) { }
                    458:        virtual ~SCSICmdNotSupportedCommand() { }
                    459: 
                    460:        // Command は何もせずステータスに移るだけなので基底のやつでいい
                    461: 
                    462:        virtual void BeginStatus() {
                    463:                buf.clear();
                    464:                buf.push_back((uint8)SCSI::StatusByte::CheckCondition);
                    465:        }
                    466: };
                    467: 
                    468: 
                    469: //
                    470: // SCSI ターゲットデバイスの共通部分
                    471: //
                    472: 
                    473: // コンストラクタ
                    474: SCSITarget::SCSITarget(SCSIHostDevice *h, int id, std::vector<uint8>& inq)
                    475: {
                    476:        logname = "scsitarget";
                    477:        devname = "SCSITarget";
                    478: 
                    479:        inquiry_data = inq;
                    480:        // ホストへのリンク (所有関係のないポインタ)
                    481:        host = h;
                    482:        myid = id;
                    483: }
                    484: 
                    485: // デストラクタ
                    486: SCSITarget::~SCSITarget()
                    487: {
                    488: }
                    489: 
                    490: // セレクションで選択された (SCSIBus から呼ばれる)
                    491: void
                    492: SCSITarget::SelectionCB()
                    493: {
                    494:        // ターゲットが、自身が選択されていることを認識してから BSY を
                    495:        // 立てるまでの時間はもうバス側でカウントしてあるので、ここでは
                    496:        // ただちに BSY を上げてよい。
                    497:        putlog(4, "Selection Callback");
                    498:        AssertBSY();
                    499: }
                    500: 
                    501: // 情報転送フェーズを開始する (SCSIBus から呼ばれる)
                    502: void
                    503: SCSITarget::StartTransferCB()
                    504: {
                    505:        // 最初はコマンドフェーズ。(ATN はとりあえず放置)
                    506:        putlog(4, "Start Command Phase");
                    507:        cmdseq.clear();
                    508:        cmdlen = 0;
                    509:        SetXfer(SCSI::XferPhase::Command);
                    510:        AssertREQ();
                    511: }
                    512: 
                    513: // 情報転送フェーズ間の遷移について
                    514: //
                    515: // 情報転送フェーズは TransferCB() で1バイトずつ転送を行い、所定のバイト数
                    516: // の転送が完了すればフェーズを遷移する。遷移方法は入出力方向別で6通り。
                    517: //  o IN  -> IN
                    518: //  o IN  -> OUT
                    519: //  o IN  -> END
                    520: //  o OUT -> OUT
                    521: //  o OUT -> IN
                    522: //  o OUT -> END
                    523: //
                    524: // IN -> IN の遷移。TransferCB() で前フェーズの最終バイト受信後、フェーズを
                    525: // 変更して REQ を立てるところまで。
                    526: //
                    527: // IN -> OUT の遷移。TransferCB() で前フェーズの最終バイト受信後、フェーズを
                    528: // 変更して (おそらく {Phase}Begin() を発行してから)、データをセットし REQ
                    529: // を立てる?
                    530: //
                    531: // IN -> END の遷移。TransferCB() で前フェーズの最終バイト受信後、BSY を
                    532: // 下げて終了。
                    533: //
                    534: // OUT -> OUT の遷移。前フェーズの最終バイトをイニシエータが受信後に
                    535: // TransferCB() が呼ばれるので、フェーズを変更して (おそらく {Phase}Begin()
                    536: // を発行してから)、データをセットし REQ を立てる?
                    537: //
                    538: // OUT -> IN の遷移。前フェーズの最終バイトをイニシエータが受信後に
                    539: // TransferCB() が呼ばれるので、フェーズを変更して (おそらく {Phase}Begin()
                    540: // を発行してから)、REQ を立てる?
                    541: //
                    542: // OUT -> END の遷移。前フェーズの最終バイトをイニシエータが受信後に
                    543: // TransferCB() が呼ばれるので、BSY を下げる?
                    544: 
                    545: // 情報転送フェーズでイニシエータが ACK を上げた。(SCSIBus から呼ばれる)
                    546: // OUT (イニシエータ → ターゲット方向) なら、ターゲットが上げた REQ に応答
                    547: // してイニシエータがデータをデータバスに乗せてからこれをコールしてくる。
                    548: // IN (ターゲット → イニシエータ方向) なら、ターゲットがデータをデータバスに
                    549: // 乗せて REQ を上げたのをイニシエータが受信した後でこれをコールしてくる。
                    550: void
                    551: SCSITarget::TransferCB()
                    552: {
                    553:        uint8 data;
                    554:        SCSI::XferPhase xfer;
                    555: 
                    556:        // このフェーズの最終バイトか
                    557:        lastbyte = false;
                    558: 
                    559:        // このフェーズの1バイト処理
                    560:        xfer = GetXfer();
                    561:        if (xfer == SCSI::XferPhase::Command) {
                    562:                // コマンドフェーズだけいろいろ特殊なので別処理。
                    563:                // 受信バッファが異なる、1バイト目で受信長が決まるなど。
                    564:                data = GetData();
                    565:                putlog(4, "TransferCB: cmdseq[%02d] = $%02x",
                    566:                        (int)cmdseq.size(), data);
                    567:                cmdseq.push_back(data);
                    568:                if (cmdseq.size() == 1) {
                    569:                        // 1バイト目ならこのコマンドが何バイトか調べる
                    570:                        switch (cmdseq[0] >> 5) {
                    571:                         case 0:        cmdlen =  6;    break;
                    572:                         case 1:        cmdlen = 10;    break;
                    573:                         case 2:        cmdlen = 10;    break;
                    574:                         case 5:        cmdlen = 12;    break;
                    575:                         default:
                    576:                                // 3,4 はリサーブ、6,7 はベンダー定義。XXX 来たらどうする?
                    577:                                cmdlen = 6;
                    578:                                break;
                    579:                        }
                    580:                } else if (cmdseq.size() >= cmdlen) {
                    581:                        if (loglevel >= 1) {
                    582:                                std::string cmdbuf;
                    583:                                const char *name = SCSI::GetCommandName(cmdseq[0]);
                    584:                                cmdbuf += string_format("Command \"%s\"", name ?: "?");
                    585:                                for (const auto& v : cmdseq) {
                    586:                                        cmdbuf += string_format(" $%02x", v);
                    587:                                }
                    588:                                putlog("%s", cmdbuf.c_str());
                    589:                        }
                    590:                        // 最終バイトを受信したらコマンドを選択
                    591:                        DispatchCmd();
                    592:                        lastbyte = true;
                    593:                }
                    594:        } else if (GetIO() == false) {
                    595:                // OUT 方向 (ターゲットが受信側)
                    596:                // bytecount は減算方向。
                    597:                cmd->buf.push_back(GetData());
                    598:                bytecount--;
                    599:                if (bytecount == 0) {
                    600:                        lastbyte = true;
                    601:                }
                    602:        } else {
                    603:                // IN 方向 (ターゲットが送信側)
                    604:                // bytecount は加算方向。
                    605:                // データは前のループの終わり (TransferAckCB()の下のほう) で
                    606:                // セットしているのでここでは引き取られた分をカウントする。
                    607:                bytecount++;
                    608:                if (bytecount >= cmd->buf.size()) {
                    609:                        lastbyte = true;
                    610:                }
                    611:        }
                    612: 
                    613:        NegateREQ();
                    614: }
                    615: 
                    616: // 情報転送フェーズでイニシエータが ACK を下げた。(SCSIBus から呼ばれる)
                    617: void
                    618: SCSITarget::TransferAckCB()
                    619: {
                    620:        SCSI::XferPhase xfer = GetXfer();
                    621: 
                    622:        // これが最終バイトだったら、フェーズ完了 → フェーズ切り替え。
                    623:        if (lastbyte) {
                    624:                SCSI::XferPhase next;
                    625:                // フェーズ完了
                    626:                switch (xfer) {
                    627:                 case SCSI::XferPhase::Command:
                    628:                        next = cmd->Command(cmdseq);
                    629:                        break;
                    630:                 case SCSI::XferPhase::DataOut:
                    631:                        next = cmd->DoneDataOut();
                    632:                        break;
                    633:                 case SCSI::XferPhase::DataIn:
                    634:                        next = cmd->DoneDataIn();
                    635:                        break;
                    636:                 case SCSI::XferPhase::MsgOut:
                    637:                        next = cmd->DoneMsgOut();
                    638:                        break;
                    639:                 case SCSI::XferPhase::MsgIn:
                    640:                        next = cmd->DoneMsgIn();
                    641:                        break;
                    642:                 case SCSI::XferPhase::Status:
                    643:                        next = cmd->DoneStatus();
                    644:                        break;
                    645:                 default:
                    646:                        PANIC("TransferCB unknown xfer done %d", (int)xfer);
                    647:                }
                    648:                putlog(2, "%s done", SCSI::GetXferPhaseName(xfer));
                    649: 
                    650:                if (next != xfer) {
                    651:                        // End ならバスフリーにして終了。
                    652:                        if (next == SCSI::XferPhase::End) {
                    653:                                NegateBSY();
                    654:                                return;
                    655:                        }
                    656: 
                    657:                        // (必要なら)フェーズを更新
                    658:                        SetXfer(next);
                    659:                        xfer = next;
                    660: 
                    661:                        // 新しいフェーズの開始処理
                    662:                        // XXX ここで bytecount とかをリセットできればいいのだが
                    663:                        // Command フェーズで Data フェーズの準備をすることが多いので
                    664:                        // 悩ましい。
                    665:                        switch (xfer) {
                    666:                         case SCSI::XferPhase::DataOut:
                    667:                                cmd->BeginDataOut();
                    668:                                cmd->buf.clear();
                    669:                                bytecount = cmd->recvbytes;
                    670:                                putlog(3, "DataOut begin (%d bytes)", bytecount);
                    671:                                break;
                    672:                         case SCSI::XferPhase::DataIn:
                    673:                                cmd->BeginDataIn();
                    674:                                bytecount = 0;
                    675:                                putlog(3, "DataIn begin (%d bytes)", (int)cmd->buf.size());
                    676:                                break;
                    677:                         case SCSI::XferPhase::MsgOut:
                    678:                                cmd->BeginMsgOut();
                    679:                                cmd->buf.clear();
                    680:                                bytecount = cmd->recvbytes;
                    681:                                putlog(3, "MsgOut begin (%d bytes)", bytecount);
                    682:                                break;
                    683:                         case SCSI::XferPhase::MsgIn:
                    684:                                cmd->BeginMsgIn();
                    685:                                bytecount = 0;
                    686:                                putlog(3, "MsgIn begin (%d bytes)", (int)cmd->buf.size());
                    687:                                break;
                    688:                         case SCSI::XferPhase::Status:
                    689:                                cmd->BeginStatus();
                    690:                                bytecount = 0;
                    691:                                putlog(3, "Status begin (%d bytes)", (int)cmd->buf.size());
                    692:                                break;
                    693:                         default:
                    694:                                PANIC("TransferCB unknown xfer begin %d", (int)xfer);
                    695:                        }
                    696:                }
                    697:        }
                    698: 
                    699:        // IN 方向 (ターゲットが送信側) ならここでデータをバスにセット。
                    700:        if (GetIO()) {
                    701:                SetData(cmd->buf[bytecount]);
                    702:                putlog(4, "SetData $%02x", GetData());
                    703:        }
                    704: 
                    705:        // 次のバイト転送を行うために REQ を上げる。
                    706:        AssertREQ();
                    707: }
                    708: 
                    709: // SCSI コマンドのディスパッチャ
                    710: void
                    711: SCSITarget::DispatchCmd()
                    712: {
                    713:        switch (cmdseq[0]) {
                    714:         case SCSI::Command::TestUnitReady:     // 0x00
                    715:                cmd.reset(new SCSICmdTestUnitReady(this));
                    716:                break;
                    717: 
                    718:         case SCSI::Command::RequestSense:      // 0x03
                    719:                cmd.reset(new SCSICmdRequestSense(this));
                    720:                break;
                    721: 
                    722:         case SCSI::Command::Inquiry:           // 0x12
                    723:                cmd.reset(new SCSICmdInquiry(this));
                    724:                break;
                    725: 
                    726:         case SCSI::Command::ModeSelect6:       // 0x15
                    727:                cmd.reset(new SCSICmdModeSelect6(this));
                    728:                break;
                    729: 
                    730:         case SCSI::Command::ReadCapacity:      // 0x25
                    731:                cmd.reset(new SCSICmdTestUnitReady(this));
                    732:                break;
                    733: 
                    734:         default:
                    735:                // サポートしていないコマンド
                    736:                const char *cname = SCSI::GetCommandName(cmdseq[0]);
                    737:                std::string name;
                    738:                if (cname) {
                    739:                        name = string_format(" %s", cname);
                    740:                }
                    741:                putlog(0, "未実装 SCSI コマンド $%02x%s len=%d",
                    742:                        cmdseq[0], name.c_str(), (int)cmdseq.size());
                    743: 
                    744:                cmd.reset(new SCSICmdNotSupportedCommand(this));
                    745:                break;
                    746:        }
                    747: }
                    748: 
                    749: //
                    750: // SCSI HD
                    751: //
                    752: 
                    753: // コンストラクタ
                    754: SCSIHD::SCSIHD(SCSIHostDevice *h, int id)
                    755:        : inherited(h, id, inquiry_data)
                    756: {
                    757:        devname = "SCSIHD";
                    758:        devtype = SCSI::HD;
                    759:        fd = -1;
                    760:        mem = NULL;
                    761: }
                    762: 
                    763: // デストラクタ
                    764: SCSIHD::~SCSIHD()
                    765: {
                    766:        if (mem) {
                    767:                munmap(mem, memlen);
                    768:                mem = NULL;
                    769:        }
                    770:        if (fd >= 0) {
                    771:                close(fd);
                    772:                fd = -1;
                    773:        }
                    774: }
                    775: 
                    776: // 初期化
                    777: bool
                    778: SCSIHD::Init()
                    779: {
                    780:        struct stat st;
                    781: 
                    782:        const std::string myname = string_format("%s:ID%d",
                    783:                host->GetConfigName(), myid);
                    784:        const std::string keybody = string_format("%s_id%d_",
                    785:                host->GetConfigName(), myid);
                    786:        const std::string imgkey = keybody + "image";
                    787:        const std::string wpkey  = keybody + "writeprotect";
                    788: 
                    789:        // devtype があって image がないのは異常状態なのでエラー
                    790:        const std::string& filename = gConfig->ReadStr(imgkey);
                    791:        if (filename == "") {
                    792:                gConfig->Err(imgkey, "not specified");
                    793:                return false;
                    794:        }
                    795: 
                    796:        const std::string path = gConfig->GetConfigDir() + filename;
                    797:        fd = open(path.c_str(), O_RDWR);
                    798:        if (fd == -1) {
                    799:                warn("%s \"%s\" open failed", myname.c_str(), path.c_str());
                    800:                return false;
                    801:        }
                    802: 
                    803:        if (fstat(fd, &st) == -1) {
                    804:                warn("%s \"%s\" fstat failed", myname.c_str(), path.c_str());
                    805:                close(fd);
                    806:                return false;
                    807:        }
                    808: 
                    809:        memlen = st.st_size;
                    810:        mem = (uint8 *)mmap(NULL, memlen, PROT_READ | PROT_WRITE,
                    811:                MAP_SHARED, fd, 0);
                    812:        if (mem == MAP_FAILED) {
                    813:                warn("%s \"%s\" mmap failed", myname.c_str(), path.c_str());
                    814:                close(fd);
                    815:                return false;
                    816:        }
                    817: 
                    818:        writeprotect = (bool)gConfig->ReadInt(wpkey);
                    819:        if (writeprotect) {
                    820:                putmsg(0, "%s: write protected", myname.c_str());
                    821:        }
                    822: 
                    823:        return true;
                    824: }
                    825: 
                    826: // SCSI コマンドのディスパッチャ
                    827: void
                    828: SCSIHD::DispatchCmd()
                    829: {
                    830:        switch (cmdseq[0]) {
                    831:         case SCSI::Command::Read6:                     // 0x08
                    832:                cmd.reset(new SCSICmdRead6(this));
                    833:                break;
                    834: 
                    835:         case SCSI::Command::Write6:            // 0x0a
                    836:                cmd.reset(new SCSICmdWrite6(this));
                    837:                break;
                    838: 
                    839:         case SCSI::Command::ReadCapacity:      // 0x25
                    840:                cmd.reset(new SCSICmdReadCapacity(this));
                    841:                break;
                    842: 
                    843:         case SCSI::Command::Read10:            // 0x28
                    844:                cmd.reset(new SCSICmdRead10(this));
                    845:                break;
                    846: 
                    847:         default:
                    848:                // 見付からなければ基本クラス側に任せる
                    849:                inherited::DispatchCmd();
                    850:                break;
                    851:        }
                    852: }
                    853: 
                    854: // HD の inquiry データ
                    855: /*static*/ std::vector<uint8>
                    856: SCSIHD::inquiry_data = {
                    857:        0x00,   // 00 Qualifier + DeviceType
                    858:        0x00,   // 01 RMB
                    859:        0x40,   // 02 ISO version
                    860:        0x00,   // 03 Response Data Format?
                    861:        36 - 4, // 04 追加データ長
                    862:        0,              // 05 Reserved
                    863:        0,              // 06 Reserved
                    864:        0x00,   // 07
                    865:        'N', 'O', 'N', 'O', ' ', ' ', ' ', ' ',
                    866:        'S', 'C', 'S', 'I', 'H', 'D', ' ', ' ',
                    867:        ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
                    868:        'r', 'e', 'v', '0',
                    869: };

unix.superglobalmegacorp.com

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