\ ========== Copyright Header Begin ========================================== \ \ Hypervisor Software File: hacom.fth \ \ Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved. \ \ - Do no alter or remove copyright notices \ \ - Redistribution and use of this software in source and binary forms, with \ or without modification, are permitted provided that the following \ conditions are met: \ \ - Redistribution of source code must retain the above copyright notice, \ this list of conditions and the following disclaimer. \ \ - Redistribution in binary form must reproduce the above copyright notice, \ this list of conditions and the following disclaimer in the \ documentation and/or other materials provided with the distribution. \ \ Neither the name of Sun Microsystems, Inc. or the names of contributors \ may be used to endorse or promote products derived from this software \ without specific prior written permission. \ \ This software is provided "AS IS," without a warranty of any kind. \ ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, \ INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A \ PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN \ MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR \ ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR \ DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN \ OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR \ FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE \ DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, \ ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF \ SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. \ \ You acknowledge that this software is not designed, licensed or \ intended for use in the design, construction, operation or maintenance of \ any nuclear facility. \ \ ========== Copyright Header End ============================================ id: @(#)hacom.fth 1.2 07/07/05 purpose: Common code for SCSI host adapter drivers. copyright: Copyright 2007 Sun Microsystems, Inc. All Rights Reserved \ See license at end of file \ The following code is intended to be independent of the details of the \ SCSI hardware implementation. It is loaded after the hardware-dependent \ file that defines execute-command, set-address, open-hardware, etc. headers -1 value inq-buf \ Address of inquiry data buffer -1 value sense-buf \ holds extended error information 0 value #retries ( -- n ) \ number of times to retry SCSI transaction \ Classifies the sense condition as either okay (0), retryable (1), \ or non-retryable (-1) : classify-sense ( -- 0 | 1 | -1 ) debug? if base @ >r hex ." Sense: " sense-buf 11 bounds do i c@ 3 u.r loop ." ..." cr r> base ! then sense-buf \ Make sure we understand the error class code dup c@ h# 7f and h# 70 <> if drop -1 exit then \ Check for filemark, end-of-media, or illegal block length dup 2+ c@ h# e0 and if drop -1 exit then 2 + c@ h# f and ( sense-key ) \ no_sense(0) and recoverable(1) are okay dup 1 <= if drop 0 exit then ( sense-key ) \ not-ready(2) may be retryable dup 2 = if \ check for MEDIA NOT PRESENT: if the media's not there the \ command is not retryable. Unlike the legacy SCSI FCode, we \ don't look at the ASCQ field of the SENSE buffer since we \ want to fail for all ASCQ values when dealing with USB devices. drop sense-buf h# c + c@ h# 3a = if -1 else 1 then exit then \ Media-error(3) is not retryable dup 3 = if drop -1 exit then \ Attention(6), and target aborted (b) are retryable. dup 6 = swap 0b = or if 1 else -1 then ; 0 value open-count : $= ( $1 $2 -- flag ) rot tuck <> if 3drop false exit then comp 0= ; external : open ( -- flag ) my-args " debug" $= if debug-on then open-count if reopen-hardware dup if open-count 1+ to open-count then exit else open-hardware dup if 1 to open-count 100 dma-alloc to sense-buf 100 dma-alloc to inq-buf then then ; : close ( -- ) open-count 1- to open-count open-count if reclose-hardware else close-hardware inq-buf 100 dma-free sense-buf 100 dma-free then ; headers create sense-cmd 3 c, 0 c, 0 c, 0 c, ff c, 0 c, : get-sense ( -- ) \ Issue REQUEST SENSE, which is not supposed to fail sense-buf ff true sense-cmd 6 execute-command 0= if drop then ; \ Give the device a little time to recover before retrying the command. : delay-retry ( -- ) 2000 0 do loop ; 0 value statbyte \ Local variable used by retry? \ RETRY? is used by RETRY-COMMAND to determine whether or not to retry the \ command, considering the following factors: \ - Success or failure of the command at the hardware level (failure at \ this level is usually fatal, except in the case of an incoming bus reset) \ - The value of the status byte returned by the command \ - The condition indicated by the sense bytes \ - The number of previous retries \ \ The input arguments are as returned by "scsi-exec" \ On output, the top of the stack is true if the command is to be retried, \ otherwise the top of the stack is false and the results that should be \ returned by retry-command are underneath it; those results indicate the type \ of error that occurred. : retry? ( hw-result | statbyte 0 -- true | [[sensebuf] f-hw] error? false ) case 0 of to statbyte endof \ No hardware error; continue checking bus-reset of true exit endof \ Retry after incoming bus reset ( hw-result ) true false exit \ Other hardware errors are fatal endcase statbyte 0= if false false exit then \ If successful, return "no-error" statbyte 2 and if \ "Check Condition", so get extended status get-sense classify-sense case ( -1|0|1 ) \ If the sense information says "no sense", return "no-error" 0 of false false exit endof \ If the error is fatal, return "sense-buf,valid,statbyte" -1 of sense-buf false statbyte false exit endof endcase \ Otherwise, the error was retryable. However, if we have \ have already retried the specified number of times, don't \ retry again; instead return sense buffer and status. #retries 0= if sense-buf false statbyte false exit then then \ Don't retry if vendor-unique, reserved, intermediate, or \ "condition met/good" bits are set. Return "no-sense,status" statbyte h# f5 and if true statbyte false exit then \ Don't retry if we have already retried the specified number \ of times. Return "no-sense,status" #retries 0= if true statbyte false exit then \ Otherwise, it was either a busy or a retryable check condition, \ so we retry. true ; \ RETRY-COMMAND executes a SCSI command. If a check condition is indicated, \ performs a "get-sense" command. If the sense bytes indicate a non-fatal \ condition (e.g. power-on reset occurred, not ready yet, or recoverable \ error), the command is retried until the condition either goes away or \ changes to a fatal error. \ \ The command is retried until: \ a) The command succeeds, or \ b) The select fails, or dma fails, or \ c) The sense bytes indicate an error that we can't retry at this level \ d) The number of retries is exceeded. \ #retries is number of times to retry (0: don't retry, -1: retry forever) \ \ sensebuf is the address of the sense buffer; it is present only \ if f-hw is 0 and error? is non-zero. The length of the sense buffer \ is 8 bytes plus the value in byte 7 of the sense buffer. \ \ f-hw is non-zero if there is a hardware error -- dma fails, select fails, \ etc -- or if the status byte was neither 0 (okay) nor 2 (check condition) \ \ error? is non-zero if there is a transaction error. If error? is 0, \ f-hw and sensebuf are not returned. \ \ If sensebuf is returned, the contents are valid until the next call to \ retry-command. sensebuf becomes inaccessable when this package is closed. \ \ dma-dir is necessary because it is not always possible to infer the DMA \ direction from the command. \ Local variables used by retry-command? 0 instance value dbuf \ Data transfer buffer 0 instance value dlen \ Expected length of data transfer 0 instance value direction-in \ Direction for data transfer -1 instance value cbuf \ Command base address 0 instance value clen \ Actual length of this command external : retry-command ( dma-buf dma-len dma-dir cmdbuf cmdlen #retries -- ... ) ( ... -- [[sensebuf] f-hw] error? ) to #retries to clen to cbuf to direction-in to dlen to dbuf begin dbuf dlen direction-in cbuf clen execute-command ( hwerr | stat 0 ) retry? while #retries 1- to #retries delay-retry repeat ; headers \ Collapses the complete error information returned by retry-command into \ a single error/no-error flag. : error? ( false | true true | sensebuf false true -- error? ) dup if swap 0= if nip then then ; external \ Simplified "retry-command" routine for commands with no data transfer phase \ and simple error checking requirements. : no-data-command ( cmdbuf -- error? ) >r 0 0 true r> 6 -1 retry-command error? ; \ short-data-command executes a command with the following characteristics: \ a) The data direction is incoming \ b) The data length is less than 256 bytes \ The host adapter driver is responsible for supplying the DMA data \ buffer; if the command succeeds, the buffer address is returned. \ The buffer contents become invalid when another SCSI command is \ executed, or when the driver is closed. : short-data-command ( data-len cmdbuf cmdlen -- true | buffer false ) >r >r inq-buf swap true r> r> -1 retry-command ( retry-cmd-results ) error? dup 0= if inq-buf swap then ; headers \ Here begins the implementation of "show-children", a word that \ is intended to be executed interactively, showing the user the \ devices that are attached to the SCSI bus. \ Tool for storing a big-endian 24-bit number at an unaligned address : 3c! ( n addr -- ) >r lbsplit drop r@ c! r@ 1+ c! r> 2+ c! ; \ Command block template for Inquiry command create inquiry-cmd h# 12 c, 0 c, 0 c, 0 c, ff c, 0 c, external : inquiry ( -- error? ) \ 8 retries should be more than enough; inquiry commands aren't \ supposed to respond with "check condition". \ However, empirically, on MC2 EVT1, 8 proves insufficient. inq-buf ff true inquiry-cmd 6 10 retry-command error? ; headers \ Reads the indicated byte from the Inquiry data buffer : inq@ ( offset -- value ) inq-buf + c@ ; : .scsi1-inquiry ( -- ) inq-buf 5 ca+ 4 inq@ fa min type ; : .scsi2-inquiry ( -- ) inq-buf 8 ca+ d# 28 type ; \ Displays the results of an Inquiry command to the indicated device : show-lun ( unit -- ) \ SUN Note - scsi unit address is two cells (target, lun) dup 0 set-address ( unit ) inquiry if drop exit then ( unit ) 0 inq@ h# 60 and if drop exit then ( unit ) ." Unit " . ." " ( ) 1 inq@ h# 80 and if ." Removable " then ( ) 0 inq@ case ( ) 0 of ." Disk " endof 1 of ." Tape " endof 2 of ." Printer " endof 3 of ." Processor " endof 4 of ." WORM " endof 5 of ." Read Only device" endof ( default ) ." Device type " dup .h endcase ( ) 4 spaces 3 inq@ 0f and 2 = if .scsi2-inquiry else .scsi1-inquiry then cr ; external \ Searches for devices on the SCSI bus, displaying the Inquiry information \ for each device that responds. : show-children ( -- ) open 0= if ." Can't open SCSI host adapter" cr exit then max-lun 1+ 0 do i show-lun loop close ; \ Inquire into the specified scsi device type and return the scsi \ type and true if the device at the specified scsi address is found. : get-scsi-type ( lun -- false | type true ) open 0= if 2drop false exit then \ SUN Note - scsi unit address is two cells (target, lun) 0 set-address inquiry if false else 0 inq@ dup 7f = if drop false else true then then close ; headers \ The diagnose command is useful for generic SCSI devices. \ It executes bothe "test-unit-ready" and "send-diagnostic" \ commands, decoding the error status information they return. create test-unit-rdy-cmd 0 c, 0 c, 0 c, 0 c, 0 c, 0 c, create send-diagnostic-cmd h# 1d c, 4 c, 0 c, 0 c, 0 c, 0 c, : send-diagnostic ( -- error? ) send-diagnostic-cmd no-data-command ; external : diagnose ( -- flag ) 0 0 true test-unit-rdy-cmd 6 -1 ( dma$ dir cmd$ #retries ) retry-command if ( [ sensebuf ] hardware-error? ) ." Test unit ready failed - " ( [ sensebuf ] hardware-error? ) if ( ) ." hardware error (no such device?)" cr ( ) else ( sensebuf ) ." extended status = " cr ( sensebuf ) base @ >r hex ( sensebuf ) 8 bounds ?do i 3 u.r loop cr ( ) r> base ! then true else send-diagnostic ( fail? ) then ; headers \ LICENSE_BEGIN \ Copyright (c) 2006 FirmWorks \ \ Permission is hereby granted, free of charge, to any person obtaining \ a copy of this software and associated documentation files (the \ "Software"), to deal in the Software without restriction, including \ without limitation the rights to use, copy, modify, merge, publish, \ distribute, sublicense, and/or sell copies of the Software, and to \ permit persons to whom the Software is furnished to do so, subject to \ the following conditions: \ \ The above copyright notice and this permission notice shall be \ included in all copies or substantial portions of the Software. \ \ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, \ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF \ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND \ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE \ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION \ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION \ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ \ LICENSE_END