Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / SLOF / board-qemu / slof / vio-vscsi.fs
1 \ *****************************************************************************
2 \ * Copyright (c) 2011 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 ." Populating " pwd
14
15 false VALUE vscsi-debug?
16 0 VALUE vscsi-unit
17
18 \ -----------------------------------------------------------
19 \ Direct DMA conversion hack
20 \ -----------------------------------------------------------
21 : l2dma ( laddr - dma_addr)      
22 ;
23
24 \ -----------------------------------------------------------
25 \ CRQ related functions
26 \ -----------------------------------------------------------
27
28 0    VALUE     crq-real-base
29 0    VALUE     crq-base
30 0    VALUE     crq-dma
31 0    VALUE     crq-offset
32 1000 CONSTANT  CRQ-SIZE
33
34 CREATE crq 10 allot
35
36 : crq-alloc ( -- )
37     \ Allocate enough to align to a page
38     CRQ-SIZE fff + alloc-mem to crq-real-base
39     \ align the result
40     crq-real-base fff + fffff000 AND to crq-base 0 to crq-offset
41     crq-base l2dma to crq-dma
42 ;
43
44 : crq-free ( -- )
45     vscsi-unit hv-free-crq
46     crq-real-base CRQ-SIZE fff + free-mem 0 to crq-base 0 to crq-real-base
47 ;
48
49 : crq-init ( -- res )
50     \ Allocate CRQ. XXX deal with fail
51     crq-alloc
52
53     vscsi-debug? IF
54         ." VSCSI: allocated crq at " crq-base . cr
55     THEN
56
57     \ Clear buffer
58     crq-base CRQ-SIZE erase
59
60     \ Register with HV
61     vscsi-unit crq-dma CRQ-SIZE hv-reg-crq
62
63     \ Fail case
64     dup 0 <> IF
65         ." VSCSI: Error " . ."  registering CRQ !" cr
66         crq-free
67     THEN
68 ;
69
70 : crq-cleanup ( -- )
71     crq-base 0 = IF EXIT THEN
72
73     vscsi-debug? IF
74         ." VSCSI: freeing crq at " crq-base . cr
75     THEN
76     crq-free
77 ;
78
79 : crq-send ( msgaddr -- true | false )
80     vscsi-unit swap hv-send-crq 0 =
81 ;
82
83 : crq-poll ( -- true | false)
84     crq-offset crq-base + dup
85     vscsi-debug? IF
86         ." VSCSI: crq poll " dup .
87     THEN
88     c@
89     vscsi-debug? IF
90         ."  value=" dup . cr
91     THEN
92     80 and 0 <> IF
93         dup crq 10 move
94         0 swap c!
95         crq-offset 10 + dup CRQ-SIZE >= IF drop 0 THEN to crq-offset
96         true
97     ELSE drop false THEN
98 ;
99
100 : crq-wait ( -- true | false)
101     \ FIXME: Add timeout
102     0 BEGIN drop crq-poll dup not WHILE d# 1 ms REPEAT
103     dup not IF
104         ." VSCSI: Timeout waiting response !" cr EXIT
105     ELSE
106         vscsi-debug? IF
107             ." VSCSI: got crq: " crq dup l@ . ."  " 4 + dup l@ . ."  "
108             4 + dup l@ . ."  " 4 + l@ . cr
109         THEN
110     THEN
111 ;
112
113 \ -----------------------------------------------------------
114 \ CRQ encapsulated SRP definitions
115 \ -----------------------------------------------------------
116
117 01 CONSTANT VIOSRP_SRP_FORMAT
118 02 CONSTANT VIOSRP_MAD_FORMAT
119 03 CONSTANT VIOSRP_OS400_FORMAT
120 04 CONSTANT VIOSRP_AIX_FORMAT
121 06 CONSTANT VIOSRP_LINUX_FORMAT
122 07 CONSTANT VIOSRP_INLINE_FORMAT
123
124 struct
125    1 field >crq-valid
126    1 field >crq-format
127    1 field >crq-reserved
128    1 field >crq-status
129    2 field >crq-timeout
130    2 field >crq-iu-len
131    8 field >crq-iu-data-ptr
132 constant /crq
133
134 : srp-send-crq ( addr len -- )
135     80                crq >crq-valid c!
136     VIOSRP_SRP_FORMAT crq >crq-format c!
137     0                 crq >crq-reserved c!
138     0                 crq >crq-status c!
139     0                 crq >crq-timeout w!
140     ( len )           crq >crq-iu-len w!
141     ( addr ) l2dma    crq >crq-iu-data-ptr x!
142     crq crq-send
143     not IF
144         ." VSCSI: Error sending CRQ !" cr
145     THEN
146 ;
147
148 : srp-wait-crq ( -- [tag true] | false )
149     crq-wait not IF false EXIT THEN
150
151     crq >crq-format c@ VIOSRP_SRP_FORMAT <> IF
152         ." VSCSI: Unsupported SRP response: "
153         crq >crq-format c@ . cr
154         false EXIT
155     THEN
156
157     crq >crq-iu-data-ptr x@ true
158 ;
159
160 \ Add scsi functions to dictionary
161 scsi-open
162
163
164 \ -----------------------------------------------------------
165 \ SRP definitions
166 \ -----------------------------------------------------------
167
168 0 VALUE >srp_opcode
169
170 00 CONSTANT SRP_LOGIN_REQ
171 01 CONSTANT SRP_TSK_MGMT
172 02 CONSTANT SRP_CMD
173 03 CONSTANT SRP_I_LOGOUT
174 c0 CONSTANT SRP_LOGIN_RSP
175 c1 CONSTANT SRP_RSP
176 c2 CONSTANT SRP_LOGIN_REJ
177 80 CONSTANT SRP_T_LOGOUT
178 81 CONSTANT SRP_CRED_REQ
179 82 CONSTANT SRP_AER_REQ
180 41 CONSTANT SRP_CRED_RSP
181 42 CONSTANT SRP_AER_RSP
182
183 02 CONSTANT SRP_BUF_FORMAT_DIRECT
184 04 CONSTANT SRP_BUF_FORMAT_INDIRECT
185
186 struct
187    1 field >srp-login-opcode
188    3 +
189    8 field >srp-login-tag
190    4 field >srp-login-req-it-iu-len
191    4 +
192    2 field >srp-login-req-buf-fmt
193    1 field >srp-login-req-flags
194    5 +
195   10 field >srp-login-init-port-ids
196   10 field >srp-login-trgt-port-ids
197 constant /srp-login
198
199 struct
200    1 field >srp-lresp-opcode
201    3 +
202    4 field >srp-lresp-req-lim-delta
203    8 field >srp-lresp-tag
204    4 field >srp-lresp-max-it-iu-len
205    4 field >srp-lresp-max-ti-iu-len
206    2 field >srp-lresp-buf-fmt
207    1 field >srp-lresp-flags
208 constant /srp-login-resp
209
210 struct
211    1 field >srp-lrej-opcode
212    3 +
213    4 field >srp-lrej-reason
214    8 field >srp-lrej-tag
215    8 +
216    2 field >srp-lrej-buf-fmt
217 constant /srp-login-rej
218
219 00 CONSTANT SRP_NO_DATA_DESC
220 01 CONSTANT SRP_DATA_DESC_DIRECT
221 02 CONSTANT SRP_DATA_DESC_INDIRECT
222
223 struct
224     1 field >srp-cmd-opcode
225     1 field >srp-cmd-sol-not
226     3 +
227     1 field >srp-cmd-buf-fmt
228     1 field >srp-cmd-dout-desc-cnt
229     1 field >srp-cmd-din-desc-cnt
230     8 field >srp-cmd-tag
231     4 +
232     8 field >srp-cmd-lun
233     1 +
234     1 field >srp-cmd-task-attr
235     1 +
236     1 field >srp-cmd-add-cdb-len
237    10 field >srp-cmd-cdb
238     0 field >srp-cmd-cdb-add
239 constant /srp-cmd
240
241 struct
242     1 field >srp-rsp-opcode
243     1 field >srp-rsp-sol-not
244     2 +
245     4 field >srp-rsp-req-lim-delta
246     8 field >srp-rsp-tag
247     2 +
248     1 field >srp-rsp-flags
249     1 field >srp-rsp-status
250     4 field >srp-rsp-dout-res-cnt
251     4 field >srp-rsp-din-res-cnt
252     4 field >srp-rsp-sense-len
253     4 field >srp-rsp-resp-len
254     0 field >srp-rsp-data
255 constant /srp-rsp
256
257 \ Constants for srp-rsp-flags
258 01 CONSTANT SRP_RSP_FLAG_RSPVALID
259 02 CONSTANT SRP_RSP_FLAG_SNSVALID
260 04 CONSTANT SRP_RSP_FLAG_DOOVER
261 05 CONSTANT SRP_RSP_FLAG_DOUNDER
262 06 CONSTANT SRP_RSP_FLAG_DIOVER
263 07 CONSTANT SRP_RSP_FLAG_DIUNDER
264
265 \ Storage for up to 256 bytes SRP request */
266 CREATE srp 100 allot
267 0 VALUE srp-len
268
269 : srp-prep-cmd-nodata ( srplun -- )
270     srp /srp-cmd erase
271     SRP_CMD srp >srp-cmd-opcode c!
272     1 srp >srp-cmd-tag x!
273     srp >srp-cmd-lun x!         \ 8 bytes lun
274     /srp-cmd to srp-len   
275 ;
276
277 : srp-prep-cmd-io ( addr len srplun -- )
278     srp-prep-cmd-nodata         ( addr len )
279     swap l2dma                  ( len dmaaddr )
280     srp srp-len +               ( len dmaaddr descaddr )
281     dup >r x! r> 8 +            ( len descaddr+8 )
282     dup 0 swap l! 4 +           ( len descaddr+c )
283     l!    
284     srp-len 10 + to srp-len
285 ;
286
287 : srp-prep-cmd-read ( addr len srplun -- )
288     srp-prep-cmd-io
289     01 srp >srp-cmd-buf-fmt c!  \ in direct buffer
290     1 srp >srp-cmd-din-desc-cnt c!
291 ;
292
293 : srp-prep-cmd-write ( addr len srplun -- )
294     srp-prep-cmd-io
295     10 srp >srp-cmd-buf-fmt c!  \ out direct buffer
296     1 srp >srp-cmd-dout-desc-cnt c!
297 ;
298
299 : srp-send-cmd ( -- )
300     vscsi-debug? IF
301         ." VSCSI: Sending SCSI cmd " srp >srp-cmd-cdb c@ . cr
302     THEN
303     srp srp-len srp-send-crq
304 ;
305
306 : srp-rsp-find-sense ( -- addr len true | false )
307     srp >srp-rsp-flags c@ SRP_RSP_FLAG_SNSVALID and 0= IF
308         false EXIT
309     THEN
310     \ XXX FIXME: We assume the sense data is right at response
311     \            data. A different server might actually have both
312     \            some response data we need to skip *and* some sense
313     \            data.
314     srp >srp-rsp-data srp >srp-rsp-sense-len l@ true
315 ;
316
317 \ Wait for a response to the last sent SRP command
318 \ returns a SCSI status code or -1 (HW error).
319 \
320 : srp-wait-rsp ( -- stat )
321     srp-wait-crq not IF false EXIT THEN
322     dup 1 <> IF
323         ." VSCSI: Invalid CRQ response tag, want 1 got " . cr
324         -1 EXIT
325     THEN drop
326     
327     srp >srp-rsp-tag x@ dup 1 <> IF
328         ." VSCSI: Invalid SRP response tag, want 1 got " . cr
329         -1 EXIT
330     THEN drop
331     
332     srp >srp-rsp-status c@
333     vscsi-debug? IF
334         ." VSCSI: Got response status: "
335         dup .status-text cr
336     THEN
337 ;
338
339 \ -----------------------------------------------------------
340 \ Perform SCSI commands
341 \ -----------------------------------------------------------
342
343 8000000000000000 INSTANCE VALUE current-target
344
345 \ SCSI command. We do *NOT* implement the "standard" execute-command
346 \ because that doesn't have a way to return the sense buffer back, and
347 \ we do have auto-sense with some hosts. Instead we implement a made-up
348 \ do-scsi-command.
349 \
350 \ Note: stat is -1 for "hw error" (ie, error queuing the command or
351 \ getting the response).
352 \
353 \ A sense buffer is returned whenever the status is non-0 however
354 \ if sense-len is 0 then no sense data is actually present
355 \
356
357 : execute-scsi-command ( buf-addr buf-len dir cmd-addr cmd-len -- ... )
358                        ( ... [ sense-buf sense-len ] stat )
359     \ Stash command addr & len
360     >r >r                               ( buf-addr buf-len dir )
361     \ Command has no data ?
362     over 0= IF
363         3drop current-target srp-prep-cmd-nodata
364     ELSE
365         \ Command is a read ?
366         current-target swap IF srp-prep-cmd-read ELSE srp-prep-cmd-write THEN
367     THEN
368     \ Recover command and copy it to our srp buffer
369     r> r>
370     srp >srp-cmd-cdb swap move
371     srp-send-cmd
372     srp-wait-rsp
373
374     \ Check for HW error
375     dup -1 = IF
376         0 0 rot EXIT
377     THEN
378
379     \ Other error status
380     dup 0<> IF
381        srp-rsp-find-sense IF
382            vscsi-debug? IF
383                over scsi-get-sense-data
384                ." VSCSI: Sense key [ " dup . ." ] " .sense-text
385                ."  ASC,ASCQ: " . . cr
386            THEN
387        ELSE 0 0
388            \ This relies on auto-sense from qemu... if that isn't always the
389            \ case we should request sense here
390            ." VSCSI: No sense data" cr
391        THEN
392        rot
393     THEN
394 ;
395
396 \ --------------------------------
397 \ Include the generic host helpers
398 \ --------------------------------
399
400 " scsi-host-helpers.fs" included
401
402 TRUE VALUE first-time-init?
403 0 VALUE open-count
404
405 \ Cleanup behind us
406 : vscsi-cleanup
407     vscsi-debug? IF ." VSCSI: Cleaning up" cr THEN
408     crq-cleanup
409
410     \ Disable TCE bypass:
411     vscsi-unit 0 rtas-set-tce-bypass
412 ;
413
414 \ Initialize our vscsi instance
415 : vscsi-init ( -- true | false )
416     vscsi-debug? IF ." VSCSI: Initializing" cr THEN
417
418     my-unit to vscsi-unit
419
420     \ Enable TCE bypass special qemu feature
421     vscsi-unit 1 rtas-set-tce-bypass
422
423     \ Initialize CRQ
424     crq-init 0 <> IF false EXIT THEN
425
426     \ Send init command
427     " "(C0 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00)" drop
428     crq-send not IF
429         ." VSCSI: Error sending init command"
430         crq-cleanup false EXIT
431     THEN
432  
433     \ Wait reply
434     crq-wait not IF
435         crq-cleanup false EXIT
436     THEN
437
438     \ Check init reply
439     crq c@ c0 <> crq 1 + c@ 02 <> or IF
440         ." VSCSI: Initial handshake failed"
441         crq-cleanup false EXIT
442     THEN
443
444     \ We should now login etc.. but we really don't need to
445     \ with our qemu model
446
447     \ Ensure we cleanup after booting
448     first-time-init? IF
449         ['] vscsi-cleanup add-quiesce-xt
450         false to first-time-init?
451     THEN
452
453     true
454 ;
455
456 : open
457     vscsi-debug? IF ." VSCSI: Opening (count is " open-count . ." )" cr THEN
458
459     open-count 0= IF
460         vscsi-init IF
461             1 to open-count true
462         ELSE ." VSCSI initialization failed !" cr false THEN
463     ELSE
464         open-count 1 + to open-count
465         true
466     THEN
467 ;
468
469 : close
470     vscsi-debug? IF ." VSCSI: Closing (count is " open-count . ." )" cr THEN
471
472     open-count 0> IF
473         open-count 1 - dup to open-count
474         0= IF
475             vscsi-cleanup
476         THEN
477     THEN
478 ;
479
480 \ -----------------------------------------------------------
481 \ SCSI scan at boot and child device support
482 \ -----------------------------------------------------------
483
484 \ We use SRP luns of the form 8000 | (bus << 8) | (id << 5) | lun
485 \ in the top 16 bits of the 64-bit LUN
486 : (set-target)
487     to current-target
488 ;
489
490 : dev-generate-srplun ( target lun -- )
491     swap 8 << 8000 or or 30 <<
492 ;
493
494 \ We obtain here a unit address on the stack, since our #address-cells
495 \ is 2, the 64-bit srplun is split in two cells that we need to join
496 \
497 \ Note: This diverges a bit from the original OF scsi spec as the two
498 \ cells are the 2 words of a 64-bit SRP LUN
499 : set-address ( srplun.lo srplun.hi -- )
500     lxjoin (set-target)
501 ;
502
503 \ We set max-transfer to a fixed value for now to avoid problems
504 \ with some CD-ROM drives.
505 \ FIXME: Check max transfer coming from VSCSI
506 : max-transfer ( -- n )
507     10000 \ Larger value seem to have problems with some CDROMs
508 ;
509
510 8 CONSTANT #dev
511 : dev-max-target ( -- #max-target )
512     #dev
513 ;
514
515 " scsi-probe-helpers.fs" included
516
517 \ Remove scsi functions from word list
518 scsi-close
519
520 : setup-alias
521     " scsi" find-alias 0= IF
522         " scsi" get-node node>path set-alias
523     ELSE
524         drop
525     THEN 
526 ;
527
528 : vscsi-init-and-scan  ( -- )
529     \ Create instance for scanning:
530     0 0 get-node open-node ?dup 0= IF EXIT THEN
531     my-self >r
532     dup to my-self
533     \ Scan the VSCSI bus:
534     scsi-find-disks
535     setup-alias
536     \ Close the temporary instance:
537     close-node
538     r> to my-self
539 ;
540
541 : vscsi-add-disk
542     " scsi-disk.fs" included
543 ;
544
545 vscsi-add-disk
546 vscsi-init-and-scan