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
10 \ * IBM Corporation - initial implementation
11 \ ****************************************************************************/
19 s" slofdev.fs" included
21 false VALUE usb-disk-debug?
23 usbdev slof-dev>port l@ dup set-unit encode-phys " reg" property
24 s" storage" device-name
26 s" dev-parent-calls.fs" included
28 2 encode-int s" #address-cells" property
29 0 encode-int s" #size-cells" property
31 : decode-unit 2 hex64-decode-unit ;
32 : encode-unit 2 hex64-encode-unit ;
34 0 CONSTANT USB_PIPE_OUT
35 1 CONSTANT USB_PIPE_IN
37 \ -----------------------------------------------------------
39 \ -----------------------------------------------------------
41 usbdev slof-dev>udev @ VALUE udev
42 usbdev slof-dev>port l@ VALUE port
43 usbdev slof-dev>hcitype l@ VALUE hcitype
46 10000 VALUE dev-max-transfer
49 0f CONSTANT SCSI-COMMAND-OFFSET
51 \ -------------------------------------------------------
53 \ -------------------------------------------------------
56 dev-max-transfer FIELD usb>data
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
74 : (dma-buf-free) ( -- )
75 td-buf td-buf-phys /td-buf dma-map-out
76 td-buf /td-buf dma-free
79 dma-buf dma-buf-phys /dma-buf dma-map-out
80 dma-buf /dma-buf dma-free
88 \ -----------------------------------------------------------
89 \ Perform SCSI commands
90 \ -----------------------------------------------------------
92 0 INSTANCE VALUE current-target
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
99 \ Note: stat is -1 for "hw error" (ie, error queuing the command or
100 \ getting the response).
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
106 : do-bulk-command ( resp-buffer resp-size -- TRUE | FALSE )
109 udev USB_PIPE_OUT td-buf td-buf-phys dma-buf-phys usb>cmd 1F
110 usb-transfer-bulk IF \ transfer CBW
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
117 \ in case of a stall/halted endpoint we clear the halt
118 \ Fall through and try reading the CSW
122 udev USB_PIPE_IN td-buf td-buf-phys dma-buf-phys usb>csw 0D
123 usb-transfer-bulk \ transfer CSW
134 /c FIELD cbw>lun \ 0:3 bits
135 /c FIELD cbw>cblen \ 0:4 bits
141 /l FIELD csw>data-residue
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
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
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
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
177 dma-buf usb>cmd 40 0 fill
178 dma-buf usb>csw 20 0 fill
180 tag usb-buf-len usb-dir lun usb-cmd-len dma-buf usb>cmd
181 ( tag transfer-len dir lun cmd-len addr )
186 dma-buf usb>cmd SCSI-COMMAND-OFFSET +
191 dma-buf-phys usb>data usb-buf-len
193 dma-buf usb>data usb-buf-addr usb-buf-len move
195 ." USB-DISK: Bulk commad failed!" cr
199 dma-buf usb>csw to csw-addr
200 csw-addr csw>sig l@ 55534253 <> IF
201 ." USB-DISK: CSW signature invalid " cr
205 csw-addr csw>status c@ CASE
209 ." USB-DISK: CSW Data residue: "
210 csw-addr csw>data-residue l@-le . cr
212 0 0 8 EXIT ENDOF \ Command failed, Retry
213 dup OF 0 0 -1 EXIT ENDOF \ Anything else -> HW error
217 csw-addr csw>status c@ dup 0<> IF
219 over scsi-get-sense-data
220 ." USB-DISK: Sense key [ " dup . ." ] " .sense-text
221 ." ASC,ASCQ: " . . cr
227 \ --------------------------------
228 \ Include the generic host helpers
229 \ --------------------------------
231 " scsi-host-helpers.fs" included
235 : usb-storage-init ( -- TRUE )
237 usb-disk-debug? IF ." USB-DISK: Allocating buffer " cr THEN
239 udev USB-MSC-INIT 0= IF
240 ." USB-DISK: Unable to initialize MSC " cr
248 : usb-storage-cleanup
250 usb-disk-debug? IF ." USB-DISK: Freeing buffer " cr THEN
252 udev USB-MSC-EXIT 0= IF ." USB-DISK: Unable to exit MSC " cr THEN
257 usb-disk-debug? IF ." USB-DISK: Opening (count is " open-count . ." )" cr THEN
262 ELSE ." USB-DISK initialization failed !" cr false THEN
264 open-count 1 + to open-count
270 usb-disk-debug? IF ." USB-DISK: Closing (count is " open-count . ." )" cr THEN
273 open-count 1 - dup to open-count
280 \ -----------------------------------------------------------
281 \ SCSI scan at boot and child device support
282 \ -----------------------------------------------------------
284 \ We use SRP luns of the form 01000000 | (target << 8) | lun
285 \ in the top 32 bits of the 64-bit LUN
287 dup 20 >> FFFF and to lun
288 dup 30 >> FF and to port
290 usb-disk-debug? IF ." USB-DISK: udev " udev . ." lun:" lun . ." port:" port . cr THEN
293 : dev-generate-srplun ( target lun-id -- srplun )
294 swap drop port 0100 or 10 << or 20 <<
297 \ FIXME: Check max transfer coming from virtio config
298 : max-transfer ( -- n )
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
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 -- )
309 usb-disk-debug? IF ." USB-DISK: udev " udev . ." lun:" lun . ." port:" port . cr THEN
313 : dev-max-target ( -- #target )
317 " scsi-probe-helpers.fs" included
319 scsi-close \ no further scsi words required
321 \ Set scsi alias if none is set yet
323 s" scsi" find-alias 0= IF
324 s" scsi" get-node node>path set-alias
330 : usb-storage-init-and-scan ( -- )
331 usb-disk-debug? IF ." Initializing usb-disk: udev " udev . cr THEN
333 \ Create instance for scanning:
334 0 0 get-node open-node ?dup 0= IF EXIT THEN
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
348 \ Close the temporary instance:
355 " scsi-disk.fs" included
359 usb-storage-init-and-scan