ではデータ転送だとどうか? ということで、まずはData-in(Device→Host)の転送から見てみたい。先ずPhoto01が、USB 2.0 DeviceからData-In transferを行った場合のシーケンスである。

Photo01: USB Attached SCSI Protocol(UASP) Revision 1.0のFigure 3から抜粋

UAS Driverはコマンドを受け取ると、ITr(Stat)とOTr(CIU)を発行する。EHCI Controllerはこれを分解し、IN(Stat)をまず発行、次いでNAK(Stat)を受け取った後でOUT(Cmd)とDATA(CUI)を発行、DeviceからまずCmdのACKを受け取った後に、今度はDATAでRRIU(Read Ready Information Unit)を受け取る。このあたりまでは前回のNon-Data Transferと同じで、SIUがRRIUに変わったのが唯一の相違点である。

実際の転送はというと、この後始まることになる。再びITr(Stat)と、今度はITr(Data-In)をUAS Driverは発行する。これを受けてDeviceはIN(Data-in)の返答という形でDATA(Data-in)を順次送り出し、EHCI ControllerはACK(Data-in)を返す。以後データが続く限り、IN(Data-in)とACK(Data-in)のハンドシェイクが続き、必要なデータを送り終わったあとでもう一度EHCI ControllerがIN(Stat)を送ると、今度はSIUが返される形だ。このSIUの結果を待って、ITc(Stat, SIU)でUAS Driverに制御を戻し、これを受けてUAS Driverがまとめて結果を返すという仕組みである。ポイントになるのは、一度RRIUを受け取っておかないとData-inが発行できないことで、これだけのために最初のトランザクションが行われているわけだ。

これはUSB 3.0ではどうなるか? というのがPhoto02である。まずUAS DriverはITr(Stat)とITr(Data-in)、OTr(CIU)をまとめて発行する。これをxHCI Controllerは順に発行する形になるが、まず発行されるIN ACK(Data-in,Prime)はData-in pipeをPrime pipe stateに遷移させることになり、これによりDeviceにデータ受信の用意をさせる。次いで発行されるIN ACK(Stat)はDeviceに対し、HostがSIUを受信可能であることを通知するものとなる。これらに対するレスポンスのNRDYを受け取った後、xHCI ControllerはDP(Cmd, CIU)を発行することで、実際にDeviceに転送を促す。

Photo02: USB Attached SCSI Protocol(UASP) Revision 1.0のFigure 7から抜粋

DeviceはDPに対するACKをまず返した後に、自身で送り出すべきデータの準備をし、まずERDY(Data-in)を通知し、xHCI Controllerにデータ送信準備完了を通知する。これを受け、以後xHCI ControllerとDeviceの間でDP(Data-in)とIN ACK(Data-in)のハンドシェイクが行われ、データが順次転送されることになる。Deviceがデータを送り出し終わると、最後にはERDY(Stat)が返されるので、これを受けてxHCI ControllerがIN ACK(Stat)を送ると、SIUがDPで返される。このSIUはITc(Stat,SIU)としてUAS Driverに送り返され、UAS Driverは先に(ITc(Data-in)の形で)受け取ったかデータとまとめて、上位に返答を返す形になる。

一見してハンドシェイクが半分近くになっていることがここでもお判りいただけよう。ポイントは、ハンドシェイクを2つに分ける必要がなくなっていることで、これだけでもオーバーヘッドの削減となる。また細かいところでは、USB 2.0の場合は実際に転送が始まった後、これを終了させるのはEHCI Controller側の作業となる。たとえば転送が10回に分けて行われる場合、EHCI ControllerはIN(Data-in)を発行した後は、Deviceからの10回のDATA(Data-in)にあわせて10回ACK(Data-in)を送り返すわけだが、その後ACK(Data-in)を送り出さねばならない。つまり10回分の転送が行われる事を理解し、数を数えている必要がある。対してUSB 3.0の場合、Deviceからの転送が終わると、そのタイミングでERDY(Stat)が返ってくるので、必ずしも転送回数をxHCI Controllerが数えている必要は無い事になる。このあたりもちょっとスマートになった部分だと思う。

ちなみに、実際にどの程度これでオーバーヘッドが減るか? というのは、実はDeviceの種類に結構依存しそうだ。USB 2.0の場合、最初にOUT(Cmd)とかDATA(Cmd,CIU)を受け取った段階で、Device側のコントローラはI/O要求を発行できる。ここでたとえばDeviceが5400rpmのHDDだったりすると、シークやら回転待ちやらが結構入るので、I/O要求を発行してから実際にデータを読み取るまでに時間が掛かり、なので、実質読み取りが終わるまでに最初のハンドシェイクが完了していて、すぐ次のデータ転送ハンドシェイクが始められることになる。つまりプロトコル上はオーバーヘッドが大きくても、実際にはオーバーヘッドが無い(というか、HDDアクセスがボトルネックになってプロトコルオーバーヘッドが無視できる)状況になっている可能性がある。こうした場合、USB 3.0でも殆ど性能は変わらないことになるだろう。ところがHDDの代わりにSSDを使っていると、今度はシーク時間などものすごく小さいから、明確にUSB 2.0と3.0で差がでることが予想される。

(続く)