Annotation of nono/vm/scsitarget.cpp, revision 1.1

1.1     ! root        1: //
        !             2: // nono
        !             3: // Copyright (C) 2018 [email protected]
        !             4: //
        !             5: 
        !             6: #include <algorithm>
        !             7: #include <fcntl.h>
        !             8: #include <sys/stat.h>
        !             9: #include <sys/mman.h>
        !            10: #include "scsitarget.h"
        !            11: #include "scsi.h"
        !            12: #include "configfile.h"
        !            13: #include "mystring.h"
        !            14: 
        !            15: //
        !            16: // SCSI コマンドクラス
        !            17: //
        !            18: class SCSICmd
        !            19: {
        !            20:  public:
        !            21:        SCSICmd(SCSITarget *p) {
        !            22:                parent = p;
        !            23:        }
        !            24:        virtual ~SCSICmd() { }
        !            25: 
        !            26:        // コマンドフェーズを開始する。
        !            27:        // コマンドバイト列が揃ったところでコールされるので、
        !            28:        // 必要な処理を行い、次のフェーズ (SCSI::Phase::*) を返す。
        !            29:        virtual uint8 Command(const std::vector<uint8>& cmds) {
        !            30:                // 何もしない系コマンドなら次はステータスフェーズ
        !            31:                return SCSI::Phase::Status;
        !            32:        }
        !            33: 
        !            34:        // データインフェーズを開始する。
        !            35:        // データインフェーズ開始時にコールされるので、
        !            36:        // ホストに転送するデータを用意し、
        !            37:        // *ptr にデータの先頭、戻り値にデータ長を返す。
        !            38:        virtual uint DataInBegin(const uint8 **ptr) {
        !            39:                return 0;
        !            40:        }
        !            41: 
        !            42:        // データアウトフェーズを開始する。
        !            43:        // データアウトフェーズ開始時にコールされるので、
        !            44:        // ホストからのデータ受信用バッファを用意し、
        !            45:        // *ptr にバッファ、戻り値にバッファ長を返す。
        !            46:        virtual uint DataOutBegin(uint8 **ptr) {
        !            47:                return 0;
        !            48:        }
        !            49: 
        !            50:        // データイン、データアウトフェーズ完了時にコールされる。
        !            51:        virtual void DataDone() { }
        !            52: 
        !            53:        // ステータスフェーズを開始する。
        !            54:        // ステータス (SCSI::StatusByte::*) を返す。
        !            55:        virtual uint Status() {
        !            56:                return SCSI::StatusByte::Good;
        !            57:        }
        !            58: 
        !            59:        // メッセージインフェーズを開始する。
        !            60:        // メッセージ (SCSI::MsgByte::*) を返す。
        !            61:        virtual uint MsgIn() {
        !            62:                return SCSI::MsgByte::CommandComplete;
        !            63:        }
        !            64: 
        !            65:  protected:
        !            66:        // このコマンドを呼び出したデバイス
        !            67:        SCSITarget *parent = NULL;
        !            68: };
        !            69: 
        !            70: // $00 TestUnitReady コマンド (共通)
        !            71: // とりあえず何もせず正常を返すだけでいい。
        !            72: class SCSICmdTestUnitReady : public SCSICmd
        !            73: {
        !            74:        typedef SCSICmd inherited;
        !            75:  public:
        !            76:        SCSICmdTestUnitReady(SCSITarget *p) : inherited(p) { }
        !            77:        virtual ~SCSICmdTestUnitReady() { }
        !            78: };
        !            79: 
        !            80: // $03 RequestSense コマンド (共通)
        !            81: class SCSICmdRequestSense: public SCSICmd
        !            82: {
        !            83:        typedef SCSICmd inherited;
        !            84:  public:
        !            85:        SCSICmdRequestSense(SCSITarget *p) : inherited(p) { }
        !            86:        virtual ~SCSICmdRequestSense() { }
        !            87: 
        !            88:        virtual uint8 Command(const std::vector<uint8>& cmds) {
        !            89:                parent->putlog(1, "RequestSense %d", cmds[4]);
        !            90: 
        !            91:                // この内容は全く不正。でっちあげである。
        !            92: 
        !            93:                len = (uint)cmds[4];
        !            94:                mem[0] = 0x80 | 0x70;
        !            95:                mem[1] = 0;
        !            96:                mem[2] = 0;     // No Sense
        !            97:                mem[3] = 0;
        !            98:                mem[4] = 0;
        !            99:                mem[5] = 0;
        !           100:                mem[6] = 0;
        !           101:                mem[7] = 0;     // 追加センスデータ長
        !           102: 
        !           103:                return SCSI::Phase::DataIn;
        !           104:        }
        !           105: 
        !           106:        virtual uint DataInBegin(const uint8 **ptr) {
        !           107:                *ptr = mem;
        !           108:                return len;
        !           109:        }
        !           110: 
        !           111:  private:
        !           112:        uint len = 0;
        !           113:        uint8 mem[256] {};
        !           114: };
        !           115: 
        !           116: // $08 Read(6) コマンド (ダイレクトアクセスデバイス)
        !           117: class SCSICmdRead6 : public SCSICmd
        !           118: {
        !           119:        typedef SCSICmd inherited;
        !           120:  public:
        !           121:        SCSICmdRead6(SCSITarget *p)
        !           122:                : inherited(p)
        !           123:        {
        !           124:                hdparent = dynamic_cast<SCSIHD*>(p);
        !           125:        }
        !           126:        virtual ~SCSICmdRead6() { }
        !           127: 
        !           128:        virtual uint8 Command(const std::vector<uint8>& cmds) {
        !           129:                uint32 lba;
        !           130:                uint32 blks;
        !           131: 
        !           132:                lba  = (cmds[1] & 0x1f) << 16;
        !           133:                lba |= cmds[2] << 8;
        !           134:                lba |= cmds[3];
        !           135:                blks = cmds[4];
        !           136: 
        !           137:                // XXX 範囲チェック
        !           138:                // READ(6) の blks == 0 は 256 を意味する。
        !           139:                // なお READ(10) ではこの変換は無い。
        !           140:                if (blks == 0) {
        !           141:                        blks = 256;
        !           142:                }
        !           143:                dataptr = hdparent->mem + (lba * hdparent->blocksize);
        !           144:                datalen = blks * parent->blocksize;
        !           145: 
        !           146:                parent->putlog(1, "READ6 $%x %d", lba, blks);
        !           147: 
        !           148:                return SCSI::Phase::DataIn;
        !           149:        }
        !           150: 
        !           151:        virtual uint DataInBegin(const uint8 **ptr) {
        !           152:                *ptr = dataptr;
        !           153:                return datalen;
        !           154:        }
        !           155: 
        !           156:  private:
        !           157:        SCSIHD *hdparent = NULL;
        !           158:        uint8 *dataptr = NULL;  // 今回の Read の先頭
        !           159:        uint datalen = 0;               // 今回の Read のバイト数
        !           160: };
        !           161: 
        !           162: // $0a Write(6) コマンド (ダイレクトアクセスデバイス)
        !           163: class SCSICmdWrite6 : public SCSICmd
        !           164: {
        !           165:        typedef SCSICmd inherited;
        !           166:  public:
        !           167:        SCSICmdWrite6(SCSITarget *p)
        !           168:                : inherited(p)
        !           169:        {
        !           170:                hdparent = dynamic_cast<SCSIHD*>(p);
        !           171:                databuf = NULL;
        !           172:                datalen = 0;
        !           173:        }
        !           174:        virtual ~SCSICmdWrite6() {
        !           175:                if (databuf) {
        !           176:                        delete[] databuf;
        !           177:                }
        !           178:        }
        !           179: 
        !           180:        virtual uint8 Command(const std::vector<uint8>& cmds) {
        !           181:                uint32 blks;
        !           182: 
        !           183:                lba  = (cmds[1] & 0x1f) << 16;
        !           184:                lba |= cmds[2] << 8;
        !           185:                lba |= cmds[3];
        !           186:                blks = cmds[4];
        !           187: 
        !           188:                // XXX 範囲チェック
        !           189:                // WRITE(6) の blks == 0 は 256 を意味する。
        !           190:                // なお WRITE(10) ではこの変換は無い。
        !           191:                if (blks == 0) {
        !           192:                        blks = 256;
        !           193:                }
        !           194:                datalen = blks * parent->blocksize;
        !           195:                databuf = new uint8[datalen];
        !           196: 
        !           197:                parent->putlog(1, "WRITE6 $%x %d", lba, blks);
        !           198: 
        !           199:                return SCSI::Phase::DataOut;
        !           200:        }
        !           201: 
        !           202:        virtual uint DataOutBegin(uint8 **ptr) {
        !           203:                *ptr = databuf;
        !           204:                return datalen;
        !           205:        }
        !           206: 
        !           207:        virtual void DataDone() {
        !           208:                if (hdparent->writeprotect == false)
        !           209:                        memcpy(hdparent->mem + (lba * hdparent->blocksize),
        !           210:                                databuf, datalen);
        !           211:        }
        !           212: 
        !           213:  private:
        !           214:        SCSIHD *hdparent = NULL;
        !           215:        uint8 *databuf = NULL;  // 今回の Write バッファ
        !           216:        uint datalen = 0;               // 今回の Write のバイト数
        !           217:        uint32 lba = 0;                 // 今回の Write の LBA
        !           218: };
        !           219: 
        !           220: // $12 Inquiry コマンド (共通)
        !           221: class SCSICmdInquiry : public SCSICmd
        !           222: {
        !           223:        typedef SCSICmd inherited;
        !           224:  public:
        !           225:        // inq, len は INQUIRY 応答データ
        !           226:        SCSICmdInquiry(SCSITarget *p, const uint8 *inq, uint len)
        !           227:                : inherited(p)
        !           228:        {
        !           229:                inquiry_buf = inq;
        !           230:                inquiry_len = len;
        !           231:        }
        !           232:        virtual ~SCSICmdInquiry() { }
        !           233: 
        !           234:        virtual uint8 Command(const std::vector<uint8>& cmds) {
        !           235:                inquiry_len = std::min(inquiry_len, (uint)cmds[4]);
        !           236: 
        !           237:                return SCSI::Phase::DataIn;
        !           238:        }
        !           239: 
        !           240:        virtual uint DataInBegin(const uint8 **ptr) {
        !           241:                *ptr = inquiry_buf;
        !           242:                return inquiry_len;
        !           243:        }
        !           244: 
        !           245:  private:
        !           246:        // Inquiry データは SCSI 種別で異なる
        !           247:        const uint8 *inquiry_buf = NULL;
        !           248:        uint inquiry_len = 0;
        !           249: };
        !           250: 
        !           251: // $15 ModeSelect(6) コマンド (共通)
        !           252: class SCSICmdModeSelect6 : public SCSICmd
        !           253: {
        !           254:        typedef SCSICmd inherited;
        !           255:  public:
        !           256:        // ModeSelect コマンドではホストからブロック長が指定される。
        !           257:        // blocksizep はその指定されたブロック長を書き戻す場所。
        !           258:        SCSICmdModeSelect6(SCSITarget *p)
        !           259:                : inherited(p)
        !           260:        {
        !           261:                modebuf = NULL;
        !           262:                len = 0;
        !           263:        }
        !           264:        virtual ~SCSICmdModeSelect6() {
        !           265:                if (modebuf) {
        !           266:                        delete[] modebuf;
        !           267:                }
        !           268:        }
        !           269: 
        !           270:        virtual uint8 Command(const std::vector<uint8>& cmds) {
        !           271:                // 指定されたバッファ長のメモリを確保。
        !           272:                len = cmds[4];
        !           273:                modebuf = new uint8[len];
        !           274:                return SCSI::Phase::DataOut;
        !           275:        }
        !           276: 
        !           277:        virtual uint DataOutBegin(uint8 **ptr) {
        !           278:                *ptr = modebuf;
        !           279:                return len;
        !           280:        }
        !           281: 
        !           282:        virtual void DataDone() {
        !           283:                // Mode Select(6) のデータは以下の構造で並んでいる。
        !           284:                //  ヘッダ
        !           285:                //  ブロックディスクリプタ#1
        !           286:                //   :
        !           287:                //  ブロックディスクリプタ#n
        !           288:                //  パラメータページ #1
        !           289:                //   :
        !           290:                //  パラメータページ #m
        !           291: 
        !           292:                const SCSI::ModeParamHdr *hdr = (const SCSI::ModeParamHdr *)modebuf;
        !           293: 
        !           294:                if (hdr->block_desc_len > 0) {
        !           295:                        const SCSI::BlockDesc *desc =
        !           296:                                (const SCSI::BlockDesc *)(modebuf + sizeof(*hdr));
        !           297:                        uint blocksize;
        !           298:                        blocksize  = (desc->block_size[0]) << 16;
        !           299:                        blocksize |= (desc->block_size[1]) << 8;
        !           300:                        blocksize |= (desc->block_size[2]);
        !           301: 
        !           302:                        // ブロック長を書き戻す
        !           303:                        parent->blocksize = blocksize;
        !           304:                }
        !           305:        };
        !           306: 
        !           307:  private:
        !           308:        uint8 *modebuf = NULL;
        !           309:        uint len = 0;
        !           310: };
        !           311: 
        !           312: // $25 ReadCapacity コマンド (ダイレクトアクセスデバイス)
        !           313: class SCSICmdReadCapacity : public SCSICmd
        !           314: {
        !           315:        typedef SCSICmd inherited;
        !           316:  public:
        !           317:        SCSICmdReadCapacity(SCSITarget *p)
        !           318:                : inherited(p)
        !           319:        {
        !           320:                hdparent = dynamic_cast<SCSIHD*>(p);
        !           321: 
        !           322:                // 応答データは
        !           323:                // +00.L 最終論理ブロックアドレス
        !           324:                // +04.L ブロック長
        !           325:                uint32 blksize = hdparent->blocksize;
        !           326:                uint32 lastblk = (hdparent->memlen / blksize) - 1;
        !           327:                databuf[0] = lastblk >> 24;
        !           328:                databuf[1] = lastblk >> 16;
        !           329:                databuf[2] = lastblk >> 8;
        !           330:                databuf[3] = lastblk;
        !           331:                databuf[4] = blksize >> 24;
        !           332:                databuf[5] = blksize >> 16;
        !           333:                databuf[6] = blksize >> 8;
        !           334:                databuf[7] = blksize;
        !           335:        }
        !           336:        virtual ~SCSICmdReadCapacity() { }
        !           337: 
        !           338:        virtual uint8 Command(const std::vector<uint8>& cmds) {
        !           339:                uint8 pmi;
        !           340:                // PMI=1 は未サポート
        !           341:                pmi = cmds[8] & 0x01;
        !           342:                if (pmi != 0) {
        !           343:                        PANIC("SCSI ReadCapacity PMI=1 not supported");
        !           344:                }
        !           345: 
        !           346:                return SCSI::Phase::DataIn;
        !           347:        }
        !           348: 
        !           349:        virtual uint DataInBegin(const uint8 **ptr) {
        !           350:                *ptr = databuf;
        !           351:                return sizeof(databuf);
        !           352:        }
        !           353: 
        !           354:  private:
        !           355:        SCSIHD *hdparent = NULL;
        !           356:        uint8 databuf[8] {};
        !           357: };
        !           358: 
        !           359: // $28 Read(10) コマンド (ダイレクトアクセスデバイス)
        !           360: class SCSICmdRead10 : public SCSICmd
        !           361: {
        !           362:        typedef SCSICmd inherited;
        !           363:  public:
        !           364:        SCSICmdRead10(SCSITarget *p)
        !           365:                : inherited(p)
        !           366:        {
        !           367:                hdparent = dynamic_cast<SCSIHD*>(p);
        !           368:        }
        !           369:        virtual ~SCSICmdRead10() { }
        !           370: 
        !           371:        virtual uint8 Command(const std::vector<uint8>& cmds) {
        !           372:                uint32 lba;
        !           373:                uint32 blks;
        !           374: 
        !           375:                if ((cmds[1] & 0x01)) {
        !           376:                        PANIC("SCSI Read(10) RelAdr not supported");
        !           377:                }
        !           378: 
        !           379:                lba  = cmds[2] << 24;
        !           380:                lba |= cmds[3] << 16;
        !           381:                lba |= cmds[4] << 8;
        !           382:                lba |= cmds[5];
        !           383: 
        !           384:                blks  = cmds[7] << 8;
        !           385:                blks |= cmds[8];
        !           386: 
        !           387:                // XXX 範囲チェック
        !           388:                dataptr = hdparent->mem + (lba * hdparent->blocksize);
        !           389:                datalen = blks * parent->blocksize;
        !           390: 
        !           391:                parent->putlog(1, "READ10 $%x %d", lba, blks);
        !           392: 
        !           393:                return SCSI::Phase::DataIn;
        !           394:        }
        !           395: 
        !           396:        virtual uint DataInBegin(const uint8 **ptr) {
        !           397:                *ptr = dataptr;
        !           398:                return datalen;
        !           399:        }
        !           400: 
        !           401:  private:
        !           402:        SCSIHD *hdparent = NULL;
        !           403:        uint8 *dataptr = 0;             // 今回の Read の先頭
        !           404:        uint datalen = 0;               // 今回の Read のバイト数
        !           405: };
        !           406: 
        !           407: // サポートしていないコマンドを受け取った時の処理。
        !           408: class SCSICmdNotSupportedCommand : public SCSICmd
        !           409: {
        !           410:        typedef SCSICmd inherited;
        !           411:  public:
        !           412:        SCSICmdNotSupportedCommand(SCSITarget *p) : inherited(p) { }
        !           413:        virtual ~SCSICmdNotSupportedCommand() { }
        !           414: 
        !           415:        // Command は何もせずステータスに移るだけなので基底のやつでいい
        !           416: 
        !           417:        virtual uint Status() {
        !           418:                return SCSI::StatusByte::CheckCondition;
        !           419:        }
        !           420: };
        !           421: 
        !           422: //
        !           423: // SCSI ターゲットデバイス基本クラス
        !           424: //
        !           425: 
        !           426: // コンストラクタ
        !           427: SCSITarget::SCSITarget(SCSIHostDevice *h, int id, SCSI::DevType type)
        !           428: {
        !           429:        host = h;
        !           430:        logname = host->GetLogName();
        !           431:        devtype = type;
        !           432:        ID = id;
        !           433:        phase = SCSI::Phase::BusFree;
        !           434: }
        !           435: 
        !           436: // デストラクタ
        !           437: SCSITarget::~SCSITarget()
        !           438: {
        !           439: }
        !           440: 
        !           441: // フェーズを newphase に遷移する
        !           442: void
        !           443: SCSITarget::SetPhase(uint newphase)
        !           444: {
        !           445:        // フェーズ遷移時に ATN をチェック。
        !           446:        // バスフリーフェーズ・アービトレーションフェーズでは ATN はセットできない。
        !           447:        // ので、それら以外で ATN が立ってる時だけ処理が必要。
        !           448:        if (phase != SCSI::Phase::BusFree &&
        !           449:            phase != SCSI::Phase::Arbitration &&
        !           450:            GetATN())
        !           451:        {
        !           452:                // lastmsg は CommandComplete に初期化してあり、CommandComplete には
        !           453:                // 解除義務はないので、1回目は必ず default に落ちるという寸法。
        !           454:                switch (lastmsg) {
        !           455:                 case SCSI::MsgByte::Disconnect:
        !           456:                 case SCSI::MsgByte::InitiatorDetectedError:
        !           457:                 case SCSI::MsgByte::Abort:
        !           458:                 case SCSI::MsgByte::MessageReject:
        !           459:                 case SCSI::MsgByte::NoOperation:
        !           460:                 case SCSI::MsgByte::MessageParityError:
        !           461:                 case SCSI::MsgByte::BusDeviceReset:
        !           462:                 case SCSI::MsgByte::AbortTag:
        !           463:                 case SCSI::MsgByte::ClearQueue:
        !           464:                 case SCSI::MsgByte::InitiateRecovery:
        !           465:                 case SCSI::MsgByte::ReleaseRecovery:
        !           466:                 case SCSI::MsgByte::TerminateIOProcess:
        !           467:                 // 2バイトコードは未対応
        !           468:                        // 解除義務があるので、継続してたらバスフリーへ移行。
        !           469:                        newphase = SCSI::Phase::BusFree;
        !           470:                        break;
        !           471:                 default:
        !           472:                        // 解除義務はないので、継続して受け付ける。
        !           473:                        // (1回目もここに来る)
        !           474:                        nextphase = newphase;
        !           475:                        newphase = SCSI::Phase::MsgOut;
        !           476:                        break;
        !           477:                }
        !           478:        }
        !           479: 
        !           480:        // MsgOut フェーズを抜ける際には必ず lastmsg を CommandComplete に戻す。
        !           481:        // CommandComplete が1回目フラグも兼ねているので。
        !           482:        if (phase == SCSI::Phase::MsgOut && newphase != SCSI::Phase::MsgOut) {
        !           483:                lastmsg = SCSI::MsgByte::CommandComplete;
        !           484:        }
        !           485: 
        !           486:        // フェーズ遷移
        !           487:        phase = newphase;
        !           488:        switch (newphase) {
        !           489:         case SCSI::Phase::BusFree:
        !           490:                // 自身の状態を変更
        !           491:                BusFreePhase();
        !           492:                // バスの状態を変更 (バスを管理してるのはここではホストの基本クラス)
        !           493:                host->B_BusFree(ID);
        !           494:                // ホストに状態変更を通知
        !           495:                host->BusRelease();
        !           496:                break;
        !           497:         case SCSI::Phase::Arbitration:
        !           498:         case SCSI::Phase::Selection:
        !           499:         case SCSI::Phase::Reselection:
        !           500:                // ?
        !           501:                break;
        !           502:         case SCSI::Phase::DataOut:
        !           503:                DataOutPhase();
        !           504:                break;
        !           505:         case SCSI::Phase::DataIn:
        !           506:                DataInPhase();
        !           507:                break;
        !           508:         case SCSI::Phase::Command:
        !           509:                CommandPhase();
        !           510:                break;
        !           511:         case SCSI::Phase::Status:
        !           512:                StatusPhase();
        !           513:                break;
        !           514:         case SCSI::Phase::MsgOut:
        !           515:                MsgOutPhase();
        !           516:                break;
        !           517:         case SCSI::Phase::MsgIn:
        !           518:                MsgInPhase();
        !           519:                break;
        !           520:        }
        !           521: }
        !           522: 
        !           523: // セレクション成功。
        !           524: void
        !           525: SCSITarget::Selected()
        !           526: {
        !           527:        SetPhase(SCSI::Phase::Command);
        !           528:        SetREQ(true);
        !           529: }
        !           530: 
        !           531: void
        !           532: SCSITarget::Ack()
        !           533: {
        !           534:        lastdata = GetDATA();
        !           535:        SetREQ(false);
        !           536:        putlog(3, "#%d data=%02x", ID, lastdata);
        !           537: }
        !           538: 
        !           539: // バスフリーフェーズ
        !           540: void
        !           541: SCSITarget::BusFreePhase()
        !           542: {
        !           543:        lastdata = 0;
        !           544:        lastmsg = 0;
        !           545: }
        !           546: 
        !           547: void
        !           548: SCSITarget::DataOutPhase()
        !           549: {
        !           550:        SetMSG(false);
        !           551:        SetCD(false);
        !           552:        SetIO(false);
        !           553:        putlog(3, "#%d Target DataOutPhase", ID);
        !           554: }
        !           555: 
        !           556: void
        !           557: SCSITarget::DataInPhase()
        !           558: {
        !           559:        SetMSG(false);
        !           560:        SetCD(false);
        !           561:        SetIO(true);
        !           562:        putlog(3, "#%d Target DataInPhase", ID);
        !           563: }
        !           564: 
        !           565: void
        !           566: SCSITarget::CommandPhase()
        !           567: {
        !           568:        SetMSG(false);
        !           569:        SetCD(true);
        !           570:        SetIO(false);
        !           571:        putlog(3, "#%d Target CommandPhase", ID);
        !           572: }
        !           573: 
        !           574: void
        !           575: SCSITarget::StatusPhase()
        !           576: {
        !           577:        SetMSG(false);
        !           578:        SetCD(true);
        !           579:        SetIO(true);
        !           580:        putlog(3, "#%d Target StatusPhase", ID);
        !           581: }
        !           582: 
        !           583: void
        !           584: SCSITarget::MsgOutPhase()
        !           585: {
        !           586:        SetMSG(true);
        !           587:        SetCD(true);
        !           588:        SetIO(false);
        !           589:        putlog(3, "#%d Target MsgOutPhase", ID);
        !           590: }
        !           591: 
        !           592: void
        !           593: SCSITarget::MsgInPhase()
        !           594: {
        !           595:        SetMSG(true);
        !           596:        SetCD(true);
        !           597:        SetIO(true);
        !           598:        putlog(3, "#%d Target MsgInPhase", ID);
        !           599: }
        !           600: 
        !           601: // データインフェーズの処理。
        !           602: uint
        !           603: SCSITarget::ExecDataIn(const uint8 **ptr)
        !           604: {
        !           605:        // コマンド固有のデータインフェーズの処理
        !           606:        uint len = cmd->DataInBegin(ptr);
        !           607: 
        !           608:        // ステータスフェーズに移行
        !           609:        SetPhase(SCSI::Phase::Status);
        !           610: 
        !           611:        return len;
        !           612: }
        !           613: 
        !           614: // データアウトフェーズの処理。
        !           615: uint
        !           616: SCSITarget::ExecDataOut(uint8 **ptr)
        !           617: {
        !           618:        // コマンド固有のデータアウトフェーズの処理
        !           619:        uint len = cmd->DataOutBegin(ptr);
        !           620: 
        !           621:        // ステータスフェーズに移行
        !           622:        SetPhase(SCSI::Phase::Status);
        !           623: 
        !           624:        return len;
        !           625: }
        !           626: 
        !           627: // コマンドフェーズの処理。
        !           628: // イニシエータが必要な長さ分のコマンドをホスト OS から受信したところで
        !           629: // イニシエータ側から呼ばれて、コマンドの処理を行う。
        !           630: // 処理後は次のフェーズに遷移する。
        !           631: void
        !           632: SCSITarget::ExecCommand(const std::vector<uint8>& argcmds)
        !           633: {
        !           634:        cmds = argcmds;
        !           635: 
        !           636:        const char *cmdname = SCSI::GetCommandName(cmds[0]);
        !           637:        if (cmdname != NULL) {
        !           638:                putlog(1, "#%d $%02x %s", ID, cmds[0], cmdname);
        !           639:        } else {
        !           640:                putlog(1, "#%d $%02x unknown command", ID, cmds[0]);
        !           641:        }
        !           642: 
        !           643:        // コマンドを選択。
        !           644:        // まずデバイス固有のコマンドをサーチ。
        !           645:        cmd = ExecDeviceCommand();
        !           646:        // 派生クラス側で選択されなければ、こちらでサーチ。
        !           647:        if (cmd == NULL) {
        !           648:                switch (cmds[0]) {
        !           649:                 case SCSI::Command::TestUnitReady:
        !           650:                        cmd = new SCSICmdTestUnitReady(this);
        !           651:                        break;
        !           652: 
        !           653:                 case SCSI::Command::RequestSense:
        !           654:                        cmd = new SCSICmdRequestSense(this);
        !           655:                        break;
        !           656: 
        !           657:                 case SCSI::Command::ModeSelect6:
        !           658:                        cmd = new SCSICmdModeSelect6(this);
        !           659:                        break;
        !           660: 
        !           661:                 default:
        !           662:                        // サポートしていないコマンド
        !           663:                        const char *cname = SCSI::GetCommandName(cmds[0]);
        !           664:                        std::string name;
        !           665:                        if (cname) {
        !           666:                                name = string_format(" %s", cname);
        !           667:                        }
        !           668:                        putlog(0, "未実装 SCSI コマンド $%02x%s len=%zd",
        !           669:                                cmds[0], name.c_str(), cmds.size());
        !           670: 
        !           671:                        cmd = new SCSICmdNotSupportedCommand(this);
        !           672:                        break;
        !           673:                }
        !           674:        }
        !           675: 
        !           676:        uint newphase = cmd->Command(cmds);
        !           677:        SetPhase(newphase);
        !           678: }
        !           679: 
        !           680: SCSICmd *
        !           681: SCSITarget::ExecDeviceCommand()
        !           682: {
        !           683:        PANIC("should not reached");
        !           684: }
        !           685: 
        !           686: // ステータスバイトを取得およびデータアウトフェーズ完了処理。
        !           687: uint8
        !           688: SCSITarget::GetStatusByte()
        !           689: {
        !           690:        // データフェーズの完了処理をここで行う。
        !           691:        cmd->DataDone();
        !           692: 
        !           693:        // XXX まだコマンド側からログが出せないのでとりあえず
        !           694:        if (cmds[0] == SCSI::Command::ModeSelect6) {
        !           695:                putlog(2, "#%d Mode Select 論理ブロック長 = %d", ID, blocksize);
        !           696:        }
        !           697: 
        !           698:        // ステータスバイトを取得。
        !           699:        uint statusbyte = cmd->Status();
        !           700: 
        !           701:        // メッセージインフェーズに移行。
        !           702:        SetPhase(SCSI::Phase::MsgIn);
        !           703:        return statusbyte;
        !           704: }
        !           705: 
        !           706: uint8
        !           707: SCSITarget::GetMessageByte()
        !           708: {
        !           709:        // メッセージを取得。
        !           710:        uint messagebyte = cmd->MsgIn();
        !           711: 
        !           712:        // CommandComplete メッセージを正常に送信したらバスフリーフェーズに移行。
        !           713:        // 実際には正常に送信できたら、だけど。
        !           714:        if (messagebyte == SCSI::MsgByte::CommandComplete) {
        !           715:                SetPhase(SCSI::Phase::BusFree);
        !           716:        }
        !           717: 
        !           718:        // コマンドクラスを解放
        !           719:        // ここでいいか。
        !           720:        delete cmd;
        !           721:        cmd = NULL;
        !           722: 
        !           723:        return messagebyte;
        !           724: }
        !           725: 
        !           726: 
        !           727: //
        !           728: // SCSI HD
        !           729: //
        !           730: 
        !           731: // コンストラクタ
        !           732: SCSIHD::SCSIHD(SCSIHostDevice *h, int id)
        !           733:        : inherited(h, id, SCSI::HD)
        !           734: {
        !           735:        devname = "SCSIHD";
        !           736:        logname = "scsihd";
        !           737: 
        !           738:        fd = -1;
        !           739: }
        !           740: 
        !           741: // デストラクタ
        !           742: SCSIHD::~SCSIHD()
        !           743: {
        !           744: }
        !           745: 
        !           746: // イメージファイルの読み込み
        !           747: bool
        !           748: SCSIHD::Init()
        !           749: {
        !           750:        struct stat st;
        !           751: 
        !           752:        const std::string myname = string_format("%s(%s,ID%d)",
        !           753:                devname, host->GetConfigName(), ID);
        !           754:        const std::string keybody = string_format("%s_id%d_",
        !           755:                host->GetConfigName(), ID);
        !           756:        const std::string imgkey = string_format("%s%s",
        !           757:                keybody.c_str(), "image");
        !           758:        const std::string wpkey  = string_format("%s%s",
        !           759:                keybody.c_str(), "writeprotect");
        !           760: 
        !           761:        // devtype があって image がないのは異常状態なのでエラー
        !           762:        const std::string& filename = gConfig->ReadStr(imgkey);
        !           763:        if (filename == "") {
        !           764:                gConfig->Err(imgkey, "not specified");
        !           765:                return false;
        !           766:        }
        !           767: 
        !           768:        writeprotect = (bool)gConfig->ReadInt(wpkey);
        !           769:        if (writeprotect) {
        !           770:                putmsg(0, "%s: write protected", myname.c_str());
        !           771:        }
        !           772: 
        !           773:        const std::string path = gConfig->GetConfigDir() + filename;
        !           774:        fd = open(path.c_str(), O_RDWR);
        !           775:        if (fd == -1) {
        !           776:                warn("%s cannot open %s", myname.c_str(), path.c_str());
        !           777:                return false;
        !           778:        }
        !           779: 
        !           780:        if (fstat(fd, &st) == -1) {
        !           781:                warn("%s cannot stat %s", myname.c_str(), path.c_str());
        !           782:                close(fd);
        !           783:                return false;
        !           784:        }
        !           785: 
        !           786:        memlen = st.st_size;
        !           787:        mem = (uint8 *)mmap(NULL, memlen, PROT_READ | PROT_WRITE,
        !           788:                MAP_SHARED, fd, 0);
        !           789:        if (mem == MAP_FAILED) {
        !           790:                warn("%s cannot mmap %s", myname.c_str(), path.c_str());
        !           791:                close(fd);
        !           792:                return false;
        !           793:        }
        !           794: 
        !           795:        return true;
        !           796: }
        !           797: 
        !           798: // HD 固有のコマンドの処理。
        !           799: // こちらで処理すれば次フェーズを返す。そうでなければ None を返す。
        !           800: SCSICmd *
        !           801: SCSIHD::ExecDeviceCommand()
        !           802: {
        !           803:        switch (cmds[0]) {
        !           804:         case SCSI::Command::Read6:
        !           805:                return new SCSICmdRead6(this);
        !           806: 
        !           807:         case SCSI::Command::Write6:
        !           808:                return new SCSICmdWrite6(this);
        !           809: 
        !           810:         case SCSI::Command::Inquiry:
        !           811:                // これは共通コマンドだけど引数だけ違う
        !           812:                return new SCSICmdInquiry(this, inquiry_data, sizeof(inquiry_data));
        !           813: 
        !           814:         case SCSI::Command::ReadCapacity:
        !           815:                return new SCSICmdReadCapacity(this);
        !           816: 
        !           817:         case SCSI::Command::Read10:
        !           818:                return new SCSICmdRead10(this);
        !           819: 
        !           820:         default:
        !           821:                // それ以外は基本クラス側で処理する。
        !           822:                return NULL;
        !           823:        }
        !           824: }
        !           825: 
        !           826: // HD の inquiry データ
        !           827: /*static*/ const uint8
        !           828: SCSIHD::inquiry_data[36] = {
        !           829:        0x00,   // 00 Qualifier + DeviceType
        !           830:        0x00,   // 01 RMB
        !           831:        0x40,   // 02 ISO version
        !           832:        0x00,   // 03 Response Data Format?
        !           833:        36 - 4, // 04 追加データ長
        !           834:        0,              // 05 Reserved
        !           835:        0,              // 06 Reserved
        !           836:        0x00,   // 07
        !           837:        'V', 'E', 'N', 'D', 'E', 'R', ' ', ' ',
        !           838:        'P', 'R', 'O', 'D', 'U', 'C', 'T', ' ',
        !           839:        'N', 'A', 'M', 'E', ' ', ' ', ' ', ' ',
        !           840:        '0', '1', '2', '3',
        !           841: };

unix.superglobalmegacorp.com

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