1\ *****************************************************************************
2\ * Copyright (c) 2004, 2008 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\ ************************************************
14\ create a new scsi word-list named 'scsi-words'
15\ ************************************************
16vocabulary scsi-words                  \ create new word list named 'scsi-words'
17also scsi-words  definitions           \ place next definitions into new list
18
19\ for some commands specific parameters are used, which normally
20\ need not to be altered. These values are preset at include time
21\ or explicit by a call of 'scsi-supp-init'
22false  value   scsi-param-debug        \ common debugging flag
23d# 0   value   scsi-param-size         \ length of CDB processed last
24h# 0   value   scsi-param-control      \ control word for CDBs as defined in SAM-4
25d# 0   value   scsi-param-errors       \ counter for detected errors
26
27\ utility to increment error counter
28: scsi-inc-errors
29   scsi-param-errors 1 + to scsi-param-errors
30;
31
32\ ***************************************************************************
33\ SCSI-Command: TEST UNIT READY
34\         Type: Primary Command (SPC-3 clause 6.33)
35\ ***************************************************************************
36\ Forth Word:   scsi-build-test-unit-ready    ( cdb -- )
37\ ***************************************************************************
38\ checks if a device is ready to receive commands
39\ ***************************************************************************
40\ command code:
4100 CONSTANT scsi-cmd-test-unit-ready
42\ CDB structure:
43STRUCT
44	/c	FIELD test-unit-ready>operation-code     \ 00h
45	4	FIELD test-unit-ready>reserved           \ unused
46	/c	FIELD test-unit-ready>control            \ control byte as specified in SAM-4
47CONSTANT scsi-length-test-unit-ready
48
49\ cdb build:
50\ all fields are zeroed
51: scsi-build-test-unit-ready  ( cdb -- )
52   dup scsi-length-test-unit-ready erase  ( cdb )
53   scsi-param-control swap test-unit-ready>control c!  ( )
54   scsi-length-test-unit-ready to scsi-param-size   \ update CDB length
55;
56
57\ ***************************************************************************
58\ SCSI-Command: REPORT LUNS
59\         Type: Primary Command
60\ ***************************************************************************
61\ Forth Word:   scsi-build-report-luns    ( cdb -- )
62\ ***************************************************************************
63\ report all LUNs supported by a device
64\ ***************************************************************************
65\ command code:
66a0 CONSTANT scsi-cmd-report-luns
67\ CDB structure:
68STRUCT
69	/c	FIELD report-luns>operation-code     \ a0h
70	1	FIELD report-luns>reserved           \ unused
71        /c      FIELD report-luns>select-report      \ report select byte
72        3       FIELD report-luns>reserved2          \ unused
73        /l      FIELD report-luns>alloc-length       \ report length
74	1	FIELD report-luns>reserved3          \ unused
75	/c	FIELD report-luns>control            \ control byte
76CONSTANT scsi-length-report-luns
77
78\ cdb build:
79\ all fields are zeroed
80: scsi-build-report-luns ( alloc-len cdb -- )
81   dup scsi-length-report-luns erase              \ 12 bytes CDB
82	scsi-cmd-report-luns over	          ( alloc-len cdb cmd cdb )
83	report-luns>operation-code c!	          ( alloc-len cdb )
84   scsi-param-control over report-luns>control c! ( alloc-len cdb )
85	report-luns>alloc-length l!	  \ size of Data-In Buffer
86   scsi-length-report-luns to scsi-param-size     \ update CDB length
87;
88
89\ ***************************************************************************
90\ SCSI-Command: REQUEST SENSE
91\         Type: Primary Command (SPC-3 clause 6.27)
92\ ***************************************************************************
93\ Forth Word:   scsi-build-request-sense    ( cdb -- )
94\ ***************************************************************************
95\ for return data a buffer of at least 252 bytes must be present!
96\ see spec: SPC-3 (r23) / clauses 4.5 and 6.27
97\ ***************************************************************************
98\ command code:
9903 CONSTANT scsi-cmd-request-sense
100\ CDB structure:
101STRUCT
102	/c	FIELD request-sense>operation-code     \ 03h
103	3	FIELD request-sense>reserved           \ unused
104	/c	FIELD request-sense>allocation-length  \ buffer-length for data response
105	/c	FIELD request-sense>control            \ control byte as specified in SAM-4
106CONSTANT scsi-length-request-sense
107
108\ cdb build:
109: scsi-build-request-sense    ( alloc-len cdb -- )
110   >r                         ( alloc-len )  ( R: -- cdb )
111   r@ scsi-length-request-sense erase  ( alloc-len )
112   scsi-cmd-request-sense r@           ( alloc-len cmd cdb )
113   request-sense>operation-code c!     ( alloc-len )
114   dup d# 252 >                        \ buffer length too big ?
115   IF
116      scsi-inc-errors
117      drop d# 252                      \ replace with 252
118   ELSE
119      dup d# 18 <                      \ allocated buffer too small ?
120      IF
121         scsi-inc-errors
122         drop 0                        \ reject return data
123      THEN
124   THEN                                      ( alloclen )
125   r@ request-sense>allocation-length c!     (  )
126   scsi-param-control r> request-sense>control c!  ( alloc-len cdb )  ( R: cdb -- )
127   scsi-length-request-sense to scsi-param-size  \ update CDB length
128;
129
130\ ----------------------------------------
131\ SCSI-Response: SENSE_DATA
132\ ----------------------------------------
13370 CONSTANT scsi-response(request-sense-0)
13471 CONSTANT scsi-response(request-sense-1)
135
136STRUCT
137   /c FIELD sense-data>response-code   \ 70h (current errors) or 71h (deferred errors)
138   /c FIELD sense-data>obsolete
139   /c FIELD sense-data>sense-key       \ D3..D0 = sense key, D7 = EndOfMedium
140   /l FIELD sense-data>info
141   /c FIELD sense-data>alloc-length    \ <= 244 (for max size)
142   /l FIELD sense-data>command-info
143   /c FIELD sense-data>asc             \ additional sense key
144   /c FIELD sense-data>ascq            \ additional sense key qualifier
145   /c FIELD sense-data>unit-code
146   3  FIELD sense-data>key-specific
147   /c FIELD sense-data>add-sense-bytes \ start of appended extra bytes
148CONSTANT scsi-length-sense-data
149
150\ ----------------------------------------
151\ get from SCSI response block:
152\  - Additional Sense Code Qualifier
153\  - Additional Sense Code
154\  - sense-key
155\ ----------------------------------------
156\ Forth Word:   scsi-get-sense-data  ( addr -- ascq asc sense-key )
157\ ----------------------------------------
158: scsi-get-sense-data                  ( addr -- ascq asc sense-key )
159   >r                                  ( R: -- addr )
160   r@ sense-data>response-code c@ 7f and 72 >= IF
161     r@ 3 + c@                           ( ascq )
162     r@ 2 + c@                           ( ascq asc )
163     r> 1 + c@ 0f and                    ( ascq asc sense-key )
164   ELSE
165     r@ sense-data>ASCQ c@               ( ascq )
166     r@ sense-data>ASC c@                ( ascq asc )
167     r> sense-data>sense-key c@ 0f and   ( ascq asc sense-key ) ( R: addr -- )
168   THEN
169;
170
171\ --------------------------------------------------------------------------
172\ Forth Word:   scsi-get-sense-data?  ( addr -- false | ascq asc sense-key true )
173\ --------------------------------------------------------------------------
174: scsi-get-sense-data?                 ( addr -- false | ascq asc sense-key true )
175   dup
176   sense-data>response-code c@
177   7e AND dup 70 = swap 72 = or         \ Response code (some devices have MSB set)
178   IF
179      scsi-get-sense-data TRUE
180   ELSE
181      drop FALSE        \ drop addr
182   THEN
183
184;
185
186\ --------------------------------------------------------------------------
187\ Forth Word:   scsi-get-sense-ID?  ( addr -- false | sense-ID true )
188\ same as scsi-get-sense-data? but returns
189\ a single word composed of: sense-key<<16 | asc<<8 | ascq
190\ --------------------------------------------------------------------------
191: scsi-get-sense-ID?                 ( addr -- false | ascq asc sense-key true )
192   dup
193   sense-data>response-code c@
194   7e AND 70 =          \ Response code (some devices have MSB set)
195   IF
196      scsi-get-sense-data        ( ascq asc sense-key )
197      10 lshift                  ( ascq asc sense-key16 )
198      swap 8 lshift or           ( ascq sense-key+asc )
199      swap or                    \ 24-bit sense-ID ( sense-key+asc+ascq )
200      TRUE
201   ELSE
202      drop FALSE        \ drop addr
203   THEN
204;
205
206\ ***************************************************************************
207\ SCSI-Command: INQUIRY
208\         Type: Primary Command (SPC-3 clause 6.4)
209\ ***************************************************************************
210\ Forth Word:   scsi-build-inquiry    ( alloc-len cdb -- )
211\ ***************************************************************************
212\ command code:
21312 CONSTANT scsi-cmd-inquiry
214
215\ CDB structure
216STRUCT
217	/c	FIELD inquiry>operation-code     \ 0x12
218	/c	FIELD inquiry>reserved           \ + EVPD-Bit (vital product data)
219	/c	FIELD inquiry>page-code          \ page code for vital product data (if used)
220	/w	FIELD inquiry>allocation-length  \ length of Data-In-Buffer
221	/c	FIELD inquiry>control            \ control byte as specified in SAM-4
222CONSTANT scsi-length-inquiry
223
224\ Setup command INQUIRY
225: scsi-build-inquiry                   ( alloc-len cdb -- )
226   dup scsi-length-inquiry erase       \ 6 bytes CDB
227	scsi-cmd-inquiry over				   ( alloc-len cdb cmd cdb )
228	inquiry>operation-code c!	         ( alloc-len cdb )
229   scsi-param-control over inquiry>control c! ( alloc-len cdb )
230	inquiry>allocation-length w!	      \ size of Data-In Buffer
231   scsi-length-inquiry to scsi-param-size    \ update CDB length
232;
233
234\ ----------------------------------------
235\ block structure of inquiry return data:
236\ ----------------------------------------
237STRUCT
238	/c	   FIELD inquiry-data>peripheral       \ qualifier and device type
239	/c	   FIELD inquiry-data>reserved1
240	/c	   FIELD inquiry-data>version          \ supported SCSI version (1,2,3)
241	/c	   FIELD inquiry-data>data-format
242	/c	   FIELD inquiry-data>add-length       \ total block length - 4
243	/c	   FIELD inquiry-data>flags1
244	/c	   FIELD inquiry-data>flags2
245	/c	   FIELD inquiry-data>flags3
246	d# 8	FIELD inquiry-data>vendor-ident     \ vendor string
247	d# 16	FIELD inquiry-data>product-ident    \ device string
248	/l 	FIELD inquiry-data>product-revision \ revision string
249	d# 20	FIELD inquiry-data>vendor-specific  \ optional params
250\ can be increased by vendor specific fields
251CONSTANT scsi-length-inquiry-data
252
253\ ***************************************************************************
254\ SCSI-Command: READ CAPACITY (10)
255\         Type: Block Command (SBC-3 clause 5.12)
256\ ***************************************************************************
257\ Forth Word:   scsi-build-read-capacity-10    ( cdb -- )
258\ ***************************************************************************
25925 CONSTANT scsi-cmd-read-capacity-10  \ command code
260
261STRUCT                                 \ SCSI 10-byte CDB structure
262	/c	FIELD read-cap-10>operation-code
263	/c	FIELD read-cap-10>reserved1
264	/l	FIELD read-cap-10>lba
265	/w	FIELD read-cap-10>reserved2
266	/c	FIELD read-cap-10>reserved3
267	/c	FIELD read-cap-10>control
268CONSTANT scsi-length-read-cap-10
269
270\ Setup READ CAPACITY (10) command
271: scsi-build-read-cap-10                     ( cdb -- )
272   dup scsi-length-read-cap-10 erase         ( cdb )
273	scsi-cmd-read-capacity-10 over            ( cdb cmd cdb )
274	read-cap-10>operation-code c!             ( cdb )
275   scsi-param-control swap read-cap-10>control c! ( )
276   scsi-length-read-cap-10 to scsi-param-size    \ update CDB length
277;
278
279\ ----------------------------------------
280\ get from SCSI response block:
281\  - Additional Sense Code Qualifier
282\  - Additional Sense Code
283\  - sense-key
284\ ----------------------------------------
285\ Forth Word:   scsi-get-capacity-10  ( addr -- block-size #blocks )
286\ ----------------------------------------
287\ Block structure
288STRUCT
289	/l	FIELD read-cap-10-data>max-lba
290	/l	FIELD read-cap-10-data>block-size
291CONSTANT scsi-length-read-cap-10-data
292
293\ get data-block
294: scsi-get-capacity-10                 ( addr -- block-size #blocks )
295   >r                                  ( addr -- ) ( R: -- addr )
296   r@ read-cap-10-data>block-size l@   ( block-size )
297   r> read-cap-10-data>max-lba l@      ( block-size #blocks ) ( R: addr -- )
298;
299
300\ ***************************************************************************
301\ SCSI-Command: READ CAPACITY (16)
302\         Type: Block Command (SBC-3 clause 5.13)
303\ ***************************************************************************
304\ Forth Word:   scsi-build-read-capacity-16    ( cdb -- )
305\ ***************************************************************************
3069e CONSTANT scsi-cmd-read-capacity-16        \ command code
307
308STRUCT                                       \ SCSI 16-byte CDB structure
309	/c	FIELD read-cap-16>operation-code
310	/c	FIELD read-cap-16>service-action
311	/l	FIELD read-cap-16>lba-high
312	/l	FIELD read-cap-16>lba-low
313	/l	FIELD read-cap-16>allocation-length    \ should be 32
314	/c	FIELD read-cap-16>reserved
315	/c	FIELD read-cap-16>control
316CONSTANT scsi-length-read-cap-16
317
318\ Setup READ CAPACITY (16) command
319: scsi-build-read-cap-16  ( cdb -- )
320   >r r@                                     ( R: -- cdb )
321   scsi-length-read-cap-16 erase             (  )
322	scsi-cmd-read-capacity-16                 ( code )
323	r@ read-cap-16>operation-code c!          (  )
324   10 r@ read-cap-16>service-action c!
325   d# 32                                     \ response size 32 bytes
326   r@ read-cap-16>allocation-length l!       (  )
327   scsi-param-control r> read-cap-16>control c! ( R: cdb -- )
328   scsi-length-read-cap-16 to scsi-param-size \ update CDB length
329;
330
331\ ----------------------------------------
332\ get from SCSI response block:
333\  - Block Size (in Bytes)
334\  - Number of Blocks
335\ ----------------------------------------
336\ Forth Word:   scsi-get-capacity-16  ( addr -- block-size #blocks )
337\ ----------------------------------------
338\ Block structure for return data
339STRUCT
340	/l	FIELD read-cap-16-data>max-lba-high    \ upper quadlet of Max-LBA
341	/l	FIELD read-cap-16-data>max-lba-low     \ lower quadlet of Max-LBA
342	/l	FIELD read-cap-16-data>block-size      \ logical block length in bytes
343   /c	FIELD read-cap-16-data>protect         \ type of protection (4 bits)
344   /c	FIELD read-cap-16-data>exponent        \ logical blocks per physical blocks
345   /w	FIELD read-cap-16-data>lowest-aligned  \ first LBA of a phsy. block
346   10 FIELD read-cap-16-data>reserved        \ 16 reserved bytes
347CONSTANT scsi-length-read-cap-16-data        \ results in 32
348
349\ get data-block
350: scsi-get-capacity-16                       ( addr -- block-size #blocks )
351   >r                                        ( R: -- addr )
352   r@ read-cap-16-data>block-size l@         ( block-size )
353   r@ read-cap-16-data>max-lba-high l@       ( block-size #blocks-high )
354   d# 32 lshift                              ( block-size #blocks-upper )
355   r> read-cap-16-data>max-lba-low l@ +      ( block-size #blocks ) ( R: addr -- )
356;
357
358\ ***************************************************************************
359\ SCSI-Command: MODE SENSE (10)
360\         Type: Primary Command (SPC-3 clause 6.10)
361\ ***************************************************************************
362\ Forth Word:   scsi-build-mode-sense-10  ( alloc-len subpage page cdb -- )
363\ ***************************************************************************
3645a CONSTANT scsi-cmd-mode-sense-10
365
366\ CDB structure
367STRUCT
368	/c	FIELD mode-sense-10>operation-code
369	/c	FIELD mode-sense-10>res-llbaa-dbd-res
370	/c	FIELD mode-sense-10>pc-page-code       \ page code + page control
371	/c	FIELD mode-sense-10>sub-page-code
372	3	FIELD mode-sense-10>reserved2
373	/w	FIELD mode-sense-10>allocation-length
374	/c	FIELD mode-sense-10>control
375CONSTANT scsi-length-mode-sense-10
376
377: scsi-build-mode-sense-10                   ( alloc-len subpage page cdb -- )
378   >r                                        ( alloc-len subpage page ) ( R: -- cdb )
379   r@ scsi-length-mode-sense-10 erase        \ 10 bytes CDB
380	scsi-cmd-mode-sense-10                    ( alloc-len subpage page cmd )
381   r@  mode-sense-10>operation-code c!		   ( alloc-len subpage page )
382   10 r@ mode-sense-10>res-llbaa-dbd-res c!  \ long LBAs accepted
383	r@ mode-sense-10>pc-page-code c!	         ( alloc-len subpage )
384	r@ mode-sense-10>sub-page-code c!	      ( alloc-len )
385	r@ mode-sense-10>allocation-length w!     ( )
386
387   scsi-param-control r> mode-sense-10>control c!  ( R: cdb -- )
388   scsi-length-mode-sense-10 to scsi-param-size  \ update CDB length
389;
390
391\ return data processing
392\ (see spec: SPC-3 clause 7.4.3)
393
394STRUCT
395	/w	FIELD mode-sense-10-data>head-length
396	/c	FIELD mode-sense-10-data>head-medium
397	/c	FIELD mode-sense-10-data>head-param
398	/c	FIELD mode-sense-10-data>head-longlba
399	/c	FIELD mode-sense-10-data>head-reserved
400	/w	FIELD mode-sense-10-data>head-descr-len
401CONSTANT scsi-length-mode-sense-10-data
402
403\ ****************************************
404\ This function shows the mode page header
405\ helpful for further analysis
406\ ****************************************
407: .mode-sense-data   ( addr -- )
408   cr
409   dup mode-sense-10-data>head-length
410   w@ ." Mode Length: " .d space
411   dup mode-sense-10-data>head-medium
412   c@ ." / Medium Type: " .d space
413   dup mode-sense-10-data>head-longlba
414   c@ ." / Long LBA: " .d space
415   mode-sense-10-data>head-descr-len
416   w@ ." / Descr. Length: " .d
417;
418
419\ ***************************************************************************
420\ SCSI-Command: READ (10)
421\         Type: Block Command (SBC-3 clause 5.8)
422\ ***************************************************************************
423\ Forth Word:   scsi-build-read-10  ( block# #blocks cdb -- )
424\ ***************************************************************************
425\ command code
42628 CONSTANT scsi-cmd-read-10
427
428\ CDB structure
429STRUCT
430   /c FIELD read-10>operation-code
431   /c FIELD read-10>protect
432   /l FIELD read-10>block-address      \ logical block address (32bits)
433   /c FIELD read-10>group
434   /w FIELD read-10>length             \ transfer length (16-bits)
435   /c FIELD read-10>control
436CONSTANT scsi-length-read-10
437
438: scsi-build-read-10                         ( block# #blocks cdb -- )
439   >r                                        ( block# #blocks )  ( R: -- cdb )
440   r@ scsi-length-read-10 erase             \ 10 bytes CDB
441	scsi-cmd-read-10 r@ read-10>operation-code c! ( block# #blocks )
442   r@ read-10>length w!                      ( block# )
443   r@ read-10>block-address l!               (  )
444   scsi-param-control r> read-10>control c!  ( R: cdb -- )
445   scsi-length-read-10 to scsi-param-size    \ update CDB length
446;
447
448\ ***************************************************************************
449\ SCSI-Command: READ (12)
450\         Type: Block Command (SBC-3 clause 5.9)
451\ ***************************************************************************
452\ Forth Word:   scsi-build-read-12  ( block# #blocks cdb -- )
453\ ***************************************************************************
454\ command code
455a8 CONSTANT scsi-cmd-read-12
456
457\ CDB structure
458STRUCT
459   /c FIELD read-12>operation-code     \ code: a8
460   /c FIELD read-12>protect            \ RDPROTECT, DPO, FUA, FUA_NV
461   /l FIELD read-12>block-address      \ lba
462   /l FIELD read-12>length             \ transfer length (32bits)
463   /c FIELD read-12>group              \ group number
464   /c FIELD read-12>control
465CONSTANT scsi-length-read-12
466
467: scsi-build-read-12                         ( block# #blocks cdb -- )
468   >r                                        ( block# #blocks )  ( R: -- cdb )
469   r@ scsi-length-read-12 erase             \ 12 bytes CDB
470	scsi-cmd-read-12 r@ read-12>operation-code c! ( block# #blocks )
471   r@ read-12>length l!                      ( block# )
472   r@ read-12>block-address l!               (  )
473   scsi-param-control r> read-12>control c!  ( R: cdb -- )
474   scsi-length-read-12 to scsi-param-size    \ update CDB length
475;
476
477\ ***************************************************************************
478\ SCSI-Command: READ (16)
479\         Type: Block Command
480\ ***************************************************************************
481\ Forth Word:   scsi-build-read-16  ( block# #blocks cdb -- )
482\ ***************************************************************************
483\ command code
48488 CONSTANT scsi-cmd-read-16
485
486\ CDB structure
487STRUCT
488   /c FIELD read-16>operation-code     \ code: 88
489   /c FIELD read-16>protect            \ RDPROTECT, DPO, FUA, FUA_NV
490   /x FIELD read-16>block-address      \ lba
491   /l FIELD read-16>length             \ transfer length (32bits)
492   /c FIELD read-16>group              \ group number
493   /c FIELD read-16>control
494CONSTANT scsi-length-read-16
495
496: scsi-build-read-16                         ( block# #blocks cdb -- )
497   >r                                        ( block# #blocks )  ( R: -- cdb )
498   r@ scsi-length-read-16 erase              \ 16 bytes CDB
499   scsi-cmd-read-16 r@ read-16>operation-code c! ( block# #blocks )
500   r@ read-16>length l!                      ( block# )
501   r@ read-16>block-address x!               (  )
502   scsi-param-control r> read-16>control c!  ( R: cdb -- )
503   scsi-length-read-16 to scsi-param-size    \ update CDB length
504;
505
506\ ***************************************************************************
507\ SCSI-Command: READ with autodetection of required command
508\               read(10) or read(12) depending on parameter size
509\               (read(6) removed because obsolete in some cases (USB))
510\         Type: Block Command
511\ ***************************************************************************
512\ Forth Word:   scsi-build-read?    ( block# #blocks cdb -- )
513\
514\                         +----------------+---------------------------|
515\                         |  block# (lba)  |  #block (transfer-length) |
516\             +-----------+----------------+---------------------------|
517\             | read-6    |  16-Bits       |  8  Bits                  |
518\             | read-10   |  32-Bits       |  16 Bits                  |
519\             | read-12   |  32-Bits       |  32 Bits                  |
520\ ***************************************************************************
521: scsi-build-read?   ( block# #blocks cdb -- length )
522   over              ( block# #blocks cdb #blocks )
523   fffe >            \ tx-length (#blocks) exceeds 16-bit limit ?
524   IF
525      scsi-build-read-12   ( block# #blocks cdb -- )
526      scsi-length-read-12  ( length )
527   ELSE                    ( block# #blocks cdb )
528      scsi-build-read-10   ( block# #blocks cdb -- )
529      scsi-length-read-10  ( length )
530   THEN
531;
532
533\ ***************************************************************************
534\ SCSI-Command: WRITE (10)
535\         Type: Block Command
536\ ***************************************************************************
537\ Forth Word:   scsi-build-write-10  ( block# #blocks cdb -- )
538\ ***************************************************************************
539\ command code
5402A CONSTANT scsi-cmd-write-10
541
542\ CDB structure
543STRUCT
544   /c FIELD write-10>operation-code
545   /c FIELD write-10>protect
546   /l FIELD write-10>block-address            \ logical block address (32bits)
547   /c FIELD write-10>group
548   /w FIELD write-10>length                   \ transfer length (16-bits)
549   /c FIELD write-10>control
550CONSTANT scsi-length-write-10
551
552: scsi-build-write-10                         ( block# #blocks cdb -- )
553   >r                                         ( block# #blocks )  ( R: -- cdb )
554   r@ scsi-length-write-10 erase              \ 10 bytes CDB
555   scsi-cmd-write-10 r@ write-10>operation-code c! ( block# #blocks )
556   r@ write-10>length w!                      ( block# )
557   r@ write-10>block-address l!               (  )
558   scsi-param-control r> write-10>control c!  ( R: cdb -- )
559   scsi-length-write-10 to scsi-param-size    \ update CDB length
560;
561
562\ ***************************************************************************
563\ SCSI-Command: WRITE (16)
564\         Type: Block Command
565\ ***************************************************************************
566\ Forth Word:   scsi-build-write-16  ( block# #blocks cdb -- )
567\ ***************************************************************************
568\ command code
5698A CONSTANT scsi-cmd-write-16
570
571\ CDB structure
572STRUCT
573   /c FIELD write-16>operation-code
574   /c FIELD write-16>protect                  \ RDPROTECT, DPO, FUA, FUA_NV
575   /x FIELD write-16>block-address            \ LBA
576   /l FIELD write-16>length                   \ Transfer length (32-bits)
577   /c FIELD write-16>group                    \ Group number
578   /c FIELD write-16>control
579CONSTANT scsi-length-write-16
580
581: scsi-build-write-16                         ( block# #blocks cdb -- )
582   >r                                         ( block# #blocks )  ( R: -- cdb )
583   r@ scsi-length-write-16 erase              \ 16 bytes CDB
584   scsi-cmd-write-16 r@ write-16>operation-code c! ( block# #blocks )
585   r@ write-16>length l!                      ( block# )
586   r@ write-16>block-address x!               (  )
587   scsi-param-control r> write-16>control c!  ( R: cdb -- )
588   scsi-length-write-16 to scsi-param-size    \ update CDB length
589;
590
591\ ***************************************************************************
592\ SCSI-Command: START STOP UNIT
593\         Type: Block Command (SBC-3 clause 5.19)
594\ ***************************************************************************
595\ Forth Word:   scsi-build-start-stop-unit  ( state# cdb -- )
596\ ***************************************************************************
597\ command code
5981b CONSTANT scsi-cmd-start-stop-unit
599
600\ CDB structure
601STRUCT
602   /c FIELD start-stop-unit>operation-code
603   /c FIELD start-stop-unit>immed
604   /w FIELD start-stop-unit>reserved
605   /c FIELD start-stop-unit>pow-condition
606   /c FIELD start-stop-unit>control
607CONSTANT scsi-length-start-stop-unit
608
609\ START/STOP constants
610\ (see spec: SBC-3 clause 5.19)
611f1 CONSTANT scsi-const-active-power    \ param used for start-stop-unit
612f2 CONSTANT scsi-const-idle-power      \ param used for start-stop-unit
613f3 CONSTANT scsi-const-standby-power   \ param used for start-stop-unit
6143  CONSTANT scsi-const-load            \ param used for start-stop-unit
6152  CONSTANT scsi-const-eject           \ param used for start-stop-unit
6161  CONSTANT scsi-const-start
6170  CONSTANT scsi-const-stop
618
619: scsi-build-start-stop-unit                 ( state# cdb -- )
620   >r                                        ( state# )  ( R: -- cdb )
621   r@ scsi-length-start-stop-unit erase      \ 6 bytes CDB
622	scsi-cmd-start-stop-unit r@ start-stop-unit>operation-code c!
623   dup 3 >
624   IF
625      4 lshift                         \ shift to upper nibble
626   THEN                                ( state )
627   r@ start-stop-unit>pow-condition c!       (  )
628   scsi-param-control r> start-stop-unit>control c!  ( R: cdb -- )
629   scsi-length-start-stop-unit to scsi-param-size  \ update CDB length
630;
631
632\ ***************************************************************************
633\ SCSI-Command: SEEK(10)
634\         Type: Block Command (obsolete)
635\ ***************************************************************************
636\ Forth Word:   scsi-build-seek  ( state# cdb -- )
637\ Obsolete function (last listed in spec SBC / Nov. 1997)
638\ implemented only for the sake of completeness
639\ ***************************************************************************
640\ command code
6412b CONSTANT scsi-cmd-seek
642
643\ CDB structure
644STRUCT
645   /c FIELD seek>operation-code
646   /c FIELD seek>reserved1
647   /l FIELD seek>lba
648   3  FIELD seek>reserved2
649   /c FIELD seek>control
650CONSTANT scsi-length-seek
651
652: scsi-build-seek  ( lba cdb -- )
653   >r              ( lba )  ( R: -- cdb )
654   r@ scsi-length-seek erase           \ 10 bytes CDB
655	scsi-cmd-seek r@ seek>operation-code c!
656   r> seek>lba l!  (  )  ( R: cdb -- )
657   scsi-length-seek to scsi-param-size \ update CDB length
658;
659
660\ ****************************************************************************
661\ CDROM media event stuff
662\ ****************************************************************************
663
664STRUCT
665    /w FIELD media-event-data-len
666    /c FIELD media-event-nea-class
667    /c FIELD media-event-supp-class
668    /l FIELD media-event-data
669CONSTANT scsi-length-media-event
670
671: scsi-build-get-media-event                     ( cdb -- )
672   dup c erase				         ( cdb )
673   4a over c!				         ( cdb )
674   01 over 1 + c!
675   10 over 4 + c!
676   08 over 8 + c!
677   drop
678;
679
680
681
682\ ***************************************************************************
683\ SCSI-Utility: .sense-code
684\ ***************************************************************************
685\ this utility prints a string associated to the sense code
686\ see specs: SPC-3/r23 clause 4.5.6
687\ ***************************************************************************
688: .sense-text ( scode -- )
689   case
690      0    OF s" OK"               ENDOF
691      1    OF s" RECOVERED ERR"    ENDOF
692      2    OF s" NOT READY"        ENDOF
693      3    OF s" MEDIUM ERROR"     ENDOF
694      4    OF s" HARDWARE ERR"     ENDOF
695      5    OF s" ILLEGAL REQUEST"  ENDOF
696      6    OF s" UNIT ATTENTION"   ENDOF
697      7    OF s" DATA PROTECT"     ENDOF
698      8    OF s" BLANK CHECK"      ENDOF
699      9    OF s" VENDOR SPECIFIC"  ENDOF
700      a    OF s" COPY ABORTED"     ENDOF
701      b    OF s" ABORTED COMMAND"  ENDOF
702      d    OF s" VOLUME OVERFLOW"  ENDOF
703      e    OF s" MISCOMPARE"       ENDOF
704      dup  OF s" UNKNOWN"          ENDOF
705   endcase
706   5b emit type 5d emit
707;
708
709\ ***************************************************************************
710\ SCSI-Utility: .status-code
711\ ***************************************************************************
712\ this utility prints a string associated to the status code
713\ see specs: SAM-3/r14 clause 5.3
714\ ***************************************************************************
715: .status-text  ( stat -- )
716   case
717      00  OF s" GOOD"                  ENDOF
718      02  OF s" CHECK CONDITION"       ENDOF
719      04  OF s" CONDITION MET"         ENDOF
720      08  OF s" BUSY"                  ENDOF
721      18  OF s" RESERVATION CONFLICT"  ENDOF
722      28  OF s" TASK SET FULL"         ENDOF
723      30  OF s" ACA ACTIVE"            ENDOF
724      40  OF s" TASK ABORTED"          ENDOF
725      dup OF s" UNKNOWN"               ENDOF
726   endcase
727   5b emit type 5d emit
728;
729
730\ ***************************************************************************
731\ SCSI-Utility: .capacity-text
732\ ***************************************************************************
733\ utility that shows total capacity on screen by use of the return data
734\ from read-capacity calculation is SI conform (base 10)
735\ ***************************************************************************
736\ sub function to print a 3 digit decimal
737\ number with 2 post decimal positions xxx.yy
738: .dec3-2 ( prenum postnum -- )
739   swap
740   base @ >r                           \ save actual base setting
741   decimal                             \ show decimal values
742   4 .r 2e emit
743   dup 9 <= IF 30 emit THEN .d         \ 3 pre-decimal, right aligned
744   r> base !                           \ restore base
745;
746
747: .capacity-text  ( block-size #blocks -- )
748   scsi-param-debug                    \ debugging flag set ?
749   IF                                  \ show additional info
750      2dup
751      cr
752      ." LBAs: " .d                    \ highest logical block number
753      ." / Block-Size: " .d
754      ." / Total Capacity: "
755   THEN
756   *                                   \ calculate total capacity
757   dup d# 1000000000000 >=             \ check terabyte limit
758   IF
759      d# 1000000000000 /mod
760      swap
761      d# 10000000000 /                 \ limit remainder to two digits
762      .dec3-2 ." TB"                   \ show terabytes as xxx.yy
763   ELSE
764      dup d# 1000000000 >=             \ check gigabyte limit
765      IF
766         d# 1000000000 /mod
767         swap
768         d# 10000000 /
769         .dec3-2 ." GB"                \ show gigabytes as xxx.yy
770      ELSE
771         dup d# 1000000 >=
772         IF
773            d# 1000000 /mod            \ check mega byte limit
774            swap
775            d# 10000 /
776            .dec3-2 ." MB"             \ show megabytes as xxx.yy
777         ELSE
778            dup d# 1000 >=             \ check kilo byte limit
779            IF
780               d# 1000 /mod
781               swap
782               d# 10 /
783               .dec3-2 ." kB"
784            ELSE
785               .d ."  Bytes"
786            THEN
787         THEN
788      THEN
789   THEN
790;
791
792\ ***************************************************************************
793\ SCSI-Utility: .inquiry-text  ( addr -- )
794\ ***************************************************************************
795\ utility that shows:
796\     vendor-ident product-ident and revision
797\ from an inquiry return data block (addr)
798\ ***************************************************************************
799: .inquiry-text  ( addr -- )
800   22 emit     \ enclose text with "
801   dup inquiry-data>vendor-ident      8 type space
802   dup inquiry-data>product-ident    10 type space
803       inquiry-data>product-revision  4 type
804   22 emit
805;
806
807\ ***************************************************************************
808\ SCSI-Utility: scsi-supp-init  ( -- )
809\ ***************************************************************************
810\ utility that helps to ensure that parameters are set to valid values
811: scsi-supp-init  ( -- )
812   false   to scsi-param-debug         \ no debug strings
813   h# 0   to scsi-param-size
814   h# 0   to scsi-param-control        \ common CDB control byte
815   d# 0   to scsi-param-errors         \ local errors (param limits)
816;
817
818\ ***************************************************************************
819\ Constants used by SCSI controller's execute-scsi-command
820\ ***************************************************************************
821true  CONSTANT scsi-dir-read
822false CONSTANT scsi-dir-write
823
824
825\ ***************************************************************************
826\ scsi loader
827\ ***************************************************************************
8280 VALUE scsi-context                   \ addr of word list on top
829
830
831\ ****************************************************************************
832\ open scsi-support by adding a new word list on top of search path
833\   precondition: scsi-support.fs must have been included
834\ ****************************************************************************
835: scsi-init  ( -- )
836   also scsi-words                     \ append scsi word-list
837   context  to scsi-context            \ save for close process
838   scsi-supp-init                      \ preset all scsi-param-xxx values
839   scsi-param-debug
840   IF
841      space ." SCSI-SUPPORT OPENED" cr
842      .wordlists
843   THEN
844;
845
846\ ****************************************************************************
847\ close scsi-session and remove scsi word list (if exists)
848\ ****************************************************************************
849\ if 'previous' is used without a preceding 'also' all forth words are lost !
850\ ****************************************************************************
851: scsi-close  ( -- )
852\ FIXME This only works if scsi-words is the last vocabulary on the stack
853\       Instead we could use get-order to find us on the "wordlist stack",
854\       remove us and write the wordlist stack back with set-order.
855\       BUT: Is this worth the effort?
856
857   scsi-param-debug
858   IF
859      space ." Closing SCSI-SUPPORT .. " cr
860   THEN
861   context scsi-context =              \ scsi word list still active ?
862   IF
863      scsi-param-errors 0<>          \ any errors occurred ?
864      IF
865         cr ." ** WARNING: " scsi-param-errors .d
866         ." SCSI Errors occurred ** " cr
867      THEN
868      previous                         \ remove scsi word list on top
869      0 to scsi-context                \ prevent from being misinterpreted
870   ELSE
871      cr ." ** WARNING: Trying to close non-open SCSI-SUPPORT (1) ** " cr
872   THEN
873   scsi-param-debug
874   IF
875     .wordlists
876   THEN
877;
878
879
880s" scsi-init" $find drop               \ return execution pointer, when included
881
882previous                               \ remove scsi word list from search path
883definitions                            \ place next definitions into previous list
884
885