Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / SLOF / slof / fs / usb / dev-storage.fs
1 \ *****************************************************************************
2 \ * Copyright (c) 2013 IBM Corporation
3 \ * All rights reserved.
4 \ * This program and the accompanying materials
5 \ * are made available under the terms of the BSD License
6 \ * which accompanies this distribution, and is available at
7 \ * http://www.opensource.org/licenses/bsd-license.php
8 \ *
9 \ * Contributors:
10 \ *     IBM Corporation - initial implementation
11 \ ****************************************************************************/
12
13 \ ( usbdev -- )
14
15 new-device
16
17 VALUE usbdev
18
19 s" slofdev.fs" included
20
21 false VALUE usb-disk-debug?
22
23 usbdev slof-dev>port l@ dup set-unit encode-phys " reg" property
24 s" storage" device-name
25
26 s" dev-parent-calls.fs" included
27
28 2 encode-int s" #address-cells" property
29 0 encode-int s" #size-cells" property
30
31 : decode-unit 2 hex64-decode-unit ;
32 : encode-unit 2 hex64-encode-unit ;
33
34 0 CONSTANT USB_PIPE_OUT
35 1 CONSTANT USB_PIPE_IN
36
37 \ -----------------------------------------------------------
38 \ Specific properties
39 \ -----------------------------------------------------------
40
41 usbdev slof-dev>udev @ VALUE udev
42 usbdev slof-dev>port l@ VALUE port
43 usbdev slof-dev>hcitype l@ VALUE hcitype
44
45 0 INSTANCE VALUE lun
46 10000 VALUE dev-max-transfer
47 0     VALUE resp-buffer
48 0     VALUE resp-size
49 0f CONSTANT SCSI-COMMAND-OFFSET
50
51 \ -------------------------------------------------------
52 \ DMA-able buffers
53 \ -------------------------------------------------------
54
55 STRUCT
56    dev-max-transfer FIELD usb>data
57    40 FIELD usb>cmd
58    20 FIELD usb>csw
59 CONSTANT /dma-buf
60
61 0 VALUE dma-buf
62 0 VALUE dma-buf-phys
63 0 VALUE td-buf
64 0 VALUE td-buf-phys
65 1000 CONSTANT /td-buf
66
67 : (dma-buf-init)  ( -- )
68    /dma-buf dma-alloc TO dma-buf
69    dma-buf /dma-buf 0 dma-map-in TO dma-buf-phys
70    /td-buf dma-alloc TO td-buf
71    td-buf /td-buf 0 dma-map-in TO td-buf-phys
72 ;
73
74 : (dma-buf-free)  ( -- )
75    td-buf td-buf-phys /td-buf dma-map-out
76    td-buf /td-buf dma-free
77    0 TO td-buf
78    0 TO td-buf-phys
79    dma-buf dma-buf-phys /dma-buf dma-map-out
80    dma-buf /dma-buf dma-free
81    0 TO dma-buf
82    0 TO dma-buf-phys
83 ;
84
85
86 scsi-open
87
88 \ -----------------------------------------------------------
89 \ Perform SCSI commands
90 \ -----------------------------------------------------------
91
92 0 INSTANCE VALUE current-target
93
94 \ SCSI command. We do *NOT* implement the "standard" execute-command
95 \ because that doesn't have a way to return the sense buffer back, and
96 \ we do have auto-sense with some hosts. Instead we implement a made-up
97 \ do-scsi-command.
98 \
99 \ Note: stat is -1 for "hw error" (ie, error queuing the command or
100 \ getting the response).
101 \
102 \ A sense buffer is returned whenever the status is non-0 however
103 \ if sense-len is 0 then no sense data is actually present
104 \
105
106 : do-bulk-command ( resp-buffer resp-size -- TRUE | FALSE )
107     TO resp-size
108     TO resp-buffer
109     udev USB_PIPE_OUT td-buf td-buf-phys dma-buf-phys usb>cmd 1F
110     usb-transfer-bulk IF \ transfer CBW
111         resp-size IF
112             d# 125 us
113             udev USB_PIPE_IN td-buf td-buf-phys resp-buffer resp-size
114             usb-transfer-bulk 1 = not IF \ transfer data
115                 usb-disk-debug? IF ." Data phase failed " cr THEN
116                 \ FALSE EXIT
117                 \ in case of a stall/halted endpoint we clear the halt
118                 \ Fall through and try reading the CSW
119             THEN
120         THEN
121         d# 125 us
122         udev USB_PIPE_IN td-buf td-buf-phys dma-buf-phys usb>csw 0D
123         usb-transfer-bulk \ transfer CSW
124     ELSE
125         FALSE EXIT
126     THEN
127 ;
128
129 STRUCT \ cbw
130     /l FIELD cbw>sig
131     /l FIELD cbw>tag
132     /l FIELD cbw>len
133     /c FIELD cbw>flags
134     /c FIELD cbw>lun     \ 0:3 bits
135     /c FIELD cbw>cblen   \ 0:4 bits
136 CONSTANT cbw-length
137
138 STRUCT \ csw
139     /l FIELD csw>sig
140     /l FIELD csw>tag
141     /l FIELD csw>data-residue
142     /c FIELD csw>status
143 CONSTANT cbw-length
144
145 0 VALUE cbw-addr
146 0 VALUE csw-addr
147
148 : build-cbw ( tag xfer-len dir lun cmd-len addr -- )
149     TO cbw-addr               ( tag xfer-len dir lun cmd-len )
150     cbw-addr cbw-length erase ( tag xfer-len dir lun cmd-len )
151     cbw-addr cbw>cblen c!     ( tag xfer-len dir lun )
152     cbw-addr cbw>lun c!       ( tag xfer-len dir )
153     \ dir is true or false
154     \ bmCBWFlags
155     \           BIT 7 Direction
156     \               0 - OUT
157     \               1 - IN
158     IF 80 ELSE 0 THEN
159     cbw-addr cbw>flags c!     ( tag xfer-len )
160     cbw-addr cbw>len l!-le    ( tag )
161     cbw-addr cbw>tag l!-le    ( )
162     43425355 cbw-addr cbw>sig l!-le
163 ;
164
165 0 INSTANCE VALUE usb-buf-addr
166 0 INSTANCE VALUE usb-buf-len
167 0 INSTANCE VALUE usb-dir
168 0 INSTANCE VALUE usb-cmd-addr
169 0 INSTANCE VALUE usb-cmd-len
170 1 VALUE tag
171
172 : execute-scsi-command ( buf-addr buf-len dir cmd-addr cmd-len -- ... )
173                        ( ... [ sense-buf sense-len ] stat )
174     \ Cleanup virtio request and response
175     to usb-cmd-len to usb-cmd-addr to usb-dir to usb-buf-len to usb-buf-addr
176
177     dma-buf usb>cmd 40 0 fill
178     dma-buf usb>csw 20 0 fill
179
180     tag usb-buf-len usb-dir lun usb-cmd-len dma-buf usb>cmd
181     ( tag transfer-len dir lun cmd-len addr )
182     build-cbw
183     1 tag + to tag
184
185     usb-cmd-addr
186     dma-buf usb>cmd SCSI-COMMAND-OFFSET +
187     usb-cmd-len
188     move
189
190     \ Send it
191     dma-buf-phys usb>data usb-buf-len
192     do-bulk-command IF
193         dma-buf usb>data usb-buf-addr usb-buf-len move
194     ELSE
195         ." USB-DISK: Bulk commad failed!" cr
196         0 0 -1 EXIT
197     THEN
198
199     dma-buf usb>csw to csw-addr
200     csw-addr csw>sig l@ 55534253 <> IF
201         ." USB-DISK: CSW signature invalid " cr
202         0 0 -1 EXIT
203     THEN
204
205     csw-addr csw>status c@ CASE
206         0 OF ENDOF                      \ Good
207         1 OF
208             usb-disk-debug? IF
209                 ." USB-DISK: CSW Data residue: "
210                 csw-addr csw>data-residue l@-le . cr
211             THEN
212             0 0 8 EXIT ENDOF    \ Command failed, Retry
213         dup OF 0 0 -1 EXIT ENDOF        \ Anything else -> HW error
214     ENDCASE
215
216     \ Other error status
217     csw-addr csw>status c@ dup 0<> IF
218         usb-disk-debug? IF
219             over scsi-get-sense-data
220             ." USB-DISK: Sense key [ " dup . ." ] " .sense-text
221             ."  ASC,ASCQ: " . . cr
222         THEN
223        rot
224     THEN
225 ;
226
227 \ --------------------------------
228 \ Include the generic host helpers
229 \ --------------------------------
230
231 " scsi-host-helpers.fs" included
232
233 0 VALUE open-count
234
235 : usb-storage-init  (  -- TRUE )
236     td-buf 0= IF
237         usb-disk-debug? IF ." USB-DISK: Allocating buffer "  cr THEN
238         (dma-buf-init)
239         udev USB-MSC-INIT 0= IF
240             ." USB-DISK: Unable to initialize MSC " cr
241             FALSE
242         ELSE
243             TRUE
244         THEN
245     THEN
246 ;
247
248 : usb-storage-cleanup
249     td-buf 0<> IF
250         usb-disk-debug? IF ." USB-DISK: Freeing buffer " cr THEN
251         (dma-buf-free)
252         udev USB-MSC-EXIT 0= IF ." USB-DISK: Unable to exit MSC " cr THEN
253     THEN
254 ;
255
256 : open
257     usb-disk-debug? IF ." USB-DISK: Opening (count is " open-count . ." )" cr THEN
258
259     open-count 0= IF
260         usb-storage-init IF
261             1 to open-count true
262         ELSE ." USB-DISK initialization failed !" cr false THEN
263     ELSE
264         open-count 1 + to open-count
265         true
266     THEN
267 ;
268
269 : close
270     usb-disk-debug? IF ." USB-DISK: Closing (count is " open-count . ." )" cr THEN
271
272     open-count 0> IF
273         open-count 1 - dup to open-count
274         0= IF
275             usb-storage-cleanup
276         THEN
277     THEN
278 ;
279
280 \ -----------------------------------------------------------
281 \ SCSI scan at boot and child device support
282 \ -----------------------------------------------------------
283
284 \ We use SRP luns of the form 01000000 | (target << 8) | lun
285 \ in the top 32 bits of the 64-bit LUN
286 : (set-target)
287     dup 20 >> FFFF and to lun
288     dup 30 >> FF and to port
289     to current-target
290     usb-disk-debug? IF ." USB-DISK: udev " udev . ." lun:" lun . ." port:" port . cr THEN
291 ;
292
293 : dev-generate-srplun ( target lun-id -- srplun )
294     swap drop port 0100 or 10 << or 20 <<
295 ;
296
297 \ FIXME: Check max transfer coming from virtio config
298 : max-transfer ( -- n )
299     dev-max-transfer
300 ;
301
302 \ We obtain here a unit address on the stack, since our #address-cells
303 \ is 2, the 64-bit srplun is split in two cells that we need to join
304 \
305 \ Note: This diverges a bit from the original OF scsi spec as the two
306 \ cells are the 2 words of a 64-bit SRP LUN
307 : set-address ( srplun.lo srplun.hi -- )
308     lxjoin (set-target)
309     usb-disk-debug? IF ." USB-DISK: udev " udev . ." lun:" lun . ." port:" port . cr THEN
310 ;
311
312 1 CONSTANT #target
313 : dev-max-target ( -- #target )
314     #target
315 ;
316
317 " scsi-probe-helpers.fs" included
318
319 scsi-close        \ no further scsi words required
320
321 \ Set scsi alias if none is set yet
322 : setup-alias
323     s" scsi" find-alias 0= IF
324         s" scsi" get-node node>path set-alias
325     ELSE
326         drop
327     THEN
328 ;
329
330 : usb-storage-init-and-scan ( -- )
331    usb-disk-debug? IF ." Initializing usb-disk: udev " udev . cr THEN
332
333   \ Create instance for scanning:
334    0 0 get-node open-node ?dup 0= IF EXIT THEN
335    my-self >r
336    dup to my-self
337
338    hcitype
339    CASE
340       1 OF 4000 TO dev-max-transfer ENDOF \ OHCI
341       2 OF 10000 TO dev-max-transfer ENDOF \ EHCI
342       3 OF F000 TO dev-max-transfer ENDOF \ XHCI
343    ENDCASE
344    usb-storage-init
345    scsi-find-disks
346    setup-alias
347    usb-storage-cleanup
348    \ Close the temporary instance:
349    close-node
350    r> to my-self
351 ;
352
353 ."     USB Storage " cr
354 : usb-scsi-add-disk
355      " scsi-disk.fs" included
356 ;
357
358 usb-scsi-add-disk
359 usb-storage-init-and-scan
360
361 finish-device