|
|
1.1 root 1: //
2: // nono
1.1.1.3 root 3: // Copyright (C) 2020 nono project
4: // Licensed under nono-license.txt
1.1 root 5: //
6:
1.1.1.10 root 7: //
1.1 root 8: // SCSI バス
1.1.1.10 root 9: //
1.1 root 10:
1.1.1.15 root 11: // フェーズ遷移についてのメモ。
12: //
13: // イニシエータ(この時点ではまだ候補だが)が BSY を立てることで
14: // (バスフリーフェーズから) アービトレーションフェーズに移る。
15: // 現行では規定時間後に自動的にイニシエータが勝利する(バスは何もしない)。
16: // イニシエータが SEL 立てて BSY を下ろすことで、セレクションフェーズに移る。
17: // この間の遷移は以下の通り。
18: // BSY SEL
19: // 0 0 BusFree
20: // ↓ イニシエータ(候補)が BSY を立てる
21: // 1 0 Arbitration (バスは何もしない)
22: // ↓ イニシエータが SEL を立てる
23: // 1 1 Arbitration
24: // ↓ イニシエータがデータバスにターゲットをセットして BSY を下ろす
25: // 0 1 Selection
26: //
27: // バスはセレクションフェーズ遷移後、規定時間でターゲットに通知。
28: // ターゲットは即 BSY を立てるのでバスはこれをイニシエータに通知。
29: // イニシエータは SEL を下げるのでバスはこれをターゲットに通知。
30: // この間の遷移は以下の通り。
31: // BSY SEL
32: // 0 1 Selection (ターゲットに通知)
33: // ↓ ターゲットが BSY を立てる
34: // 1 1 Selection (イニシエータに通知)
35: // ↓ イニシエータがデータバスと SEL を下げる
36: // 1 0 Transfer (ターゲットに通知)
37: //
38: // バスは Transfer 後、規定時間でターゲットに通知。
39: // ターゲットは転送フェーズ(の最初のコマンドフェーズ) に移行する。
40:
41: // 転送フェーズについてのメモ。
42: //
43: // -----> (実線) は関数呼び出し
44: // - - -> (破線) は関数からの戻り
45: // 〜〜-> (波線) はイベントコールバックによる呼び出し
46: //
47: // マニュアル転送は以下のようになる。
48: // 基本的にはターゲットが REQ を上げたことをイベントでイニシエータに通知し、
49: // イニシエータは基本的に関数呼び出しでターゲットを操作することにする。
50: //
51: // 非同期転送時の REQ/ACK シーケンスに時間規定はないが、時間を考慮せずに
52: // 実行してしまうと現実より速い転送が出来てしまう可能性があるので、ここでは
53: // AssertREQ が TransferReqCB を呼び出すところでタイミングを調整する。
54: // 具体的には前回の TransferReqCB から 1usec 以上空けるというのはどうか。
55: //
56: // イニシエータ ターゲット
57: // ------------ ----------
58: // Event 〜〜-> StartTransferCB
59: // ↓
60: // REQ を上げる
61: // TransferReqCB <-〜〜〜 Event 〜〜〜
62: // ACK を上げる
63: // +------ AssertACK() ---> TransferCB
64: // 1バイト送受信
65: // REQ を下げる
66: // < - - - - - - - - - - - return;
67: // (誰かが)
68: // ACK を下げる
69: // +------ NegateACK() ---> TransferAckCB
70: // REQ を上げる 〜〜+
71: // < - - - - - - - - - - - return; :
72: // :
73: // TransferReqCB <-〜〜〜 Event 〜〜〜〜〜〜〜〜〜〜〜〜+
74: //
75: // ハードウェア転送の場合は ACK 一往復を省略して以下のようにする。
76: // Transfer() (TransferCB()) は ACK が立っていなければハードウェア転送と
77: // 判断する。
78: //
79: // イニシエータ ターゲット
80: // ------------ ----------
81: // Event 〜〜-> StartTransferCB
82: // ↓
83: // REQ を上げる
84: // TransferReqCB <-〜〜〜 Event 〜〜〜
85: // |
86: // +------- Transfer() ---> TransferCB
87: // 1バイト送受信
88: // REQ を下げる
89: // REQ を上げる 〜〜+
90: // < - - - - - - - - - - - return; :
91: // :
92: // TransferReqCB <-〜〜〜 Event 〜〜〜〜〜〜〜〜〜〜〜〜+
93: //
94:
1.1 root 95: #include "scsibus.h"
96: #include "scsidev.h"
1.1.1.15 root 97: #include "scsidomain.h"
1.1.1.16 root 98: #include "event.h"
1.1.1.10 root 99: #include "scheduler.h"
1.1 root 100:
101: // time 時間後に呼び出すコールバックをセットする。
102: // func の書式が面倒なのを省略して書きたいため。
103: #define CallAfter(func_, name_, time_) do { \
1.1.1.17! root 104: event->SetCallback(&SCSIBus::func_); \
1.1.1.16 root 105: event->time = time_; \
106: event->SetName(name_); \
1.1.1.11 root 107: scheduler->RestartEvent(event); \
1.1 root 108: } while (0)
109:
110: // コンストラクタ
1.1.1.15 root 111: SCSIBus::SCSIBus(SCSIDomain *domain_)
1.1.1.11 root 112: : inherited(OBJ_SCSIBUS)
1.1 root 113: {
1.1.1.15 root 114: domain = domain_;
1.1 root 115: }
116:
117: // デストラクタ
118: SCSIBus::~SCSIBus()
119: {
120: }
121:
1.1.1.12 root 122: // 初期化
123: bool
124: SCSIBus::Init()
125: {
1.1.1.15 root 126: // 現時点で管理下にあるデバイス(ターゲット)をバスに接続。
127: // イニシエータはこの時点では ID 未定なのでバスには繋がらない。
128: Refresh();
129:
1.1.1.16 root 130: auto evman = GetEventManager();
131: // 複数出来たら名前どうするべか
132: event = evman->Regist(this, NULL, "SCSIBus");
1.1.1.12 root 133:
134: return true;
135: }
136:
1.1.1.10 root 137: // 電源オン/リセット
1.1.1.4 root 138: void
1.1.1.10 root 139: SCSIBus::ResetHard(bool poweron)
1.1.1.4 root 140: {
1.1.1.10 root 141: if (poweron) {
142: phase = SCSI::Phase::BusFree;
143: rst = false;
144: req = false;
145: ack = false;
146: atn = false;
147: sel = 0;
148: bsy = 0;
149: xfer = 0;
150: data = 0;
151:
152: last_req_time = 0;
153: req_wait = 0;
154: init_id = -1;
155: target_id = -1;
156: }
157:
1.1.1.4 root 158: // ここでのイベントは実際にはイニシエータかターゲットのどちらかが
159: // 時間を伴う処理をしている最中であることを示しているものなので、
160: // イニシエータがリセットされたこととバスの動作とは本来関係ないのだが
161: // ここでは特にイニシエータに次のバイトを転送させる、という目的で
162: // タイマーイベントが使われており、本体をリセットしたのに入れ違いで
163: // イニシエータの転送処理が呼び出されてしまうというような事故を
164: // 防ぐためにもここでタイマーを停止する。
1.1.1.11 root 165: scheduler->StopEvent(event);
1.1.1.4 root 166: }
167:
1.1.1.15 root 168: // デバイス情報を更新する。
169: // domain の device[] が変更されたら呼ぶこと。
1.1.1.12 root 170: void
1.1.1.15 root 171: SCSIBus::Refresh()
1.1.1.12 root 172: {
1.1.1.15 root 173: domain->GetDevices(&device);
1.1.1.12 root 174: }
175:
1.1 root 176: // RST を上げる
177: void
178: SCSIBus::AssertRST()
179: {
180: putlog(4, "%s", __func__);
181:
182: // すでに上がってたら何もしない
183: if (rst) {
184: return;
185: }
186:
187: rst = true;
188:
189: // 即バスリセットを全員に通知
1.1.1.15 root 190: for (int i = 0; i < device.size(); i++) {
1.1 root 191: if (device[i]) {
1.1.1.12 root 192: device[i]->OnBusReset();
1.1 root 193: }
194: }
195:
196: // コールバック終了後に内部状態もクリア
197: init_id = -1;
198: target_id = -1;
199: }
200:
201: // RST を下げる
202: void
203: SCSIBus::NegateRST()
204: {
205: putlog(4, "%s", __func__);
206:
207: rst = false;
208:
209: // 特にすることはない
210: }
211:
212: // SEL を上げる
213: void
214: SCSIBus::AssertSEL(uint id)
215: {
1.1.1.12 root 216: putlog(4, "%s(#%u)", __func__, id);
1.1 root 217:
218: // すでに上がってたら何もしない
1.1.1.16 root 219: if ((sel & (1U << id))) {
1.1 root 220: return;
221: }
222:
1.1.1.16 root 223: sel |= (1U << id);
1.1 root 224:
225: if (GetPhase() == SCSI::Phase::BusFree) {
226: // バスフリーフェーズなら、アービトレーションなしでセレクション
227: // フェーズに移行。
228: //
229: // 仕様Phase |Free |<---- Selection ---->|
230: //
231: // BSY ~~\__________________________/~~~~~~~
232: //
233: // Data -----------< Initiator&Target ID >---
234: //
235: // SEL ________________/~~~~~~~~~~~~~~~~\___
236: // ^イマココ
237: //
238: // 実装Phase |<- Free ->|<-- Selection ->|
239: //
240: // SCSI 本にはデータバスが変化したところから Selection フェーズと
241: // 書いてあるように読めるけど(上)、ここでは SEL がアサートされた
242: // ところからとする(下)。
243:
244: SetPhase(SCSI::Phase::Selection);
245:
246: // SEL を上げた人がイニシエータ
247: init_id = id;
248:
249: // 即セレクション開始。
250: CallAfter(SelectionStart, "SCSIBus Selection Start", 0);
251:
252: } else if (GetPhase() == SCSI::Phase::Arbitration) {
253: // アービトレーションフェーズなら、
254: // アービトレーションに勝ってセレクションフェーズに移行途中。
255: // この場合はセレクションフェーズに移行するのはここではなく
256: // BSY の立ち下がりなので、そっち参照。
257: //
258: // 仕様Phase Arbitration |---|<--- Selection -->|
259: //
260: // BSY /~~~~~~~~~~~~~~~\_______________/~~~~~~
261: //
262: // Data <InitiatorID>< Initiator&Target ID >---
263: //
264: // SEL __________/~~~~~~~~~~~~~~~~~~~~~~~~\___
265: // ^イマココ
266: //
267: // 実装Phase <-Arbitration ->|<--- Selection -->|
268:
269: // SEL を上げた人がイニシエータなことだけはここで覚えておく。
270: init_id = id;
271:
272: } else {
1.1.1.6 root 273: // それ以外(転送フェーズ)中に SEL が立てられたらどうすればいいか。
274: // これは転送中に LUNA をリセットすると起きる。LUNA の PROM は SPC に
275: // 対してバスリセットを発行せずに、セレクションを行おうとするため。
276: // SCSI 本には載ってないので分からないが、このような規約違反はたいてい
277: // イニシエータが検出してバスフリーかバスリセットを行うことが意図
278: // されているんじゃないかと想像するけど、今回そのイニシエータが違反
279: // してるので、どうするんだろうね。
280: // 賢いターゲットデバイスだとこれを検出して自主的にバスフリーへ落ちる
281: // だろうか。賢くないターゲットデバイスは検出せずにそのまま (そして
282: // デッドロック) になるだろうか。
283:
1.1.1.7 root 284: #if 1
285: // XXX とりあえず LUNA で SCSI がなんか刺さった時に本体リセットでも
286: // 直らない状況を真似するため、ターゲットは何もしないでおく。
287: #else
1.1.1.6 root 288: // ターゲットデバイスは賢いので、全員イニシエータ様に忖度して
289: // 即座にバスフリーへ移行するというのはどうか。
1.1.1.15 root 290: for (uint i = 0; i < device.size(); i++) {
1.1.1.6 root 291: if (i != id) {
292: NegateBSY(i);
293: }
294: }
1.1.1.7 root 295: #endif
1.1 root 296: }
297: }
298:
299: // SEL を下げる
300: void
301: SCSIBus::NegateSEL(uint id)
302: {
1.1.1.12 root 303: putlog(4, "%s(#%u)", __func__, id);
1.1 root 304:
305: // すでに下りてたら何もしない
1.1.1.16 root 306: if ((sel & (1U << id)) == 0) {
1.1 root 307: return;
308: }
309:
1.1.1.16 root 310: sel &= ~(1U << id);
1.1 root 311:
1.1.1.6 root 312: if (GetPhase() == SCSI::Phase::BusFree) {
313: // バスフリーフェーズで SEL を下げる
314:
315: // 通常は起きないはずだけど、転送フェーズ中に LUNA をリセットすると
316: // -> LUNA の PROM が SEL を上げる (プロトコル違反)
317: // -> ターゲットは転送フェーズ中なのに SEL が上がったのを検出して
318: // BSY を取り下げてバスフリーに移行する
319: // -> バスフリーがイニシエータに通知され、イニシエータが SEL を下げる
320: // となるので、このケースはスルーしてよい。
321:
322: } else if (GetPhase() == SCSI::Phase::Selection) {
1.1 root 323: // セレクションフェーズで SEL を下げる
324: if (bsy) {
325: // BSY が立っていれば、ターゲットがセレクションに応答したので
326: // イニシエータが SEL を下げて、これから任意時間後にターゲットが
327: // 情報転送フェーズに移行する。
328:
329: CallAfter(StartTransfer, "SCSIBus Transfer Start", 400_nsec);
330: } else {
331: // BSY が立ってなければ、ターゲットが応答しなかったことに
332: // イニシエータがあきらめて SEL を下げたので、何もせず
333: // バスフリーフェーズに移行。
334: BusFree(id);
335: }
336: } else {
1.1.1.6 root 337: // 下げる分には無視してもいいはずだけど、どうする?
1.1.1.10 root 338: VMPANIC("NegateSEL in %s phase", GetPhaseName());
1.1 root 339: }
340: }
341:
342: // BSY を上げる
343: void
344: SCSIBus::AssertBSY(uint id)
345: {
1.1.1.12 root 346: putlog(4, "%s(#%u)", __func__, id);
1.1 root 347:
348: // すでに上がってたら何もしない
1.1.1.16 root 349: if ((bsy & (1U << id))) {
1.1 root 350: return;
351: }
352:
1.1.1.16 root 353: bsy |= (1U << id);
1.1 root 354:
355: if (GetPhase() == SCSI::Phase::BusFree) {
356: // バスフリーフェーズだったらアービトレーション開始
357:
358: // 実際のアービトレーションは、
359: // バスフリーを検出してから規定時間経過後に、データバスに自身の ID を
360: // 出して BSY を立てる。規定時間内に他のデバイスもアービトレーションに
361: // 参加すれば ID の高い方が勝つ。負けた方は規定時間内にアービトレー
362: // ションを取り下げる。規定期間経って勝っていればアービトレーション
363: // 成功となり、セレクションフェーズに移る。
364: // のだが、エミュレータ上では、今の所アービトレーションで競合が起きる
365: // ことはないため、アービトレーションは規定時間経過して必ず成功する。
366: // ちゃんとしたアービトレーションを実装する場合はたぶんこれだけでは
367: // 済まないと思うので書き換えること。
368:
369: SetPhase(SCSI::Phase::Arbitration);
370:
371: } else if (GetPhase() == SCSI::Phase::Arbitration) {
372: // アービトレーションフェーズだったら、アービトレーションに参加。
373: // 今は起きない。
1.1.1.12 root 374: VMPANIC("AssertBSY(#%u) in arbitration", id);
1.1 root 375:
376: } else if (GetPhase() == SCSI::Phase::Selection) {
377: // セレクションフェーズだったら、転送フェーズに移行中。
378: // ターゲットが BSY をアサートしたので次は規定時間経過後に
379: // SelectionAck() を呼び出してイニシエータに SEL を下げさせる。
380:
381: CallAfter(SelectionAck, "SCSIBus Selection Ack", 90_nsec);
382: } else {
383: // どうする?
1.1.1.12 root 384: VMPANIC("AssertBSY(#%u) in %s phase", id, GetPhaseName());
1.1 root 385: }
386: }
387:
388: // BSY を下げる
389: void
390: SCSIBus::NegateBSY(uint id)
391: {
1.1.1.12 root 392: putlog(4, "%s(#%u)", __func__, id);
1.1 root 393:
394: // すでに下りてたら何もしない
1.1.1.16 root 395: if ((bsy & (1U << id)) == 0) {
1.1 root 396: return;
397: }
398:
1.1.1.16 root 399: bsy &= ~(1U << id);
1.1 root 400:
401: if (GetPhase() == SCSI::Phase::Transfer) {
402: // 転送フェーズから BSY を下げたらバスフリーに移行。
403: BusFree(id);
404:
405: } else if (GetPhase() == SCSI::Phase::Arbitration) {
406: // アービトレーションフェーズなら、
407: // イニシエータが BSY を下ろすことでセレクションフェーズに移行。
408: //
409: // この少し上の AssertSEL() 中のタイムチャート参照。
410:
411: SetPhase(SCSI::Phase::Selection);
412:
413: // 即セレクション開始。
414: CallAfter(SelectionStart, "SCSIBus Selection Start", 0);
415:
416: } else {
417: // どうする?
1.1.1.12 root 418: VMPANIC("NegateBSY(#%u) in %s phase", id, GetPhaseName());
1.1 root 419: }
420: }
421:
422: // MSG, CD, IO 信号線を変更する。
423: void
424: SCSIBus::SetXfer(uint8 val)
425: {
426: uint8 oldxfer = xfer;
427:
428: xfer = val & (SCSI::MSG | SCSI::CD | SCSI::IO);
429: if (oldxfer != xfer) {
430: if (GetPhase() == SCSI::Phase::Transfer) {
431: putlog(4, "SetXfer(%x:%s)", xfer, SCSI::GetXferPhaseName(xfer));
432: } else {
433: putlog(4, "SetXfer(%x)", xfer);
434: }
435: }
436: }
437:
438: // REQ を上げる
439: void
440: SCSIBus::AssertREQ()
441: {
442: if (GetPhase() == SCSI::Phase::Transfer) {
443: // REQ を上げると言いつつ、ここで転送レートの時間調整をしているので
444: // (scsibus.h の解説参照) REQ を実際に上げるのはイベント発生後。
445: // XXX 本来ターゲットデバイスがタイマー持っててやるべきだけど、
446: // イベントがもう一つ増えるのもうざいので。どのみち、ここの REQ
447: // 通知はイベントにしないといけないので。
448:
449: uint64 after = 0;
1.1.1.11 root 450: uint64 now = scheduler->GetVirtTime();
1.1 root 451: if (now < last_req_time + 1_usec) {
452: after = (last_req_time + 1_usec) - now;
453: }
1.1.1.4 root 454: // ウェイトが指示されていれば入れる (シークタイムなど)
455: if (req_wait != 0) {
456: after += req_wait;
457: req_wait = 0;
458: }
1.1.1.9 root 459: last_req_time = now + after;
1.1 root 460: CallAfter(TransferReq, "SCSIBus AssertREQ", after);
461: } else {
462: // 転送フェーズでないのに上げることはないと思うけど
463: // とりあえず通知もせずその場で上げておくか?
464: putlog(4, "%s", __func__);
465: req = true;
466: }
467: }
468:
469: // ターゲットが REQ を立てようとして所定時間経ったので REQ を立てて
1.1.1.12 root 470: // イニシエータの OnTransferReq を呼び出すところ。
1.1 root 471: void
1.1.1.16 root 472: SCSIBus::TransferReq(Event *ev)
1.1 root 473: {
474: putlog(4, "AssertREQ");
475: req = true;
476:
477: assert(device[init_id]);
1.1.1.12 root 478: device[init_id]->OnTransferReq();
1.1 root 479: }
480:
481: // REQ を下げる
482: void
483: SCSIBus::NegateREQ()
484: {
485: putlog(4, "%s", __func__);
486: req = false;
487: }
488:
489: // ACK を上げる
490: void
491: SCSIBus::AssertACK()
492: {
493: putlog(4, "%s", __func__);
494: ack = true;
495:
496: if (GetPhase() == SCSI::Phase::Transfer) {
497: assert(device[target_id]);
1.1.1.12 root 498: device[target_id]->OnTransfer();
1.1 root 499: }
500: }
501:
502: // ACK を下げる
503: void
504: SCSIBus::NegateACK()
505: {
506: putlog(4, "%s", __func__);
507: ack = false;
508:
509: if (GetPhase() == SCSI::Phase::Transfer) {
510: assert(device[target_id]);
1.1.1.12 root 511: device[target_id]->OnTransferAck();
1.1 root 512: }
513: }
514:
515: // ATN を上げる
516: void
517: SCSIBus::AssertATN()
518: {
519: putlog(4, "%s", __func__);
520: atn = true;
521: }
522:
523: // ATN を下げる
524: void
525: SCSIBus::NegateATN()
526: {
527: putlog(4, "%s", __func__);
528: atn = false;
529: }
530:
531: // バスフリーフェーズに移行。
532: // id はこのバスフリーを行ったデバイス (0..7)
533: void
1.1.1.12 root 534: SCSIBus::BusFree(uint id)
1.1 root 535: {
536: putlog(4, "%s", __func__);
537:
538: SetPhase(SCSI::Phase::BusFree);
539:
540: // 即全デバイスに通知。
1.1.1.15 root 541: for (int i = 0; i < device.size(); i++) {
1.1 root 542: if (device[i]) {
1.1.1.12 root 543: device[i]->OnBusFree(id);
1.1 root 544: }
545: }
546:
547: // コールバック終了後に内部状態もクリア
548: init_id = -1;
549: target_id = -1;
550:
551: // 通知された各デバイスは規定時間内に他の信号線も取り下げなければ
552: // ならない。
553: }
554:
555: // セレクションから情報転送フェーズまで
556: //
557: // 仕様Phase <- Selection ->|
558: //
559: // BSY _______________/~~~~~~~~~
560: //
561: // Data Initiator&Target ID >----
562: //
563: // SEL ~~~~~~~~~~~~~~~~~~~~~~\__
564: //
565: // -(1)->|--(2)-->|-(3)->|
566: //
567: // セレクションフェーズ開始後、(ターゲット)デバイスは、SEL がアサート、
568: // (IO がネゲート)、データバスの自身の ID がアサート、が 400nsec 以上
569: // 継続することで、自身がターゲットに選択されていることを認識する。(1)
570: // ターゲットは (1) から 200usec 以内に BSY をアサートする。(2)
571: // イニシエータは (2) から 90nsec 以上後に SEL (とデータ) を下げる。(3)
572: //
573: // 実装では、セレクションフェーズ開始が SelectionStart() の呼び出しに対応。
574: //
575: // ターゲットデバイスが存在していない場合はタイムアウトとなるが、これは
576: // ホストが処理するのでバスは何もしない。
577: // ターゲットデバイスが存在していれば SelectionStart() から 400nsec 後 +
578: // 200usec 以内…なので適当に間をとって 100usec 後に Selection() コールバック
579: // を呼び出す(1+2)。
580: //
1.1.1.12 root 581: // Selection() コールバック(が呼び出す device->OnSelected()) は通常 BSY を
1.1 root 582: // アサートするはずであり、そこから 90nsec 後に SelectionAck() コールバック
583: // を呼び出す(3)。
584: //
1.1.1.12 root 585: // SelectionAck() コールバック(が呼び出す device->OnSelectionAck()) は通常
1.1 root 586: // SEL をネゲートするはずであり、そこから情報転送フェーズへの移行には特に
587: // 規定はなさそうなので、400nsec 後に StartTransfer() をコールバックして
588: // デバイスを情報転送フェーズに移行させる。
589:
590: // セレクションフェーズ開始。
591: void
1.1.1.16 root 592: SCSIBus::SelectionStart(Event *ev)
1.1 root 593: {
594: // この時点でデータバスには自身の ID と相手の ID が立っているはず。
595: // 一方 sel は SEL 信号線を立てた人のビットを持っているので、
596: // これでターゲットを特定する。
597: uint target_mask = data ^ sel;
598: if (__builtin_popcount(target_mask) != 1) {
599: // データバスから自身を除いた結果立ってるビットが1個以外だったら
600: // 誰も応答しないので、何もせず帰ってよい。
1.1.1.2 root 601: putlog(3, "%s (No target specified; databus=$%02x)", __func__, data);
1.1 root 602: return;
603: }
604:
605: // ターゲット ID はここで取得
606: target_id = DecodeID(target_mask);
607: if (device[target_id] == NULL) {
608: // ターゲットデバイスがいなければ、バスは何もしない。
609: // (その結果イニシエータでタイムアウトが起きるはず)
610: putlog(4, "%s (No target)", __func__);
611: return;
612: }
613:
614: // ターゲットデバイスがいれば、規定時間経過後ターゲットに通知。
615: putlog(4, "%s", __func__);
616: CallAfter(Selected, "SCSIBus Selected", 100_usec);
617: }
618:
619: // SelectionStart() にてターゲットが選択されて規定時間経ったので
620: // そろそろターゲットが BSY を立てる頃に呼ばれるコールバック。
621: void
1.1.1.16 root 622: SCSIBus::Selected(Event *ev)
1.1 root 623: {
624: // ターゲットに通知。ターゲットがいることは確定している。
625: assert(device[target_id]);
1.1.1.12 root 626: device[target_id]->OnSelected();
1.1 root 627: }
628:
629: // ターゲットが BSY を立てて規定時間経ったので
1.1.1.4 root 630: // そろそろイニシエータが SEL を下げる頃に呼ばれるコールバック。
1.1 root 631: void
1.1.1.16 root 632: SCSIBus::SelectionAck(Event *ev)
1.1 root 633: {
634: // イニシエータに通知。
635: assert(device[init_id]);
1.1.1.12 root 636: device[init_id]->OnSelectionAck();
1.1 root 637: }
638:
639: // 情報転送フェーズ開始を通知する。
640: // BSY を上げて情報転送フェーズに移行したところで呼ばれる。
641: void
1.1.1.16 root 642: SCSIBus::StartTransfer(Event *ev)
1.1 root 643: {
644: SetPhase(SCSI::Phase::Transfer);
645:
646: assert(device[target_id]);
1.1.1.12 root 647: device[target_id]->OnStartTransfer();
648: }
649:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.