blob: 4fedeeeb162ed9cfc9736ee0354924869aa65488 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
|
\ *****************************************************************************
\ * Copyright (c) 2012 IBM Corporation
\ * All rights reserved.
\ * This program and the accompanying materials
\ * are made available under the terms of the BSD License
\ * which accompanies this distribution, and is available at
\ * http://www.opensource.org/licenses/bsd-license.php
\ *
\ * Contributors:
\ * IBM Corporation - initial implementation
\ ****************************************************************************/
." Populating " pwd cr
FALSE CONSTANT virtio-scsi-debug
2 encode-int s" #address-cells" property
0 encode-int s" #size-cells" property
: decode-unit 2 hex64-decode-unit ;
: encode-unit 2 hex64-encode-unit ;
FALSE VALUE initialized?
virtio-setup-vd VALUE virtiodev
STRUCT \ virtio-scsi-config
/l FIELD vs-cfg>num-queues
/l FIELD vs-cfg>seg-max
/l FIELD vs-cfg>max-sectors
/l FIELD vs-cfg>cmd-per-lun
/l FIELD vs-cfg>event-info-size
/l FIELD vs-cfg>sense_size
/l FIELD vs-cfg>cdb-size
/w FIELD vs-cfg>max-channel
/w FIELD vs-cfg>max-target
/l FIELD vs-cfg>max-lun
CONSTANT vs-cfg-length
STRUCT \ virtio-scsi-req
8 FIELD vs-req>lun
8 FIELD vs-req>tag
/c FIELD vs-req>task-attr
/c FIELD vs-req>prio
/c FIELD vs-req>crn
20 FIELD vs-req>cdb
CONSTANT vs-req-length
STRUCT \ virtio-scsi-resp
/l FIELD vs-rsp>sense-len
/l FIELD vs-rsp>residual
/w FIELD vs-rsp>status-qualifier
/c FIELD vs-rsp>status
/c FIELD vs-rsp>response
60 FIELD vs-rsp>sense
CONSTANT vs-rsp-length
CREATE vs-req vs-req-length allot
CREATE vs-rsp vs-rsp-length allot
scsi-open
\ -----------------------------------------------------------
\ Perform SCSI commands
\ -----------------------------------------------------------
0 INSTANCE VALUE current-target
\ SCSI command. We do *NOT* implement the "standard" execute-command
\ because that doesn't have a way to return the sense buffer back, and
\ we do have auto-sense with some hosts. Instead we implement a made-up
\ do-scsi-command.
\
\ Note: stat is -1 for "hw error" (ie, error queuing the command or
\ getting the response).
\
\ A sense buffer is returned whenever the status is non-0 however
\ if sense-len is 0 then no sense data is actually present
\
: execute-scsi-command ( buf-addr buf-len dir cmd-addr cmd-len -- ... )
( ... [ sense-buf sense-len ] stat )
\ Cleanup virtio request and response
vs-req vs-req-length erase
vs-rsp vs-rsp-length erase
\ Populate the request
current-target vs-req vs-req>lun x!
vs-req vs-req>cdb swap move
\ Send it
vs-req vs-rsp virtiodev
virtio-scsi-send
0 <> IF
." VIRTIO-SCSI: Queuing failure !" cr
0 0 -1 EXIT
THEN
\ Check virtio response
vs-rsp vs-rsp>response c@ CASE
0 OF ENDOF \ Good
5 OF drop 0 0 8 EXIT ENDOF \ Busy
dup OF 0 0 -1 EXIT ENDOF \ Anything else -> HW error
ENDCASE
\ Other error status
vs-rsp vs-rsp>status c@ dup 0<> IF
vs-rsp vs-rsp>sense-len l@ dup 0= IF
\ This relies on auto-sense from qemu... if that isn't always the
\ case we should request sense here
." VIRTIO-SCSI: No sense data" cr
0 EXIT
THEN
vs-rsp vs-rsp>sense swap
virtio-scsi-debug IF
over scsi-get-sense-data
." VIRTIO-SCSI: Sense key [ " dup . ." ] " .sense-text
." ASC,ASCQ: " . . cr
THEN
rot
THEN
;
\ --------------------------------
\ Include the generic host helpers
\ --------------------------------
" scsi-host-helpers.fs" included
\ FIXME: Check max transfer coming from virtio config
: max-transfer ( -- n )
10000 \ Larger value seem to have problems with some CDROMs
;
\ -----------------------------------------------------------
\ SCSI scan at boot and child device support
\ -----------------------------------------------------------
\ We use SRP luns of the form 01000000 | (target << 16) | lun
\ in the top 32 bits of the 64-bit LUN
: (set-target)
to current-target
;
: dev-generate-srplun ( target lun-id -- srplun )
swap 0100 or 10 << or 20 <<
;
\ We obtain here a unit address on the stack, since our #address-cells
\ is 2, the 64-bit srplun is split in two cells that we need to join
\
\ Note: This diverges a bit from the original OF scsi spec as the two
\ cells are the 2 words of a 64-bit SRP LUN
: set-address ( srplun.lo srplun.hi -- )
lxjoin (set-target)
;
100 CONSTANT #target
: dev-max-target ( -- #target )
#target
;
" scsi-probe-helpers.fs" included
scsi-close \ no further scsi words required
0 VALUE queue-control-addr
0 VALUE queue-event-addr
0 VALUE queue-cmd-addr
: setup-virt-queues
\ add 3 queues 0-controlq, 1-eventq, 2-cmdq
\ fixme: do we need to find more than the above 3 queues if exists
virtiodev 0 virtio-get-qsize virtio-vring-size
alloc-mem to queue-control-addr
virtiodev 0 queue-control-addr virtio-set-qaddr
virtiodev 1 virtio-get-qsize virtio-vring-size
alloc-mem to queue-event-addr
virtiodev 1 queue-event-addr virtio-set-qaddr
virtiodev 2 virtio-get-qsize virtio-vring-size
alloc-mem to queue-cmd-addr
virtiodev 2 queue-cmd-addr virtio-set-qaddr
;
\ Set scsi alias if none is set yet
: setup-alias
s" scsi" find-alias 0= IF
s" scsi" get-node node>path set-alias
ELSE
drop
THEN
;
: shutdown ( -- )
initialized? IF
my-phandle node>path open-dev ?dup IF
virtiodev virtio-scsi-shutdown
close-dev
THEN
FALSE to initialized?
THEN
;
: virtio-scsi-init-and-scan ( -- )
\ Create instance for scanning:
0 0 get-node open-node ?dup 0= IF ." exiting " cr EXIT THEN
my-self >r
dup to my-self
\ Scan the VSCSI bus:
virtiodev virtio-scsi-init
0= IF
setup-virt-queues
scsi-find-disks
setup-alias
TRUE to initialized?
['] shutdown add-quiesce-xt
THEN
\ Close the temporary instance:
close-node
r> to my-self
;
: virtio-scsi-add-disk
" scsi-disk.fs" included
;
virtio-scsi-add-disk
virtio-scsi-init-and-scan
|