|
|
1.1 root 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: \ -----------------------------------------------------------
15: \ OF properties
16: \ -----------------------------------------------------------
17:
18: s" storage" device-name
19: s" block" device-type
20:
21: 2 encode-int s" #address-cells" property
22: 0 encode-int s" #size-cells" property
23:
24: \ -----------------------------------------------------------
25: \ Specific properties
26: \ -----------------------------------------------------------
27:
28: 8 VALUE mps-bulk-out
29: 8 VALUE mps-bulk-in
30: 8 VALUE mps-dcp
31: 0 VALUE bulk-in-ep
32: 0 VALUE bulk-out-ep
33: 0 VALUE bulk-in-toggle
34: 0 VALUE bulk-out-toggle
35: 0 VALUE lun
36: 0 VALUE my-usb-address
37:
38:
39: \ ----------------------------------------------------------
40: \ Instance specific values
41: \ ----------------------------------------------------------
42:
43: 0 VALUE csw-buffer
44: 0e VALUE cfg-buffer
45: 0 VALUE response-buffer
46: 0 VALUE command-buffer
47: 0 VALUE resp-size
48: 0 VALUE resp-buffer
49: INSTANCE VARIABLE ihandle-bulk
50: INSTANCE VARIABLE ihandle-deblocker
51: INSTANCE VARIABLE flag
52: INSTANCE VARIABLE count
53: 0 VALUE max-transfer
54: 200 VALUE block-size \ default (512 Bytes)
55: -1 VALUE max-block-num \ highest reported block-number
56:
57:
58: \ -------------------------------------------------------
59: \ General Constants
60: \ -------------------------------------------------------
61:
62: 0f CONSTANT SCSI-COMMAND-OFFSET
63:
64:
65: \ -------------------------------------------------------
66: \ All support methods inherited from parent or imported
67: \ from support packages are included here. Also included
68: \ are the internal methods
69: \ -------------------------------------------------------
70:
71: s" usb-storage-support.fs" INCLUDED
72:
73: \ ---------------------------------------------------------------
74: \ COLON Definitions: Implementation of Standard SCSI commands
75: \ over USB OHCI
76: \ ---------------------------------------------------------------
77:
78:
79: \ to use the general bulk command a lot of global variables
80: \ must be set. See for example the inquiry command.
81: 0 VALUE bulk-cnt
82: 0 VALUE bulk-cmd-len
83: 0 VALUE itest
84: : do-bulk-command ( resp-buffer resp-size -- TRUE | FALSE )
85: TO resp-size
86: TO resp-buffer
87: \ dump buffer in debug-mode
88: usb-debug-flag
89: IF
90: command-buffer 0E + c@ TO bulk-cmd-len
91: s" cmd-length: " bulk-cmd-len usb-debug-print-val
92: command-buffer bulk-cmd-len 0E + dump cr
93: THEN
94:
95: 6 TO bulk-cnt \ 2 old value
96: FALSE dup
97: BEGIN
98: 0=
99: WHILE
100: drop
101: \ prepare and send bulk CBW
102: 1 1 bulk-out-toggle command-buffer 1f mps-bulk-out
103: ( pt ed-type toggle buffer length mps-bulk-out )
104: my-usb-address bulk-out-ep 7 lshift or
105: ( pt ed-type toggle buffer length mps address )
106: rw-endpoint swap ( TRUE toggle | FALSE toggle )
107: to bulk-out-toggle ( TRUE | FALSE )
108: IF
109: s" resp-size : " resp-size usb-debug-print-val
110: resp-size 0<>
111: IF \ do we need a response ?!
112: \ read the bulk response
113: 0 1 bulk-in-toggle resp-buffer resp-size mps-bulk-in
114: ( pt ed-type toggle buffer length mps-bulk-in )
115: my-usb-address bulk-in-ep 7 lshift or
116: ( pt ed-type toggle buffer length mps address )
117: rw-endpoint swap ( TRUE toggle | FALSE toggle )
118: to bulk-in-toggle ( TRUE | FALSE )
119: ELSE
120: TRUE
121: THEN
122: IF \ read the bulk CSW
123: 0 1 bulk-in-toggle csw-buffer D mps-bulk-in
124: ( pt ed-type toggle buffer length mps-bulk-in )
125: my-usb-address bulk-in-ep 7 lshift or
126: ( pt ed-type toggle buffer length mps address )
127: rw-endpoint swap ( TRUE toggle | FALSE toggle )
128: to bulk-in-toggle ( TRUE | FALSE )
129: IF
130: s" Command successful." usb-debug-print
131: TRUE dup
132: ELSE
133: s" Command failed in CSW stage" usb-debug-print
134: FALSE dup
135: THEN
136: ELSE
137: s" Command failed while receiving DATA... read CSW..." usb-debug-print
138: \ STALLED: Get CSW to send the CBW again
139: 0 1 bulk-in-toggle csw-buffer D mps-bulk-in
140: ( pt ed-type toggle buffer length mps-bulk-in )
141: my-usb-address bulk-in-ep 7 lshift or
142: ( pt ed-type toggle buffer length mps address )
143: rw-endpoint swap ( TRUE toggle | FALSE toggle )
144: to bulk-in-toggle ( TRUE | FALSE )
145: IF
146: s" OK evaluate the CSW ..." usb-debug-print
147: csw-buffer c + c@ dup TO itest
148: s" CSW Status: " itest usb-debug-print-val
149: dup
150: 2 =
151: IF \ Phase Error
152: s" Phase error do a bulk reset-recovery ..." usb-debug-print
153: bulk-out-ep bulk-in-ep my-usb-address
154: bulk-reset-recovery-procedure
155: THEN
156: \ ELSE
157: \ don't abort if the read fails.
158: 1 =
159: IF \ Command failed
160: s" Command Failed do a bulk-reset-recovery" usb-debug-print
161: bulk-out-ep bulk-in-ep my-usb-address
162: bulk-reset-recovery-procedure
163: THEN
164: THEN
165: FALSE dup
166: THEN
167: ELSE
168: s" Command failed while Sending CBW ..." usb-debug-print
169: FALSE dup
170: THEN
171: bulk-cnt 1 - TO bulk-cnt
172: bulk-cnt 0=
173: IF
174: 2drop FALSE dup
175: THEN
176: REPEAT
177: ;
178:
179:
180: \ ---------------------------------------------------------------
181: \ Method to 1. Send the INQUIRY command 2. Receive and analyse
182: \ (pending) INQUIRY data
183: \ ---------------------------------------------------------------
184: scsi-open
185: usb-debug-flag to scsi-param-debug \ copy debug flag
186:
187: 24 CONSTANT inquiry-length \ was 20
188:
189: : inquiry ( -- )
190: s" usb-storage: inquiry" usb-debug-print
191: command-buffer 1 inquiry-length 80 lun scsi-length-inquiry
192: ( address tag transfer-len direction lun command-len )
193: build-cbw
194: inquiry-length command-buffer SCSI-COMMAND-OFFSET + ( alloc-len address )
195: scsi-build-inquiry
196: response-buffer inquiry-length erase \ provide clean buffer
197: response-buffer inquiry-length do-bulk-command
198: IF
199: s" Successfully read INQUIRY data" usb-debug-print
200: 0d emit space space
201: response-buffer c@ \ get 'Peripheral Device Type' (PDT)
202: CASE
203: 0 OF ." BLOCK-DEV: " ENDOF \ SCSI Block Device
204: 5 OF ." CD-ROM : " ENDOF
205: 7 OF ." OPTICAL : " ENDOF
206: e OF ." RED-BLOCK: " ENDOF \ SCSI Reduced Block Device
207: dup dup OF ." ? (" . 8 emit 29 emit 2 spaces ENDOF
208: ENDCASE
209: space
210: \ create vendor identification in device property
211: response-buffer 8 + 16 encode-string s" ident-str" property
212: response-buffer .inquiry-text
213: ELSE
214: 5040 error" (USB) Device transaction error. (inquiry)"
215: ABORT
216: THEN
217: ;
218:
219: \ ---------------------------------------------------------------
220: \ Method to 1. Send the READ CAPACITY command
221: \ 2. Recieve and analyse the response data
222: \ ---------------------------------------------------------------
223:
224: : read-capacity ( -- )
225: s" usb-storage: read-capacity" usb-debug-print
226: command-buffer 1 8 80 lun scsi-length-read-cap-10
227: ( address tag transfer-len direction lun command-len )
228: build-cbw
229: \ command-buffer 30 dump cr \ dump the command buffer
230: command-buffer SCSI-COMMAND-OFFSET + ( address )
231: scsi-build-read-cap-10
232: lun 5 lshift
233: command-buffer SCSI-COMMAND-OFFSET + ( address )
234: read-cap-10>reserved1 c!
235:
236: response-buffer 8 erase \ provide clean buffer
237: response-buffer 8 do-bulk-command
238: IF
239: s" Successfully read READ CAPACITY data" usb-debug-print
240: ELSE
241: 5040 error" (USB) Device transaction error. (capacity)"
242: ABORT
243: THEN
244: ;
245:
246:
247: \ -------------------------------------------------------------------
248: \ Method to 1. Send TEST UNIT READY command 2. Analyse the status
249: \ of the response
250: \ -------------------------------------------------------------------
251:
252: : test-unit-ready ( -- TRUE | FALSE )
253: command-buffer 1 0 80 lun scsi-length-test-unit-ready \ was: 0c
254: ( address tag transfer-len direction lun command-len )
255: build-cbw
256: command-buffer SCSI-COMMAND-OFFSET + ( address )
257: scsi-build-test-unit-ready ( cdb -- )
258: response-buffer 0 do-bulk-command
259: IF
260: s" Successfully read test unit ready data" usb-debug-print
261: s" Test Unit STATUS availabe in csw-buffer" usb-debug-print
262: csw-buffer 0c + c@ 0= IF
263: s" Test Unit Command Successfully Executed" usb-debug-print
264: TRUE ( TRUE )
265: ELSE
266: s" Test Unit Command Failed to execute" usb-debug-print
267: FALSE ( FALSE )
268: THEN
269: ELSE
270: \ TRUE ABORT" USB device transaction error. (test-unit-ready)"
271: 5040 error" (USB) Device transaction error. (test-unit-ready)"
272: ABORT
273: THEN
274: ;
275:
276: \ ****************************************************
277: \ multiple checks of 'test-unit-ready' with timeout
278: \ ****************************************************
279: : wait-for-unit-ready ( -- TRUE|FALSE )
280: s" --> WAIT: test-unit-ready ... " usb-debug-print
281: d# 100 ( count ) \ up to 10 seconds
282: BEGIN ( count )
283: dup 0> ( count flag )
284: test-unit-ready \ dup IF 2b ELSE 2d THEN emit
285: not and ( count flag )
286: WHILE
287: 1- ( count )
288: d# 100 wait-proceed \ wait 100 ms
289: REPEAT ( count )
290: 0=
291: IF
292: s" ** Device not ready ** " usb-debug-print
293: FALSE
294: ELSE
295: TRUE
296: THEN
297: ;
298:
299:
300: \ -------------------------------------------------
301: \ Method to 1. read sense data 2. analyse sesnse
302: \ data(pending)
303: \ ------------------------------------------------
304:
305: : request-sense ( -- )
306: s" request-sense: Command ready." usb-debug-print
307: command-buffer 1 12 80 lun scsi-length-request-sense
308: ( address tag transfer-len direction lun command-len )
309: build-cbw
310: \ -scsi-supp- command-buffer SCSI-COMMAND-OFFSET + 12 ( address alloc-len )
311: \ -scsi-supp- build-request-sense
312:
313: 12 command-buffer SCSI-COMMAND-OFFSET + ( alloc-len cdb )
314: scsi-build-request-sense ( alloc-len cdb -- )
315:
316: response-buffer 12 do-bulk-command
317: IF
318: s" Read Sense data successfully" usb-debug-print
319: \ response-buffer 12 dump cr \ dump the rsponsed message
320: ELSE
321: \ TRUE ABORT" USB device transaction error. (request-sense)"
322: 5040 error" (USB) Device transaction error. (request-sense)"
323: ABORT
324: THEN
325: ;
326:
327: : start ( -- )
328: command-buffer 1 0 80 lun scsi-length-start-stop-unit
329: ( address tag transfer-len direction lun command-len )
330: build-cbw
331: \ -scsi-supp- command-buffer SCSI-COMMAND-OFFSET + ( address )
332: \ -scsi-supp- build-start
333:
334: command-buffer SCSI-COMMAND-OFFSET + ( cdb )
335: scsi-const-start scsi-build-start-stop-unit ( state# cdb -- )
336:
337: response-buffer 0 do-bulk-command
338: IF
339: s" Start successfully" usb-debug-print
340: ELSE
341: \ TRUE ABORT" USB device transaction error. (start)"
342: 5040 error" (USB) Device transaction error. (start)"
343: ABORT
344: THEN
345: ;
346:
347:
348: \ To transmit SCSI Stop command
349:
350: : stop ( -- )
351: command-buffer 1 0 80 lun scsi-length-start-stop-unit
352: ( address tag transfer-len direction lun command-len )
353: build-cbw
354: \ -scsi-supp- command-buffer SCSI-COMMAND-OFFSET + ( address )
355: \ -scsi-supp- build-stop
356:
357: command-buffer SCSI-COMMAND-OFFSET + ( cdb )
358: scsi-const-stop scsi-build-start-stop-unit ( state# cdb -- )
359:
360: response-buffer 0 do-bulk-command
361: IF
362: s" Stop successfully" usb-debug-print
363: ELSE
364: \ TRUE ABORT" USB device transaction error. (stop)"
365: 5040 error" (USB) Device transaction error. (stop)"
366: ABORT
367: THEN
368: ;
369:
370:
371: 0 VALUE temp1
372: 0 VALUE temp2
373: 0 VALUE temp3
374:
375:
376: \ -------------------------------------------------------------
377: \ block device's seek
378: \ -------------------------------------------------------------
379: \ if anything is wrong in the boot device, a seek-request can
380: \ occur that exceeds the limits of the device in the following
381: \ read-command. So checking is required and the appropriate
382: \ return-value has to be returned
383: \ Spec requires -1 if operation fails and 0 or 1 if it succeeds !!
384: \ -------------------------------------------------------------
385:
386: : seek ( pos-lo pos-hi -- status )
387: 2dup lxjoin max-block-num block-size * >
388: IF
389: ." ** Seek Error: pos too large ("
390: dup . over . ." -> " max-block-num block-size * .
391: ." ) ** " cr
392: -1 \ see spec-1275 page 183
393: ELSE
394: s" seek" ihandle-deblocker @ $call-method
395: THEN
396: ;
397:
398:
399: \ -------------------------------------------------------------
400: \ block device's read
401: \ -------------------------------------------------------------
402:
403: : read ( address length -- actual )
404: s" read" ihandle-deblocker @ $call-method
405: ;
406:
407:
408: \ -------------------------------------------------------------
409: \ read-blocks to be used by deblocker
410: \ -------------------------------------------------------------
411: : read-blocks ( address block# #blocks -- #read-blocks )
412: 2dup + max-block-num >
413: IF
414: ." ** Requested block too large "
415: 2dup + ." (" .d ." -> " max-block-num .d
416: bs emit ." ) ... read aborted **" cr
417: nip nip \ leave #blocks on stack
418: ELSE
419: block-size * command-buffer ( address block# transfer-len command-buffer )
420: 1 2 pick 80 lun 0c build-cbw ( address block# transfer-len )
421: dup to temp1 ( address block# transfer-len )
422: block-size / ( address block# #blocks )
423: command-buffer ( address block# #blocks command-addr )
424: SCSI-COMMAND-OFFSET + ( address block# #blocks cdb )
425: scsi-build-read? ( block# #blocks cdb -- length )
426: command-buffer 0e + c! \ update bCBWCBLength-field with resulting CDB length
427: temp1 ( address length )
428: do-bulk-command
429: IF
430: s" Read data successfully" usb-debug-print
431: ELSE
432: \ TRUE ABORT" USB device transaction error. (read-blocks)"
433: 5040 error" (USB) Device transaction error. (read-blocks)"
434: ABORT
435: THEN
436: temp1 block-size / ( #read-blocks )
437: THEN
438: ;
439:
440: \ ------------------------------------------------
441: \ To bring the the media to seekable and readable
442: \ condition.
443: \ ------------------------------------------------
444:
445: d# 800 CONSTANT media-ready-retry
446:
447: : make-media-ready ( -- )
448: s" usb-storage: make-media-ready" usb-debug-print
449: 0 flag !
450: 0 count !
451: BEGIN
452: flag @ 0=
453: WHILE
454: test-unit-ready IF
455: s" Media ready for access." usb-debug-print
456: 1 flag !
457: ELSE
458: count @ 1 + count !
459: count @ media-ready-retry = IF
460: 1 flag !
461: 5000 error" (USB) Media or drive not ready for this blade."
462: ABORT
463: THEN
464: request-sense
465: response-buffer scsi-get-sense-ID? ( addr -- false | sense-ID true )
466: IF
467: ffff00 AND \ remaining: sense-key ASC
468: CASE
469: 023a00 OF \ MEDIUM NOT PRESENT (02 3a 00)
470: 5010 error" (USB) No Media found! Check for the drawer/inserted media."
471: ABORT
472: ENDOF
473:
474: 020400 OF \ LOGICAL DRIVE NOT READY - INITIALIZATION REQUIRED
475: 5010 error" (USB) No Media found! Check for the drawer/inserted media."
476: ABORT
477: ENDOF
478:
479: 033000 OF \ CANNOT READ MEDIUM - UNKNOWN FORMAT
480: 5020 error" (USB) Unknown media format."
481: ABORT
482: ENDOF
483: ENDCASE
484: THEN
485: THEN
486: d# 10 ms \ wait maximum 10ms * 800 (=8s)
487: REPEAT
488: usb-debug-flag IF
489: ." make-media-ready finished after "
490: count @ decimal . hex ." tries." cr
491: THEN
492: ;
493:
494: \ ------------------------------------------------
495: \ read and show devices capacity
496: \ ------------------------------------------------
497: : .showcap
498: space
499: test-unit-ready drop \ initial command
500: request-sense
501: response-buffer scsi-get-sense-ID? ( addr -- false | sense-ID true )
502: IF
503: dup FFFF00 and 023a00 = ( sense-id flag )
504: IF
505: uDOC-failure?
506: 023a02 = \ see sense-codes SPC-3 clause 4.5.6
507: IF
508: ." Tray Open!"
509: ELSE
510: ." No Media"
511: THEN
512: ELSE ( sense-id )
513: drop
514: wait-for-unit-ready
515: IF
516: read-capacity
517: response-buffer scsi-get-capacity-10 space .capacity-text
518: ELSE
519: request-sense
520: response-buffer scsi-get-sense-ID? ( addr -- false | sense-ID true )
521: IF
522: dup ff0000 and 040000 = \ sense-code = 4 ?
523: IF
524: ." *HW-ERROR*"
525: uDOC-failure?
526: ELSE
527: dup FFFF00 and 023a00 = IF uDOC-failure? THEN
528: CASE ( sense-ID )
529: \ see SPC-3 clause 4.5.6
530: 023a00 OF ." No Media " ENDOF
531: 023a02 OF ." Tray Open! " ENDOF
532: dup OF ." ? " ENDOF
533: ENDCASE
534: THEN
535: THEN
536: THEN
537: THEN
538: ELSE
539: ." ?? "
540: THEN
541: ;
542:
543:
544:
545: : init-dev-ready
546: test-unit-ready drop
547: 4 >r \ loop-counter
548: 0 0
549: BEGIN
550: 2drop
551: request-sense
552: response-buffer scsi-get-sense-data ( ascq asc sense-key )
553: 0<> r> 1- dup >r 0<> AND \ loop-counter or sense-key
554: WHILE
555: REPEAT
556: 2drop
557: r> drop
558: ;
559:
560:
561:
562: scsi-close \ no further scsi words required
563:
564:
565: \ Set up the block-size of the device, using the READ CAPACITY command.
566: \ Note: Media must be ready (=> make-media-ready) or READ CAPACITY
567: \ might fail!
568:
569: : (init-block-size)
570: read-capacity
571: response-buffer l@ dup 0<>
572: IF
573: to max-block-num \ highest block-number
574: ELSE
575: -1 to max-block-num \ indeterminate
576: THEN
577: response-buffer 4 +
578: l@ to block-size
579: s" usb-storage: block-size=" block-size usb-debug-print-val
580: ;
581:
582:
583: \ Standard OF methods
584:
585: : open ( -- TRUE )
586: s" usb-storage: open" usb-debug-print
587: ihandle-bulk s" bulk" (open-package)
588:
589: make-media-ready
590: (init-block-size) \ Init block-size before opening the deblocker
591:
592: ihandle-deblocker s" deblocker" (open-package)
593:
594: s" disk-label" find-package IF ( phandle )
595: usb-debug-flag IF ." my-args for disk-label = " my-args swap . . cr THEN
596: my-args rot interpose
597: THEN
598: TRUE ( TRUE )
599: ;
600:
601:
602: : close ( -- )
603: ihandle-deblocker (close-package)
604: ihandle-bulk (close-package)
605: ;
606:
607:
608: \ Set device name according to type
609:
610: : (init-device-name) ( -- )
611: init-dev-ready
612: inquiry
613: response-buffer c@
614: CASE
615: 1 OF .showcap s" tape" device-name ENDOF
616: 5 OF .showcap s" cdrom" device-name s" CDROM found" usb-debug-print ENDOF
617: 0 OF .showcap s" sbc-dev" device-name s" SBC Direct access device" usb-debug-print ENDOF
618: 7 OF .showcap s" optical" device-name s" Optical memory found" usb-debug-print ENDOF
619: 0E OF .showcap s" rbc-dev" device-name s" RBC direct acces device found" usb-debug-print ENDOF
620: \ dup OF s" storage" device-name ENDOF
621: ENDCASE
622: ;
623:
624:
625: \ Initial device node setup
626:
627: : (initial-setup)
628: ihandle-bulk s" bulk" (open-package)
629: device-init
630: (init-device-name)
631: set-drive-alias
632: 200 to block-size \ Default block-size, will be overwritten in "open"
633: 10000 to max-transfer
634:
635: ihandle-bulk (close-package)
636: ;
637:
638: (initial-setup)
639:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.