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
10 \ * IBM Corporation - initial implementation
11 \ ****************************************************************************/
15 false VALUE vscsi-debug?
18 \ -----------------------------------------------------------
19 \ Direct DMA conversion hack
20 \ -----------------------------------------------------------
21 : l2dma ( laddr - dma_addr)
24 \ -----------------------------------------------------------
25 \ CRQ related functions
26 \ -----------------------------------------------------------
32 1000 CONSTANT CRQ-SIZE
37 \ Allocate enough to align to a page
38 CRQ-SIZE fff + alloc-mem to crq-real-base
40 crq-real-base fff + fffff000 AND to crq-base 0 to crq-offset
41 crq-base l2dma to crq-dma
45 vscsi-unit hv-free-crq
46 crq-real-base CRQ-SIZE fff + free-mem 0 to crq-base 0 to crq-real-base
50 \ Allocate CRQ. XXX deal with fail
54 ." VSCSI: allocated crq at " crq-base . cr
58 crq-base CRQ-SIZE erase
61 vscsi-unit crq-dma CRQ-SIZE hv-reg-crq
65 ." VSCSI: Error " . ." registering CRQ !" cr
71 crq-base 0 = IF EXIT THEN
74 ." VSCSI: freeing crq at " crq-base . cr
79 : crq-send ( msgaddr -- true | false )
80 vscsi-unit swap hv-send-crq 0 =
83 : crq-poll ( -- true | false)
84 crq-offset crq-base + dup
86 ." VSCSI: crq poll " dup .
95 crq-offset 10 + dup CRQ-SIZE >= IF drop 0 THEN to crq-offset
100 : crq-wait ( -- true | false)
102 0 BEGIN drop crq-poll dup not WHILE d# 1 ms REPEAT
104 ." VSCSI: Timeout waiting response !" cr EXIT
107 ." VSCSI: got crq: " crq dup l@ . ." " 4 + dup l@ . ." "
108 4 + dup l@ . ." " 4 + l@ . cr
113 \ -----------------------------------------------------------
114 \ CRQ encapsulated SRP definitions
115 \ -----------------------------------------------------------
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
127 1 field >crq-reserved
131 8 field >crq-iu-data-ptr
134 : srp-send-crq ( addr len -- )
136 VIOSRP_SRP_FORMAT crq >crq-format c!
137 0 crq >crq-reserved c!
139 0 crq >crq-timeout w!
140 ( len ) crq >crq-iu-len w!
141 ( addr ) l2dma crq >crq-iu-data-ptr x!
144 ." VSCSI: Error sending CRQ !" cr
148 : srp-wait-crq ( -- [tag true] | false )
149 crq-wait not IF false EXIT THEN
151 crq >crq-format c@ VIOSRP_SRP_FORMAT <> IF
152 ." VSCSI: Unsupported SRP response: "
153 crq >crq-format c@ . cr
157 crq >crq-iu-data-ptr x@ true
160 \ Add scsi functions to dictionary
164 \ -----------------------------------------------------------
166 \ -----------------------------------------------------------
170 00 CONSTANT SRP_LOGIN_REQ
171 01 CONSTANT SRP_TSK_MGMT
173 03 CONSTANT SRP_I_LOGOUT
174 c0 CONSTANT SRP_LOGIN_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
183 02 CONSTANT SRP_BUF_FORMAT_DIRECT
184 04 CONSTANT SRP_BUF_FORMAT_INDIRECT
187 1 field >srp-login-opcode
189 8 field >srp-login-tag
190 4 field >srp-login-req-it-iu-len
192 2 field >srp-login-req-buf-fmt
193 1 field >srp-login-req-flags
195 10 field >srp-login-init-port-ids
196 10 field >srp-login-trgt-port-ids
200 1 field >srp-lresp-opcode
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
211 1 field >srp-lrej-opcode
213 4 field >srp-lrej-reason
214 8 field >srp-lrej-tag
216 2 field >srp-lrej-buf-fmt
217 constant /srp-login-rej
219 00 CONSTANT SRP_NO_DATA_DESC
220 01 CONSTANT SRP_DATA_DESC_DIRECT
221 02 CONSTANT SRP_DATA_DESC_INDIRECT
224 1 field >srp-cmd-opcode
225 1 field >srp-cmd-sol-not
227 1 field >srp-cmd-buf-fmt
228 1 field >srp-cmd-dout-desc-cnt
229 1 field >srp-cmd-din-desc-cnt
234 1 field >srp-cmd-task-attr
236 1 field >srp-cmd-add-cdb-len
237 10 field >srp-cmd-cdb
238 0 field >srp-cmd-cdb-add
242 1 field >srp-rsp-opcode
243 1 field >srp-rsp-sol-not
245 4 field >srp-rsp-req-lim-delta
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
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
265 \ Storage for up to 256 bytes SRP request */
269 : srp-prep-cmd-nodata ( srplun -- )
271 SRP_CMD srp >srp-cmd-opcode c!
272 1 srp >srp-cmd-tag x!
273 srp >srp-cmd-lun x! \ 8 bytes lun
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 )
284 srp-len 10 + to srp-len
287 : srp-prep-cmd-read ( addr len srplun -- )
289 01 srp >srp-cmd-buf-fmt c! \ in direct buffer
290 1 srp >srp-cmd-din-desc-cnt c!
293 : srp-prep-cmd-write ( addr len srplun -- )
295 10 srp >srp-cmd-buf-fmt c! \ out direct buffer
296 1 srp >srp-cmd-dout-desc-cnt c!
299 : srp-send-cmd ( -- )
301 ." VSCSI: Sending SCSI cmd " srp >srp-cmd-cdb c@ . cr
303 srp srp-len srp-send-crq
306 : srp-rsp-find-sense ( -- addr len true | false )
307 srp >srp-rsp-flags c@ SRP_RSP_FLAG_SNSVALID and 0= IF
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
314 srp >srp-rsp-data srp >srp-rsp-sense-len l@ true
317 \ Wait for a response to the last sent SRP command
318 \ returns a SCSI status code or -1 (HW error).
320 : srp-wait-rsp ( -- stat )
321 srp-wait-crq not IF false EXIT THEN
323 ." VSCSI: Invalid CRQ response tag, want 1 got " . cr
327 srp >srp-rsp-tag x@ dup 1 <> IF
328 ." VSCSI: Invalid SRP response tag, want 1 got " . cr
332 srp >srp-rsp-status c@
334 ." VSCSI: Got response status: "
339 \ -----------------------------------------------------------
340 \ Perform SCSI commands
341 \ -----------------------------------------------------------
343 8000000000000000 INSTANCE VALUE current-target
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
350 \ Note: stat is -1 for "hw error" (ie, error queuing the command or
351 \ getting the response).
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
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 ?
363 3drop current-target srp-prep-cmd-nodata
365 \ Command is a read ?
366 current-target swap IF srp-prep-cmd-read ELSE srp-prep-cmd-write THEN
368 \ Recover command and copy it to our srp buffer
370 srp >srp-cmd-cdb swap move
381 srp-rsp-find-sense IF
383 over scsi-get-sense-data
384 ." VSCSI: Sense key [ " dup . ." ] " .sense-text
385 ." ASC,ASCQ: " . . cr
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
396 \ --------------------------------
397 \ Include the generic host helpers
398 \ --------------------------------
400 " scsi-host-helpers.fs" included
402 TRUE VALUE first-time-init?
407 vscsi-debug? IF ." VSCSI: Cleaning up" cr THEN
410 \ Disable TCE bypass:
411 vscsi-unit 0 rtas-set-tce-bypass
414 \ Initialize our vscsi instance
415 : vscsi-init ( -- true | false )
416 vscsi-debug? IF ." VSCSI: Initializing" cr THEN
418 my-unit to vscsi-unit
420 \ Enable TCE bypass special qemu feature
421 vscsi-unit 1 rtas-set-tce-bypass
424 crq-init 0 <> IF false EXIT THEN
427 " "(C0 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00)" drop
429 ." VSCSI: Error sending init command"
430 crq-cleanup false EXIT
435 crq-cleanup false EXIT
439 crq c@ c0 <> crq 1 + c@ 02 <> or IF
440 ." VSCSI: Initial handshake failed"
441 crq-cleanup false EXIT
444 \ We should now login etc.. but we really don't need to
445 \ with our qemu model
447 \ Ensure we cleanup after booting
449 ['] vscsi-cleanup add-quiesce-xt
450 false to first-time-init?
457 vscsi-debug? IF ." VSCSI: Opening (count is " open-count . ." )" cr THEN
462 ELSE ." VSCSI initialization failed !" cr false THEN
464 open-count 1 + to open-count
470 vscsi-debug? IF ." VSCSI: Closing (count is " open-count . ." )" cr THEN
473 open-count 1 - dup to open-count
480 \ -----------------------------------------------------------
481 \ SCSI scan at boot and child device support
482 \ -----------------------------------------------------------
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
490 : dev-generate-srplun ( target lun -- )
491 swap 8 << 8000 or or 30 <<
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
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 -- )
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
511 : dev-max-target ( -- #max-target )
515 " scsi-probe-helpers.fs" included
517 \ Remove scsi functions from word list
521 " scsi" find-alias 0= IF
522 " scsi" get-node node>path set-alias
528 : vscsi-init-and-scan ( -- )
529 \ Create instance for scanning:
530 0 0 get-node open-node ?dup 0= IF EXIT THEN
533 \ Scan the VSCSI bus:
536 \ Close the temporary instance:
542 " scsi-disk.fs" included