このシチュエーションで、Hubはどう動くか? という話であるが、DownStream Portに着目すると、まずスタートするのはDSPORT.Disconnectである(Photo01)。上位にあるDevice/Hubの電源が入った、あるいはDeviceの速度変更が入った、などの場合には、まずこのStateに到着することになる。この状態では、PortのLogical PowerをOnとした上で、下位DeviceとのConnection確立を待つ形になる。ここから抜けてDSPORT.Trainingに遷移するのは、RxDetext、つまりDownstream側のRxポートに配線が接続され、かつその先のControllerが稼動したことを確認したタイミングとなる(これは配線のインピーダンスが変わることで検出できる)。また、大半のエラー状態では再びこのDSPORT.Disconnectedに戻る。要するにHubからケーブルなりDeviceなりが抜かれる、というケースが非常に多い(これは使い方を考えれば当然)だからで、この場合は当然何も繋がっていないからDSPORT.Disconnectでいいわけだ。

Photo01: 厳密に言えば、他にDSPORT.Powered-offとかDSPORT.Disabledといったステートがあるのは前回説明した通り。

さて、接続を確認したら、DSPORT.Trainingに入り、Link Trainingを開始する(Photo02)。ここで1st LPFS TimeoutになったらDSPORT.Complianceに遷移し、Compliance Testを実施するし、DeviceがLoopback Testを実施したい場合はTS2 ordered setを返してくるので、この場合はDSPORT.Loopbackに遷移する。問題なくLink Trainingが完了したら、Link StateがPolling.IdleからU0に移り、これにあわせてDSPORT.Enabledに遷移する形だ。またTimeoutが発生した場合は、やっぱりDSPORT.Disconnectに戻る。

Photo02: Link Trainingの内容はDeviceの場合と全く同一である。したがって、Deviceから見た場合、Hostと同一の振る舞いをすることになる。

一度U0に入った後は、DSPORT.Enabledの中で以後処理が行われるという話は前回もした通りだ(Photo03)。U0~U3 Stateの他、Recovery StateもこのDSPORT.Enabledの内部で処理される事になる。では、Hubに何かDeviceを繋げて使っていて、そこでUSBケーブルが抜かれたらどうなるか? という話だが、この場合はいきなりDSPORT.Disconnectedに飛ぶことになる。こちらで、DSPORT.Disconnectedに左上から繋がっているものに、"Disconnected Deteced"がある。要するにDisconnectedされたら、従来State Machineが保持していたデータを全て破棄し、またDSPORT.Disconnectedからやり直しという訳だ。これはこれで理にかなっている。というのは、一度Downstream側がDisconnectされたら、再びケーブルが繋がった時に同じ構成とは限らないし、Device側もDisconnect直前の状態を保持しているとは限らないからで、であればState Machineもリセットして全部やり直した方が早い。

Photo03: 面白いのは、DSPORT.Enabledから直接DSPORT.RESETTINGに推移することはないこと。エラー処理をせずにいきなりPortがリセットされてしまっては困るとは思うが、前回も書いたとおり自動でRecover出来ない場合はDSPORT.Errorに入れてしまい、後は人手で回復させると割り切っているためだろう。まぁHostの知らないところで勝手にUSBのResetを掛けられてしまっても困るのだろうが。

ではDSPORT.Resettingは何をするか? (Photo04)という話だが、こちらは端的に言えばUSB全体のResetが掛かった場合に発生する。Upstream側からSet Port FeatureとしてPORT_RESETないしPORT_BH_RESETを受信した場合、これをDownStream側に送信する。これが正常にDownstream側Deviceに伝達でき、また規定時間内にDeviceが再起動すれば、そのままDSPORT.Enabledに遷移するし、規定時間内に間に合わなければDSPORT.Disconnectedに遷移する。そもそも伝達に失敗した場合はDSPORT.Errorに遷移して終りという訳だ。ちなみにこのStateにはいるのは、自身がDSPORT.DisconnectedとかDSPORT.Powered-offに居ない場合に限られる。これらの場合だと、そもそもResetを伝達する必要が無い(というか、伝達できない)から、Set Port Featureそのものが無視され、DSPORT.RESETTINGに入らない。

Photo04: PORT_RESETはHot ResetもしくはWarm Reset(これがどちらになるか、はLTSSM stateにより決まる)が、PORT_BH_RESETの場合はWarm Resetが行われる。

次に速度変更である(Photo05)。これも前回ちょっと触れた話であるが、何らかの理由があってUSB 3.0での接続が維持できなくなった場合、USB 2.0での接続を行う仕組みになっている。順序としては、

  • HostがUSB 3.0を切り離す
  • Hubがそれを検出し、USB 3.0を切り離す(USB 2.0の接続は維持する)
  • Deviceもこれを検出、USB 2.0で接続する
  • という順序になる。逆にUSB 2.0→USB 3.0の場合だが、
  • HostがUSB 3.0での接続を検出してUSB 3.0での接続を開始する
  • Hubがこれを検出し、全てのDownstream PortでUSB 3.0の接続を開始する。ただしUSB 2.0での接続は維持する
  • Host上のUSB 2.0ドライバが、USB 2.0のトポロジーに対してReset送出
  • DeviceがUSB 2.0のResetを検出、再びUSB 3.0での接続を開始する

という形になる。ちなみにこれはGlobal Speed Change、つまりHost以下の全Deviceの接続を切り替える場合の話で、ある特定Deviceのみの変更ではない事に注意されたい。(続く)

Photo05: これはあくまでUSB 3.0からみての構図。