scsi2Lib.c
上传用户:nvosite88
上传日期:2007-01-17
资源大小:4983k
文件大小:130k
源码类别:

VxWorks

开发平台:

C/C++

  1. /* scsi2Lib.c - Small Computer System Interface (SCSI) library (SCSI-2) */
  2. /* Copyright 1989-2002 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /*
  5. modification history
  6. --------------------
  7. 04l,07mar02,pmr  SPR 73383: no division-by-zero in scsiTargetOptionsShow().
  8. 04k,16oct01,pmr  SPR 67310: turning off message-using options when messaging
  9.                  is turned off in scsiTargetOptionsSet().
  10. 04j,08oct01,rcs  tested for removable and medium not present in 
  11.                  scsiPhysDevCreate() SPR# 32203
  12. 04i,05oct01,rcs  added display of ASCQ (Additional Sense Code Qualifier) to 
  13.                  scsi2Transact() SCSI_DEBUG_MSGs. SPR# 29269  
  14. 04h,03oct01,rcs  clarified description of xferWidth in scsiTargetOptionsSet()
  15.                  SPR# 69003 
  16. 04g,26sep01,rcs  fixed scsi2PhysDevCreate() to use user specified `numBlocks' 
  17.                  or `blockSize' SPR# 22635
  18. 04f,26sep01,rcs  fixed scsiTargetOptionsSet() to allow for narrow width
  19.                  to be explicitly set for a narrow target. SPR# 28262 
  20. 04e,25sep01,rcs  added routine scsiTargetOptionsShow() SPR# 69223
  21. 04d,24sep01,rcs  set errno for MEDIUM ERROR, HARDWARE ERROR, ILLEGAL REQUEST, 
  22.                  BLANK CHECK, ABORTED COMMAND, and VOLUME OVERFLOW in switch
  23.                  statement in scsi2Transact(). SPR# 21236 
  24. 04c,05oct98,jmp  doc: cleanup.
  25. 04b,28aug97,dds  SPR 3425: "scsiFormatUnit" command, times out for disks which 
  26.                  take a long time to format.
  27. 04a,14aug97,dds  Rework of SPR 8219.
  28. 03z,28jul97,dds  SPR 8219: switching from synch to async mode cause target
  29.                  to hang.
  30. 03y,24jul97,dds  SPR 8323 / 7838: scsiTargetOptionsGet returns "xferWidth"
  31. 03x,10jul97,dds  added library support for adaptec chips.
  32. 03w,09jul97,dgp  doc: correct fonts per SPR 7853
  33. 03v,28mar97,dds  SPR 8220: added check for parity errors.
  34. 03u,28oct96,dgp  doc: editing for newly published SCSI libraries
  35. 03t,21oct96,dds  removed NOMANUAL for functions called from the 
  36.                  driver interface.
  37. 03s,14sep96,dds  removed the scsiMgr and scsiCtrl functions. These 
  38.                  functions are found in scsiMgrLib.c and scsiCtrlLib.c
  39. 03r,30jul96,jds  fixed scsiCacheSynchronize() to act on cache lines only
  40. 03q,29jul96,jds  added support for hardware snooping 
  41. 03p,06may96,jds  more doc tweaks
  42. 03o,01may96,jds  doc tweaks
  43. 03n,22apr96,jds  doc tweaks to describe WIDE transfers
  44. 03m,20apr96,jds  added WIDE data transfer support
  45. 03l,25jan96,jds  added scsiCtrl routine modifications based on SPARC/5390
  46. 03k,13nov95,jds  minor document changes
  47. 03j,08nov95,jds  more doc cleanup
  48. 03i,20sep95,jdi  doc cleanup.
  49. 03h,30aug95,jds  bug fixes and cleanup. Bugs include several instances where
  50.  function was returning with semaphore taken.
  51. 03g,26jul95,jds  added scsiReadBlockLimits in scsiPhysDevCreate for SEQ devs
  52. 03f,25jul95,jds  added support in scsiTransact for sequential devices. Created
  53.                  chkMedChangeAndWP (). Made appropriate changes in other
  54.  routines as well.e.g scsiPhysDevCreate ()
  55. 03e,19jul95,jds  removed all SCSI direct access commands and put them in 
  56.                  scsiDirectLib, also moved blkDev routines.
  57. 03d,21mar95,ihw  minor bug fixes in "scsiCtrl*()" routines
  58. 03c,07oct94,ihw  errno now set if sense data is unrecognised
  59.  error message logged if max number of threads is reached
  60. 03b,27may94,ihw  documented prior to release
  61. 03a,30mar94,ihw  modified for enhanced SCSI library: tagged command queueing
  62.                     major architectural changes ...
  63.                  ABORT rather than REJECT used to reject invalid reselection
  64.  removed redundant code for additional length in data in xfer
  65.  fixed incorrect handling of ext msg in with zero length byte
  66. 02b,25feb94,ihw  fixed synchronous transfer message-in diagnostics
  67. 02a,14jan94,ihw  modified for enhanced SCSI library: multiple initiators,
  68.               disconnect/reconnect and synchronous transfer supported
  69.  "scsiSyncXferNegotiate()" made non-local for NCR driver
  70. 01w,27nov92,jdi  documentation cleanup, including SPR 1415.
  71. 01v,15sep92,ccc  reworked select timeout, fixed extended message to work
  72.  with new drive, documentation changes.
  73. 01u,10aug92,ccc  added timeouts to scsiXaction for each scsi command.
  74. 01t,28jul92,rrr  fixed decl of scsiSyncTarget
  75. 01s,22jul92,gae  added correct number of parameters to logMsg().
  76. 01r,20jul92,eve  Remove conditional INCLUDE_SYNC_SCSI compilation.
  77. 01q,18jul92,smb  Changed errno.h to errnoLib.h.
  78. 01p,13jul92,eve  added init of the current pScsiXaction in scsiPhaseSequence().
  79. 01o,08jul92,eve  supplies a reqSense buffer if there is no user buffer 
  80.  in scsiTransact routine.
  81. 01n,03jul92,eve  added new sync feature with NOMANUAL
  82. 01m,26may92,rrr  the tree shuffle
  83. 01l,16dec91,gae  added includes for ANSI; added parameters to logMsg() calls.
  84. 01k,19nov91,rrr  shut up some ansi warnings.
  85. 01j,04oct91,rrr  passed through the ansification filter
  86.                   -changed functions to ansi style
  87.   -changed READ, WRITE and UPDATE to O_RDONLY O_WRONLY and ...
  88.   -changed VOID to void
  89.   -changed copyright notice
  90. 01i,13mar91,jcc  misc. clean-up and enhancements.
  91. 01h,25oct90,jcc  lint.
  92. 01g,18oct90,jcc  removed call to printErrno() in scsiAutoConfig().
  93. 01f,02oct90,jcc  UTINY became UINT8; added scsiAutoConfig(), scsiPhysDevIdGet(),
  94.  and scsiIoctl() option FIODISKFORMAT;
  95.  changed all malloc()'s to calloc()'s in xxCreate() routines;
  96.  made changes associated with SEM_ID's becoming SEMAPHORE's
  97.  in created structures;
  98.  enhanced scsiPhysDevCreate() to determine amount and type
  99.  of REQUEST SENSE data returned by the device; miscellaneous.
  100. 01e,10aug90,dnw  fixed warnings caused by changing scsiBusReset to VOIDFUNCPTR.
  101. 01d,18jul90,jcc  made semTake() calls 5.0 compatible; clean-up.
  102. 01c,08jun90,jcc  modified incoming message handling; generalized scsiTransact
  103.  calls to a procedure variable to allow off-board SCSI
  104.  controller drivers; documentation.
  105. 01b,23mar90,jcc  lint.
  106. 01a,05may89,jcc  written.
  107. */
  108. /*
  109. DESCRIPTION
  110. This library implements the Small Computer System Interface (SCSI)
  111. protocol in a controller-independent manner.  It implements only the SCSI
  112. initiator function as defined in the SCSI-2 ANSI specification. This library 
  113. does not support a VxWorks target acting as a SCSI target.
  114. The implementation is transaction based.  A transaction is defined as the
  115. selection of a SCSI device by the initiator, the issuance of a SCSI command,
  116. and the sequence of data, status, and message phases necessary to perform
  117. the command.  A transaction normally completes with a "Command Complete"
  118. message from the target, followed by disconnection from the SCSI bus.  If
  119. the status from the target is "Check Condition," the transaction
  120. continues; the initiator issues a "Request Sense" command to gain more
  121. information on the exception condition reported.
  122. Many of the subroutines in scsi2Lib facilitate the transaction of
  123. frequently used SCSI commands.  Individual command fields are passed as
  124. arguments from which SCSI Command Descriptor Blocks are constructed, and
  125. fields of a SCSI_TRANSACTION structure are filled in appropriately.  This
  126. structure, along with the SCSI_PHYS_DEV structure associated with the
  127. target SCSI device, is passed to the routine whose address is indicated by
  128. the 'scsiTransact' field of the SCSI_CTRL structure associated with the
  129. relevant SCSI controller. The above mentioned structures are defined in 
  130. scsi2Lib.h.
  131. The function variable 'scsiTransact' is set by the individual SCSI
  132. controller driver.  For off-board SCSI controllers, this
  133. routine rearranges the fields of the SCSI_TRANSACTION structure into
  134. the appropriate structure for the specified hardware, which then carries out
  135. the transaction through firmware control.  Drivers for an on-board
  136. SCSI-controller chip can use the scsiTransact() routine in scsiLib (which
  137. invokes the scsi2Transact() routine in scsi2Lib), as long as they provide the 
  138. other functions specified in the SCSI_CTRL structure.
  139. SCSI TRANSACTION TIMEOUT
  140. Associated with each transaction is a time limit (specified in microseconds,
  141. but measured with the resolution of the system clock).  If the transaction
  142. has not completed within this time limit, the SCSI library aborts it; the
  143. called routine fails with a corresponding error code.  The timeout period
  144. includes time spent waiting for the target device to become free to accept
  145. the command.
  146. The semantics of the timeout should guarantee that the caller waits no 
  147. longer than the transaction timeout period, but in practice this
  148. may depend on the state of the SCSI bus and the connected target device when
  149. the timeout occurs.  If the target behaves correctly according to the SCSI
  150. specification, proper timeout behavior results.  However, in certain
  151. unusual cases--for example, when the target does not respond to an asserted 
  152. ATN signal--the caller may remain blocked for longer than the timeout period.
  153. If the transaction timeout causes problems in your system, you can set the
  154. value of either or both the global variables "scsi{Min,Max}Timeout".  These
  155. specify (in microseconds) the global minimum and maximum timeout periods,
  156. which override (clip) the value specified for a transaction.  They may be
  157. changed at any time and affect all transactions issued after the new
  158. values are set.  The range of both these variable is 0 to 0xffffffff (zero to
  159. about 4295 seconds).
  160. SCSI TRANSACTION PRIORITY
  161. Each transaction also has an associated priority used by the SCSI
  162. library when selecting the next command to issue when the SCSI system is
  163. idle.  It chooses the highest priority transaction that can be dispatched
  164. on an available physical device.  If there are several equal-priority
  165. transactions available, the SCSI library uses a simple round-robin
  166. scheme to avoid favoring the same physical device.
  167. Priorities range from 0 (highest) to 255 (lowest), which is the same as task
  168. priorities.  The priority SCSI_THREAD_TASK_PRIORITY can be used to give the
  169. transaction the same priority as the calling task (this is the method used
  170. internally by this SCSI-2 library).
  171. SUPPORTED SCSI DEVICES
  172. This library requires peripherals that conform to the SCSI-2 ANSI
  173. standard; in particular, the INQUIRY, REQUEST SENSE, and
  174. TEST UNIT READY commands must be supported as specified by this standard.
  175. In general, the SCSI library is self-configuring to work with any device
  176. that meets these requirements.
  177. Peripherals that support identification and the SCSI message protocol are
  178. strongly recommended as these provide maximum performance.
  179. In theory, all classes of SCSI devices are supported.  The scsiLib library
  180. provides the capability to transact any SCSI command on any SCSI device
  181. through the FIOSCSICOMMAND function of the scsiIoctl() routine (which 
  182. invokes the scsi2Ioctl() routine in scsi2Lib).
  183. Only direct-access devices (disks) are supported by file systems like dosFs, 
  184. rt11Fs and rawFs. These file systems employ routines in 
  185. scsiDirectLib (most of which are described in scsiLib but defined in 
  186. scsiDirectLib). In the case of sequential-access devices (tapes), higher-level
  187. tape file systems, like tapeFs,  make use of scsiSeqLib. For other types of 
  188. devices, additional, higher-level software is necessary to map user-level
  189. commands to SCSI transactions.
  190. DISCONNECT/RECONNECT SUPPORT
  191. The target device can be disconnected from the SCSI bus while it carries
  192. out a SCSI command; in this way, commands to multiple SCSI devices can
  193. be overlapped to improve overall SCSI throughput.  There are no
  194. restrictions on the number of pending, disconnected commands or the
  195. order in which they are resumed.  The SCSI library serializes access to the
  196. device according to the capabilities and status of the device (see the
  197. following section).
  198. Use of the disconnect/reconnect mechanism is invisible to users of the SCSI
  199. library. It can be enabled and disabled separately for each target device
  200. (see scsiTargetOptionsSet()).  Note that support for disconnect/reconnect
  201. depends on the capabilities of the controller and its driver (see below).
  202. TAGGED COMMAND QUEUEING SUPPORT
  203. If the target device conforms to the ANSI SCSI-2 standard and indicates
  204. (using the INQUIRY command) that it supports command queuing, the SCSI
  205. library allows new commands to be started on the device whenever the SCSI
  206. bus is idle.  That is, it executes multiple commands concurrently on the
  207. target device.  By default, commands are tagged with a SIMPLE QUEUE TAG
  208. message.  Up to 256 commands can be executing concurrently.
  209. The SCSI library correctly handles contingent allegiance conditions that
  210. arise while a device is executing tagged commands.  (A contingent
  211. allegiance condition exists when a target device is maintaining sense data that
  212. the initiator should use to correctly recover from an error condition.)  It
  213. issues an untagged REQUEST SENSE command, and stops issuing tagged commands
  214. until the sense recovery command has completed.
  215. For devices that do not support command queuing, the SCSI library only
  216. issues a new command when the previous one has completed.  These devices
  217. can only execute a single command at once.
  218. Use of tagged command queuing is normally invisible to users of the SCSI
  219. library.  If necessary, the default tag type and maximum number of tags may
  220. be changed on a per-target basis, using scsiTargetOptionsSet().
  221. SYNCHRONOUS TRANSFER PROTOCOL SUPPORT
  222. If the SCSI controller hardware supports the synchronous transfer
  223. protocol, scsiLib negotiates with the target device to determine
  224. whether to use synchronous or asynchronous transfers.  Either VxWorks
  225. or the target device may start a round of negotiation.  Depending on the
  226. controller hardware, synchronous transfer rates up to the maximum allowed
  227. by the SCSI-2 standard (10 Mtransfers/second) can be used.
  228. Again, this is normally invisible to users of the SCSI library, but
  229. synchronous transfer parameters may be set or disabled on a per-target basis
  230. by using scsiTargetOptionsSet().
  231. WIDE DATA TRANSFER SUPPORT
  232. If the SCSI controller supports the wide data transfer protocol, scsiLib
  233. negotiates wide data transfer parameters with the target device, if
  234. that device also supports wide transfers. Either VxWorks or the target device
  235. may start a round of negotiation. Wide data transfer parameters are 
  236. negotiated prior to the synchronous data transfer parameters, as 
  237. specified by the SCSI-2 ANSI specification. In conjunction with
  238. synchronous transfer, up to a maximum of 20MB/sec. can be attained.
  239. Wide data transfer negotiation is invisible to users of this library,
  240. but it is possible to enable or disable wide data transfers and the
  241. parameters on a per-target basis by using scsiTargetOptionsSet().
  242. SCSI BUS RESET
  243. The SCSI library implements the ANSI "hard reset" option.  Any transactions
  244. in progress when a SCSI bus reset is detected fail with an error code
  245. indicating termination due to bus reset.  Any transactions waiting to start
  246. executing are then started normally.
  247. CONFIGURING SCSI CONTROLLERS
  248. The routines to create and initialize a specific SCSI controller are
  249. particular to the controller and normally are found in its library
  250. module.  The normal calling sequence is:
  251. .ne 4
  252. .CS
  253.     xxCtrlCreate (...); /@ parameters are controller specific @/
  254.     xxCtrlInit (...); /@ parameters are controller specific @/
  255. .CE
  256. The conceptual difference between the two routines is that xxCtrlCreate()
  257. calloc's memory for the xx_SCSI_CTRL data structure and initializes
  258. information that is never expected to change (for example, clock rate).  The
  259. remaining fields in the xx_SCSI_CTRL structure are initialized by
  260. xxCtrlInit() and any necessary registers are written on the SCSI
  261. controller to effect the desired initialization.  This routine can be
  262. called multiple times, although this is rarely required.  For example, the
  263. bus ID of the SCSI controller can be changed without rebooting the VxWorks
  264. system.
  265. CONFIGURING PHYSICAL SCSI DEVICES
  266. Before a device can be used, it must be "created," that is, declared.
  267. This is done with scsiPhysDevCreate() and can only be done after a
  268. SCSI_CTRL structure exists and has been properly initialized.
  269. .CS
  270. SCSI_PHYS_DEV *scsiPhysDevCreate
  271.     (
  272.     SCSI_CTRL * pScsiCtrl,/@ ptr to SCSI controller info @/
  273.     int  devBusId,   /@ device's SCSI bus ID @/
  274.     int  devLUN,   /@ device's logical unit number @/
  275.     int  reqSenseLength,  /@ length of REQUEST SENSE data dev returns @/
  276.     int  devType,   /@ type of SCSI device @/
  277.     BOOL removable,   /@ whether medium is removable @/
  278.     int  numBlocks,   /@ number of blocks on device @/
  279.     int  blockSize   /@ size of a block in bytes @/
  280.     )
  281. .CE
  282. Several of these parameters can be left unspecified, as follows:
  283. .iP <reqSenseLength>
  284. If 0, issue a REQUEST_SENSE to determine a request sense length.
  285. .iP <devType>
  286. This parameter is ignored: an INQUIRY command is used to ascertain the
  287. device type.  A value of NONE (-1) is the recommended placeholder.
  288. .iP "<numBlocks>, <blockSize>"
  289. If 0, issue a READ_CAPACITY to determine the number of blocks.
  290. .LP
  291. The above values are recommended, unless the device does not support the
  292. required commands, or other non-standard conditions prevail.
  293. LOGICAL PARTITIONS ON DIRECT-ACCESS BLOCK DEVICES
  294. It is possible to have more than one logical partition on a SCSI block
  295. device.  This capability is currently not supported for removable media
  296. devices.  A partition is an array of contiguously addressed blocks
  297. with a specified starting block address and specified number of blocks.
  298. The scsiBlkDevCreate() routine is called once for each block device
  299. partition.  Under normal usage, logical partitions should not overlap.
  300. .ne 8
  301. .CS
  302. SCSI_BLK_DEV *scsiBlkDevCreate
  303.     (
  304.     SCSI_PHYS_DEV *  pScsiPhysDev,  /@ ptr to SCSI physical device info @/
  305.     int              numBlocks,     /@ number of blocks in block device @/
  306.     int              blockOffset    /@ address of first block in volume @/
  307.     )
  308. .CE
  309. Note that if <numBlocks> is 0, the rest of the device is used.
  310. ATTACHING DISK FILE SYSTEMS TO LOGICAL PARTITIONS
  311. Files cannot be read or written to a disk partition until a file system (for
  312. example, dosFs, rt11Fs, or rawFs) has been initialized on the partition.
  313. For more information, see the relevant documentation in dosFsLib,
  314. rt11FsLib, or rawFsLib.
  315. USING A SEQUENTIAL-ACCESS BLOCK DEVICE
  316. The entire volume (tape) on a sequential-access block device is treated as 
  317. a single raw file. This raw file is made available to higher-level layers
  318. like tapeFs by the scsiSeqDevCreate() routine, described in scsiSeqLib. The
  319. scsiSeqDevCreate() routine is called once for a given SCSI physical 
  320. device.
  321. .CS
  322. SEQ_DEV *scsiSeqDevCreate
  323.     (
  324.     SCSI_PHYS_DEV *pScsiPhysDev  /@ ptr to SCSI physical device info @/
  325.     )
  326. .CE
  327. TRANSMITTING ARBITRARY COMMANDS TO SCSI DEVICES
  328. The scsi2Lib, scsiCommonLib, scsiDirectLib, and scsiSeqLib libraries 
  329. collectively provide routines that implement all mandatory SCSI-2 
  330. direct-access and sequential-access commands. Still, there are situations that
  331. require commands that are not supported by these libraries (for example, 
  332. writing software that needs to use an optional SCSI-2 command).
  333. Arbitrary commands are handled with the FIOSCSICOMMAND option to
  334. scsiIoctl().  The <arg> parameter for FIOSCSICOMMAND is a pointer to a
  335. valid SCSI_TRANSACTION structure.  Typically, a call to scsiIoctl() is written
  336. as a subroutine of the form:
  337. .CS
  338. STATUS myScsiCommand
  339.     (
  340.     SCSI_PHYS_DEV *  pScsiPhysDev,  /@ ptr to SCSI physical device     @/
  341.     char *      buffer,     /@ ptr to data buffer              @/
  342.     int      bufLength,     /@ length of buffer in bytes       @/
  343.     int      someParam     /@ param. specifiable in cmd block @/
  344.     )
  345.     {
  346.     SCSI_COMMAND myScsiCmdBlock; /@ SCSI command byte array @/
  347.     SCSI_TRANSACTION myScsiXaction; /@ info on a SCSI transaction @/
  348.     /@ fill in fields of SCSI_COMMAND structure @/
  349.     myScsiCmdBlock [0] = MY_COMMAND_OPCODE; /@ the required opcode @/
  350.     .
  351.     myScsiCmdBlock [X] = (UINT8) someParam; /@ for example @/
  352.     .
  353.     myScsiCmdBlock [N-1] = MY_CONTROL_BYTE; /@ typically == 0 @/
  354.     /@ fill in fields of SCSI_TRANSACTION structure @/
  355.     myScsiXaction.cmdAddress    = myScsiCmdBlock;
  356.     myScsiXaction.cmdLength     = <# of valid bytes in myScsiCmdBlock>;
  357.     myScsiXaction.dataAddress   = (UINT8 *) buffer;
  358.     myScsiXaction.dataDirection = <O_RDONLY (0) or O_WRONLY (1)>;
  359.     myScsiXaction.dataLength    = bufLength;
  360.     myScsiXaction.addLengthByte = 0;      /@ no longer used @/
  361.     myScsiXaction.cmdTimeout    = <timeout in usec>;
  362.     myScsiXaction.tagType       = SCSI_TAG_{DEFAULT,UNTAGGED,
  363.     SIMPLE,ORDERED,HEAD_OF_Q};
  364.     myScsiXaction.priority      = [ 0 (highest) to 255 (lowest) ];
  365.     if (scsiIoctl (pScsiPhysDev, FIOSCSICOMMAND, &myScsiXaction) == OK)
  366. return (OK);
  367.     else
  368.         /@ optionally perform retry or other action based on value of
  369.  *  myScsiXaction.statusByte
  370.  @/
  371. return (ERROR);
  372.     }
  373. .CE
  374. INCLUDE FILES
  375. scsiLib.h, scsi2Lib.h
  376. SEE ALSO: dosFsLib, rt11FsLib, rawFsLib, tapeFsLib, scsiLib, scsiCommonLib,
  377. scsiDirectLib, scsiSeqLib, scsiMgrLib, scsiCtrlLib,
  378. .I  "American National Standard for Information Systems - Small Computer" 
  379. .I  "System Interface (SCSI-2), ANSI X3T9,"
  380. .pG "I/O System, Local File Systems"
  381. */
  382. #define  INCLUDE_SCSI2
  383. #include "vxWorks.h"
  384. #include "ioLib.h"
  385. #include "intLib.h"
  386. #include "ctype.h"
  387. #include "cacheLib.h"
  388. #include "stdlib.h"
  389. #include "errnoLib.h"
  390. #include "taskLib.h"
  391. #include "lstLib.h"
  392. #include "logLib.h"
  393. #include "msgQLib.h"
  394. #include "string.h"
  395. #include "stdio.h"
  396. #include "sysLib.h"
  397. #include "scsiLib.h"
  398. #include "wdLib.h"
  399. /* globals */
  400. extern int scsiPhysDevMutexOptions;
  401. IMPORT BOOL scsiErrors; /* enable SCSI error messages */
  402. IMPORT BOOL scsiDebug; /* enable task level debug messages */
  403. IMPORT BOOL scsiIntsDebug; /* enable int level debug messages */
  404. int scsiCtrlMutexSemOptions = SEM_Q_PRIORITY |
  405.       SEM_INVERSION_SAFE |
  406.       SEM_DELETE_SAFE;
  407. int scsiMaxNumThreads       = SCSI_DEF_MAX_THREADS;
  408. int scsiAllocNumThreads     = SCSI_DEF_ALLOC_THREADS;
  409. UINT scsiMinTimeout         = SCSI_DEF_MIN_TIMEOUT;
  410. UINT scsiMaxTimeout         = SCSI_DEF_MAX_TIMEOUT;
  411. int scsiCacheFlushThreshold = SCSI_DEF_CACHE_FLUSH_THRESHOLD;
  412. UINT scsiTestUnitRdyTrys = 5;           /* Times to retry scsiTestUnitReady() */
  413. IMPORT SCSI_CTRL * pSysScsiCtrl; /* ptr to default SCSI_CTRL struct */
  414. VOID               scsiTargetReset (SCSI_CTRL * pScsiCtrl, UINT busId);
  415. VOID               scsiThreadListShow   (LIST * pList);
  416. VOID               scsiThreadListIdShow (LIST * pList);
  417. /* forward static functions */
  418. /* Backward compatability functions localised */
  419. LOCAL STATUS          scsi2CtrlInit (SCSI_CTRL *);
  420. LOCAL SCSI_PHYS_DEV * scsi2PhysDevIdGet (SCSI_CTRL *, int, int);
  421. LOCAL STATUS          scsi2PhysDevDelete (FAST SCSI_PHYS_DEV *);
  422. LOCAL SCSI_PHYS_DEV * scsi2PhysDevCreate (SCSI_CTRL *, int, int, int, int, BOOL,
  423.                                         int, int);
  424. LOCAL STATUS          scsi2AutoConfig (SCSI_CTRL *);
  425. LOCAL STATUS          scsi2Show (FAST SCSI_CTRL *);
  426. LOCAL STATUS          scsi2BusReset (SCSI_CTRL *);
  427. LOCAL STATUS          scsi2CmdBuild (SCSI_COMMAND, int *, UINT8, int, BOOL, int,
  428.                                                                 int, UINT8);
  429. LOCAL STATUS          scsi2Transact (SCSI_PHYS_DEV *, SCSI_TRANSACTION *);
  430. LOCAL STATUS          scsi2Ioctl (SCSI_PHYS_DEV *, int, int);
  431. LOCAL char *          scsi2PhaseNameGet (int);
  432. /* Miscellaneous support routines */
  433. LOCAL void          scsiTargetInit  (SCSI_CTRL * pScsiCtrl, UINT busId);
  434. LOCAL BOOL        strIsPrintable (char *pString);
  435. LOCAL UINT          scsiTimeoutCvt  (UINT uSecs);
  436. LOCAL SCSI_PRIORITY scsiPriorityCvt (UINT priority);
  437. LOCAL SCSI_THREAD * scsiThreadCreate (SCSI_PHYS_DEV    * pScsiPhysDev,
  438.       SCSI_TRANSACTION * pScsiXaction);
  439. LOCAL void          scsiThreadDelete (SCSI_THREAD * pThread);
  440. LOCAL SCSI_THREAD * scsiThreadAllocate (SCSI_CTRL * pScsiCtrl);
  441. LOCAL void          scsiThreadDeallocate (SCSI_CTRL * pScsiCtrl,
  442.   SCSI_THREAD * pThread);
  443. LOCAL char *        scsiThreadArrayCreate (SCSI_CTRL * pScsiCtrl, int nThreads);
  444. LOCAL STATUS        scsiThreadExecute (SCSI_THREAD * pThread);
  445. LOCAL STATUS        scsiCommand (SCSI_PHYS_DEV * pScsiPhysDev,
  446.  SCSI_TRANSACTION * pScsiXaction);
  447. LOCAL void      chkMedChangeAndWP (int addSenseCode, 
  448.   SCSI_PHYS_DEV * pScsiPhysDev);
  449. /* Imported functions from other scsi*Lib modules */
  450. IMPORT void scsiDirectLibTblInit ();
  451. IMPORT void scsiCommonLibTblInit ();
  452. /*******************************************************************************
  453. *
  454. * scsi2IfInit - initialize the SCSI-2 interface to scsiLib
  455. *
  456. * This routine initializes the SCSI-2 function interface by adding all the 
  457. * routines in scsi2Lib plus those in scsiDirectLib and scsiCommonLib. It is
  458. * invoked by usrConfig.c if the macro INCLUDE_SCSI2 is defined in
  459. * config.h.  The calling interface remains the same between SCSI-1 and SCSI-2;
  460. * this routine simply sets the calling interface function pointers to 
  461. * the SCSI-2 functions.
  462. *
  463. * RETURNS: N/A
  464. */
  465. void scsi2IfInit ()
  466.     {
  467.     /* Allocate memory for the interface table */
  468.     pScsiIfTbl = (SCSI_FUNC_TBL *) calloc (1,sizeof (SCSI_FUNC_TBL));
  469.     if (pScsiIfTbl == NULL)
  470. return;
  471.     /* Initialisation of functions in this module */
  472.     pScsiIfTbl->scsiCtrlInit      = (FUNCPTR) scsi2CtrlInit;
  473.     pScsiIfTbl->scsiPhaseNameGet  = (FUNCPTR) scsi2PhaseNameGet;
  474.     pScsiIfTbl->scsiPhysDevCreate = (FUNCPTR) scsi2PhysDevCreate;
  475.     pScsiIfTbl->scsiPhysDevDelete = (FUNCPTR) scsi2PhysDevDelete;
  476.     pScsiIfTbl->scsiPhysDevIdGet  = (FUNCPTR) scsi2PhysDevIdGet;
  477.     pScsiIfTbl->scsiAutoConfig    = (FUNCPTR) scsi2AutoConfig;
  478.     pScsiIfTbl->scsiShow          = (FUNCPTR) scsi2Show;
  479.     pScsiIfTbl->scsiBusReset      = (FUNCPTR) scsi2BusReset;
  480.     pScsiIfTbl->scsiCmdBuild      = (FUNCPTR) scsi2CmdBuild;
  481.     pScsiIfTbl->scsiTransact      = (FUNCPTR) scsi2Transact;
  482.     pScsiIfTbl->scsiIoctl         = (FUNCPTR) scsi2Ioctl;
  483.     /* Initialisation of functions in other modules */
  484.     scsiDirectLibTblInit ();
  485.     scsiCommonLibTblInit ();
  486.     }
  487. /*******************************************************************************
  488. *
  489. * scsi2CtrlInit - initialize generic fields of a SCSI_CTRL structure
  490. *
  491. * This routine should be called by the SCSI controller libraries' xxCtrlCreate
  492. * routines, which are responsible for initializing any fields not herein
  493. * initialized.  It is NOT intended to be called directly by a user.
  494. *
  495. * NOTE
  496. * As a matter of good practice, the SCSI_CTRL structure should be
  497. * calloc()'ed by the xxCtrlCreate() routine, so that all fields are
  498. * initially zero.  If this is done, some of the work of this routine will be
  499. * redundant.
  500. *
  501. * Many of the fields in the SCSI_CTRL structure are used to set up virtual
  502. * functions and configuration data for the controller drivers.  If these
  503. * fields are left set to zero, default values are used.  These values assume
  504. * that a bus-level controller driver is used in conjunction with the
  505. * generic thread-level driver in this source file (see "scsiCtrlxxx()").
  506. *
  507. * INTERNAL
  508. * This function is really initialising too many things and should probably
  509. * be broken into several functions such as: scsiMgrInit, scsiCtrlInit (i.e.
  510. * the "generic" controller), and an overall initialisation function that
  511. * can be called by a driver create routine, as the current routine is.
  512. *
  513. * RETURNS: OK, or ERROR if a semaphore creation fails.
  514. *
  515. * NOMANUAL
  516. */
  517. LOCAL STATUS scsi2CtrlInit
  518.     (
  519.     SCSI_CTRL * pScsiCtrl       /* ptr to SCSI_CTRL struct to initialize */
  520.     )
  521.     {
  522.     int ix; /* loop index */
  523.     /*
  524.      * Initialize virtual functions and configuration info.
  525.      *
  526.      * If the driver has left the default value (0), set to the values
  527.      * for the generic thread-level driver.
  528.      */
  529.     /* structure sizes */
  530.     
  531.     if (pScsiCtrl->eventSize == 0)
  532.      pScsiCtrl->eventSize = sizeof (SCSI_EVENT);
  533.     if (pScsiCtrl->threadSize == 0)
  534.      pScsiCtrl->threadSize = sizeof (SCSI_THREAD);
  535.     /* virtual functions bus-level driver */
  536.     if (pScsiCtrl->scsiTransact == 0)
  537.      pScsiCtrl->scsiTransact = scsiTransact;
  538.     if (pScsiCtrl->scsiEventProc == 0)
  539.      pScsiCtrl->scsiEventProc = scsiCtrlEvent;
  540.     if (pScsiCtrl->scsiThreadInit == 0)
  541.      pScsiCtrl->scsiThreadInit = scsiCtrlThreadInit;
  542.     if (pScsiCtrl->scsiThreadActivate == 0)
  543.      pScsiCtrl->scsiThreadActivate = scsiCtrlThreadActivate;
  544.     if (pScsiCtrl->scsiThreadAbort == 0)
  545.      pScsiCtrl->scsiThreadAbort = scsiCtrlThreadAbort;
  546.     
  547.     /* create controller mutual exclusion semaphore */
  548.     if ((pScsiCtrl->mutexSem = semMCreate (scsiCtrlMutexSemOptions)) == NULL)
  549.         {
  550.         printErr ("scsiCtrlInit: semMCreate of mutexSem failed.n");
  551.         goto failed;
  552.         }
  553.     /* create sync semaphore for controller events and client requests */
  554.     if ((pScsiCtrl->actionSem = semBCreate (scsiMgrActionSemOptions,
  555.     SEM_EMPTY)) == NULL)
  556.         {
  557.         printErr ("scsiCtrlInit: semBCreate of actionSem failed.n");
  558.         goto failed;
  559.         }
  560.     /* create ring buffers for controller events and client requests */
  561.     
  562.     if ((pScsiCtrl->eventQ = rngCreate (scsiMgrEventQSize *
  563. pScsiCtrl->eventSize)) == NULL)
  564. {
  565. printErr ("scsiCtrlInit: rngCreate of eventQ failedn");
  566.         goto failed;
  567. }
  568.     
  569.     if ((pScsiCtrl->timeoutQ = rngCreate (scsiMgrTimeoutQSize *
  570.   sizeof (SCSI_TIMEOUT))) == NULL)
  571. {
  572. printErr ("scsiCtrlInit: rngCreate of timeoutQ failedn");
  573.         goto failed;
  574. }
  575.     if ((pScsiCtrl->requestQ = rngCreate (scsiMgrRequestQSize *
  576.   sizeof (SCSI_REQUEST))) == NULL)
  577. {
  578. printErr ("scsiCtrlInit: rngCreate of requestQ failedn");
  579.         goto failed;
  580. }
  581.     if ((pScsiCtrl->replyQ = rngCreate (scsiMgrReplyQSize *
  582. sizeof (SCSI_REPLY))) == NULL)
  583. {
  584. printErr ("scsiCtrlInit: rngCreate of replyQ failedn");
  585.         goto failed;
  586. }
  587.     /* create thread used for incoming identification */
  588.     if ((pScsiCtrl->pIdentThread = scsiCtrlIdentThreadCreate (pScsiCtrl)) == 0)
  589. {
  590. printErr ("scsiCtrlInit: can't create identification thread.n");
  591. goto failed;
  592. }
  593.     /* initialize the list of free threads */
  594.     lstInit (&pScsiCtrl->freeThreads);
  595.     /* initialize support for disconnect and sync. xfer to yes */
  596.     /* (may be reset by driver) */
  597.     pScsiCtrl->disconnect = TRUE;
  598.     pScsiCtrl->syncXfer   = TRUE;
  599.     /* 
  600.      * The default behaviour is assumed to be to disallow wide transfers.
  601.      * However, this default can be modified by the controller driver and
  602.      * must be tested first.
  603.      */
  604.     if (pScsiCtrl->wideXfer != TRUE)
  605.         pScsiCtrl->wideXfer   = FALSE;
  606.     /* initialise controller state variables */
  607.     pScsiCtrl->active   = FALSE;
  608.     pScsiCtrl->nThreads = 0;
  609.     pScsiCtrl->pThread  = 0;
  610.     pScsiCtrl->nextDev  = 0;
  611.     pScsiCtrl->msgInState  = SCSI_MSG_IN_NONE;
  612.     pScsiCtrl->msgOutState = SCSI_MSG_OUT_NONE;
  613.     /* initialize array of target information */
  614.     for (ix = 0; ix < SCSI_MAX_TARGETS; ix++)
  615. {
  616. pScsiCtrl->targetArr [ix].scsiDevBusId = ix;
  617. scsiTargetInit (pScsiCtrl, ix);
  618. }
  619.     /* initialize array of ptrs to SCSI_PHYS_DEV structures to NULL */
  620.     for (ix = 0; ix < SCSI_MAX_PHYS_DEVS; ix++)
  621. {
  622. pScsiCtrl->physDevArr [ix] = (SCSI_PHYS_DEV *) NULL;
  623. }
  624.     /* by default hardware snooping is disabled */
  625.     pScsiCtrl->cacheSnooping = FALSE;
  626.     return (OK);
  627. failed:
  628.     if (pScsiCtrl->mutexSem != 0)
  629. (void) semDelete (pScsiCtrl->mutexSem);
  630.     if (pScsiCtrl->actionSem != 0)
  631. (void) semDelete (pScsiCtrl->actionSem);
  632.     if (pScsiCtrl->eventQ != 0)
  633. (void) rngDelete (pScsiCtrl->eventQ);
  634.     if (pScsiCtrl->timeoutQ != 0)
  635. (void) rngDelete (pScsiCtrl->timeoutQ);
  636.     if (pScsiCtrl->requestQ != 0)
  637. (void) rngDelete (pScsiCtrl->requestQ);
  638.     return (ERROR);
  639.     }
  640. /*******************************************************************************
  641. *
  642. * scsiTargetInit - initialise a SCSI target structure
  643. *
  644. * Set all per-target configurable parameters to their default values.
  645. * Initialise all the target's state variables.
  646. *
  647. * RETURNS: N/A
  648. *
  649. * NOMANUAL
  650. */
  651. LOCAL void scsiTargetInit
  652.     (
  653.     FAST SCSI_CTRL *pScsiCtrl, /* ptr to SCSI controller info   */
  654.     UINT busId /* SCSI bus ID of target to init */
  655.     )
  656.     {
  657.     FAST SCSI_TARGET *pScsiTarget = &pScsiCtrl->targetArr [busId];
  658.     
  659.     /* initialise options (also see "scsiTargetOptionsSet()") */
  660.     pScsiTarget->selTimeOut = SCSI_DEF_SELECT_TIMEOUT;
  661.     pScsiTarget->messages   = TRUE;
  662.     pScsiTarget->disconnect = TRUE;
  663.     pScsiTarget->xferOffset = SCSI_SYNC_XFER_ASYNC_OFFSET;
  664.     pScsiTarget->xferPeriod = SCSI_SYNC_XFER_ASYNC_PERIOD;
  665.     pScsiTarget->maxOffset  = SCSI_SYNC_XFER_MAX_OFFSET;
  666.     pScsiTarget->minPeriod  = SCSI_SYNC_XFER_MIN_PERIOD;
  667.     pScsiTarget->tagType    = SCSI_DEF_TAG_TYPE;
  668.     pScsiTarget->maxTags    = SCSI_MAX_TAGS;
  669.     if (pScsiCtrl->wideXfer)
  670.         pScsiTarget->xferWidth  = SCSI_WIDE_XFER_SIZE_DEFAULT;
  671.     else 
  672.         pScsiTarget->xferWidth  = SCSI_WIDE_XFER_SIZE_NARROW;
  673.     /* initialize wide / sync support for each target to be FALSE */
  674.     pScsiTarget->wideSupport   = FALSE;
  675.     pScsiTarget->syncSupport   = FALSE;
  676.     scsiTargetReset (pScsiCtrl, busId);
  677.     }
  678. /*******************************************************************************
  679. *
  680. * scsiTargetReset - reset the state of a SCSI target
  681. *
  682. * Reset the target's state variables, but do not change its configurable
  683. * parameters.  Typically called when a target is initialised, and when a
  684. * SCSI bus reset occurs.
  685. *
  686. * RETURNS: N/A
  687. *
  688. * NOMANUAL
  689. */
  690. VOID scsiTargetReset
  691.     (
  692.     FAST SCSI_CTRL *pScsiCtrl, /* ptr to SCSI controller info    */
  693.     UINT busId /* SCSI bus ID of target to reset */
  694.     )
  695.     {
  696.     FAST SCSI_TARGET *pScsiTarget = &pScsiCtrl->targetArr [busId];
  697.     
  698.     /* intialise synchronous transfer fsm */
  699.     scsiSyncXferNegotiate (pScsiCtrl, pScsiTarget, SYNC_XFER_RESET);
  700.     /* similarly, intialise the wide data transfer fsm */
  701.     scsiWideXferNegotiate (pScsiCtrl, pScsiTarget, WIDE_XFER_RESET);
  702.     }
  703. /*******************************************************************************
  704. *
  705. * scsiTargetOptionsSet - set options for one or all SCSI targets
  706. *
  707. * This routine sets the options defined by the bitmask `which' for the
  708. * specified target (or all targets if `devBusId' is SCSI_SET_OPT_ALL_TARGETS).
  709. *
  710. * The bitmask `which' can be any combination of the following, bitwise
  711. * OR'd together (corresponding fields in the SCSI_OPTIONS structure are
  712. * shown in parentheses):
  713. *
  714. * .TS
  715. * tab(|);
  716. * l l l.
  717. * SCSI_SET_OPT_TIMEOUT    | 'selTimeOut' | select timeout period, microseconds
  718. * SCSI_SET_OPT_MESSAGES   | 'messages'   | FALSE to disable SCSI messages
  719. *
  720. * SCSI_SET_OPT_DISCONNECT | 'disconnect' | FALSE to disable discon/recon
  721. *
  722. * SCSI_SET_OPT_XFER_PARAMS| 'maxOffset,' | max sync xfer offset, 0=>async
  723. *                         |  'minPeriod' | min sync xfer period, x 4 nsec.
  724. *
  725. * SCSI_SET_OPT_TAG_PARAMS | 'tagType,'   | default tag type (SCSI_TAG_*)
  726. *                         |  'maxTags'   | max cmd tags available
  727. *
  728. * SCSI_SET_OPT_WIDE_PARAMS| 'xferWidth'  | data transfer width setting.
  729. *    xferWidth = 0 ;  8 bits wide 
  730. *    xferWidth = 1 ; 16 bits wide
  731. *
  732. * .TE
  733. *
  734. * NOTE
  735. * This routine can be used after the target device has already been used; 
  736. * in this case, however, it is not possible to change the tag parameters. 
  737. * This routine must not be used while there is any SCSI activity on the 
  738. * specified target(s).
  739. *
  740. * RETURNS: OK, or ERROR if the bus ID or options are invalid.
  741. */
  742. STATUS scsiTargetOptionsSet
  743.     (
  744.     SCSI_CTRL    *pScsiCtrl, /* ptr to SCSI controller info   */
  745.     int           devBusId, /* target to affect, or all      */
  746.     SCSI_OPTIONS *pOptions, /* buffer containing new options */
  747.     UINT          which /* which options to change       */
  748.     )
  749.     {
  750.     int i;
  751.     /* verify bus ID of target, and validity of "which" bitmask */
  752.     
  753.     if (((devBusId < SCSI_MIN_BUS_ID) || (devBusId > SCSI_MAX_BUS_ID)) &&
  754. (devBusId != SCSI_SET_OPT_ALL_TARGETS))
  755. {
  756. errnoSet (S_scsiLib_ILLEGAL_BUS_ID);
  757. return (ERROR);
  758. }
  759.     if ((which & SCSI_SET_OPT_BITMASK) != which)
  760. {
  761. errnoSet (S_scsiLib_ILLEGAL_PARAMETER);
  762. return (ERROR);
  763. }
  764.     /* set options for one or all targets (loop is easiest approach) */
  765.     
  766.     for (i = 0; i < SCSI_MAX_TARGETS; ++i)
  767. {
  768. if ((devBusId == i) || (devBusId == SCSI_SET_OPT_ALL_TARGETS))
  769.     {
  770.     SCSI_TARGET *pScsiTarget = &pScsiCtrl->targetArr [i];
  771.     /* support for variable select timeout period (us) */
  772.     
  773.     if (which & SCSI_SET_OPT_TIMEOUT)
  774. pScsiTarget->selTimeOut = pOptions->selTimeOut;
  775.     /* support for messages (other than COMMAND COMPLETE) */
  776.     
  777.     if (which & SCSI_SET_OPT_MESSAGES)
  778. pScsiTarget->messages = pOptions->messages;
  779.     /* if messages are off, force options to SCSI-1 defaults */
  780.             if (!pScsiTarget->messages)
  781. {
  782. pScsiTarget->disconnect = FALSE; 
  783. pScsiTarget->maxOffset = 0;
  784. pScsiTarget->xferWidth = SCSI_WIDE_XFER_SIZE_NARROW; 
  785. }
  786.     /* support for disconnect / reconnect (requires messages) */
  787.     
  788.     if (which & SCSI_SET_OPT_DISCONNECT)
  789. {
  790. if (pOptions->disconnect &&
  791.     (!pScsiCtrl->disconnect || !pScsiTarget->messages))
  792.     {
  793.     errnoSet (S_scsiLib_ILLEGAL_PARAMETER);
  794.     return (ERROR);
  795.     }
  796. pScsiTarget->disconnect = pOptions->disconnect;
  797. }
  798.             
  799.     /* support for synchronous data transfer (requires messages) */
  800.     
  801.     if (which & SCSI_SET_OPT_XFER_PARAMS)
  802. {
  803. if ((pOptions->maxOffset != SCSI_SYNC_XFER_ASYNC_OFFSET) &&
  804.     (!pScsiCtrl->syncXfer || !pScsiTarget->messages)) 
  805.     {
  806.     errnoSet (S_scsiLib_ILLEGAL_PARAMETER);
  807.     return (ERROR);
  808.     }
  809.                 if (pOptions->minPeriod < 1)
  810.     {
  811.     errnoSet (S_scsiLib_ILLEGAL_PARAMETER);
  812.     return (ERROR);
  813.     }
  814. pScsiTarget->maxOffset = pOptions->maxOffset;
  815. pScsiTarget->minPeriod = pOptions->minPeriod;
  816.           /* re-intialise synchronous transfer fsm */
  817.           scsiSyncXferNegotiate (pScsiCtrl, pScsiTarget, SYNC_XFER_RESET);
  818. }
  819.     /* support for tagged commands (requires messages) */
  820.     
  821.     if (which & SCSI_SET_OPT_TAG_PARAMS)
  822. {
  823. BOOL valid;
  824. switch (pOptions->tagType)
  825.     {
  826.     case SCSI_TAG_UNTAGGED:
  827.      valid = (pOptions->maxTags == 0);
  828. break;
  829.     case SCSI_TAG_SIMPLE:
  830.     case SCSI_TAG_ORDERED:
  831.     case SCSI_TAG_HEAD_OF_Q:
  832. valid = pScsiTarget->messages    &&
  833.      (pOptions->maxTags >  0) &&
  834.         (pOptions->maxTags <= SCSI_MAX_TAGS);
  835. break;
  836.     default:
  837.      valid = FALSE;
  838. break;
  839.     }
  840. if (!valid)
  841.     {
  842.     errnoSet (S_scsiLib_ILLEGAL_PARAMETER);
  843.     return (ERROR);
  844.     }
  845.           pScsiTarget->tagType = pOptions->tagType;
  846. pScsiTarget->maxTags = pOptions->maxTags;
  847. }
  848.             /* support for wide data transfer (requires messages) */
  849.             if (which & SCSI_SET_OPT_WIDE_PARAMS)
  850.         {
  851. if (pOptions->xferWidth != SCSI_WIDE_XFER_SIZE_NARROW &&
  852.     pOptions->xferWidth != SCSI_WIDE_XFER_SIZE_DEFAULT) 
  853.     {
  854.     errnoSet (S_scsiLib_ILLEGAL_PARAMETER);
  855.     return (ERROR);
  856.     }
  857. if (pScsiTarget->messages)
  858.     {
  859.                     pScsiTarget->xferWidth = pOptions->xferWidth;
  860.                     /* re-initialise wide data xfer fsm */
  861.               scsiWideXferNegotiate (pScsiCtrl, pScsiTarget, 
  862.    WIDE_XFER_RESET);
  863.                     }
  864. else  
  865.     {
  866.     /* if messages off, only accept NARROW */
  867.     if (pOptions->xferWidth != SCSI_WIDE_XFER_SIZE_NARROW)
  868.         {
  869.         errnoSet (S_scsiLib_ILLEGAL_PARAMETER);
  870.         return (ERROR);
  871.         }
  872.                     }
  873. }
  874.     }
  875. }
  876.     
  877.     return (OK);
  878.     }
  879. /*******************************************************************************
  880. *
  881. * scsiTargetOptionsGet - get options for one or all SCSI targets
  882. *
  883. * This routine copies the current options for the specified target into the
  884. * caller's buffer.
  885. *
  886. * RETURNS: OK, or ERROR if the bus ID is invalid.
  887. */
  888. STATUS scsiTargetOptionsGet
  889.     (
  890.     SCSI_CTRL    *pScsiCtrl, /* ptr to SCSI controller info */
  891.     int           devBusId, /* target to interrogate       */
  892.     SCSI_OPTIONS *pOptions /* buffer to return options    */
  893.     )
  894.     {
  895.     SCSI_TARGET *pScsiTarget;
  896.     if ((devBusId < SCSI_MIN_BUS_ID) || (devBusId > SCSI_MAX_BUS_ID))
  897. {
  898. errnoSet (S_scsiLib_ILLEGAL_BUS_ID);
  899. return (ERROR);
  900. }
  901.     pScsiTarget = &pScsiCtrl->targetArr [devBusId];
  902.     pOptions->selTimeOut = pScsiTarget->selTimeOut;
  903.     pOptions->messages   = pScsiTarget->messages;
  904.     pOptions->disconnect = pScsiTarget->disconnect;
  905.     pOptions->maxOffset  = pScsiTarget->xferOffset;
  906.     pOptions->minPeriod  = pScsiTarget->xferPeriod;
  907.     pOptions->tagType    = pScsiTarget->tagType;
  908.     pOptions->maxTags    = pScsiTarget->maxTags;
  909.     pOptions->xferWidth  =  pScsiTarget->xferWidth;
  910.     return (OK);
  911.     }
  912. /*******************************************************************************
  913. *
  914. * scsiTargetOptionsShow - display options for specified SCSI target
  915. *
  916. * This routine displays the current target options for the specified target in
  917. * the following format:
  918. * Target Options (id <scsi bus ID>): 
  919. *     selection TimeOut: <timeout> nano secs
  920. *      messages allowed: TRUE or FALSE
  921. *    disconnect allowed: TRUE or FALSE
  922. *        REQ/ACK offset: <negotiated offset> 
  923. *       transfer period: <negotiated period> 
  924. *        transfer width: 8 or 16 bits
  925. * maximum transfer rate: <peak transfer rate> MB/sec
  926. *              tag type: <tag type>
  927. *          maximum tags: <max tags>
  928. *
  929. * RETURNS: OK, or ERROR if the bus ID is invalid.
  930. */
  931. STATUS scsiTargetOptionsShow
  932.     (
  933.     SCSI_CTRL    *pScsiCtrl, /* ptr to SCSI controller info */
  934.     int           devBusId /* target to interrogate       */
  935.     )
  936.     {
  937.     SCSI_OPTIONS options; /* buffer for returned options    */
  938.     if ((devBusId < SCSI_MIN_BUS_ID) || (devBusId > SCSI_MAX_BUS_ID))
  939. {
  940. errnoSet (S_scsiLib_ILLEGAL_BUS_ID);
  941. return (ERROR);
  942. }
  943.     if (scsiTargetOptionsGet (pScsiCtrl, devBusId, &options) == ERROR)
  944.         {
  945.         return (ERROR);
  946.         }
  947.     printf("Target Options (id %d):n", devBusId);
  948.     printf("     selection TimeOut: %d nano secsn", options.selTimeOut);
  949.     printf("      messages allowed: %sn", 
  950.                        (options.messages ? "TRUE" : "FALSE"));
  951.     printf("    disconnect allowed: %sn",
  952.                        (options.disconnect ? "TRUE" : "FALSE"));
  953.     printf("        REQ/ACK offset: %dn", options.maxOffset);
  954.     printf("       transfer period: %dn", (options.minPeriod * 4));
  955.     printf("        transfer width: %s bitsn", 
  956.                        (options.xferWidth ? "16" : "8"));
  957.     printf(" maximum transfer rate: %d MB/secn", 
  958.               (options.minPeriod == 0 ? 0 : (options.xferWidth ? 
  959.               (250 * 2 / options.minPeriod) : (250 / options.minPeriod))));
  960.     printf("              tag type: 0x%xn", options.tagType);
  961.     printf("          maximum tags: %dn", options.maxTags);
  962.     return (OK);
  963.     }
  964. /*******************************************************************************
  965. *
  966. * scsi2PhysDevDelete - delete a SCSI physical device structure
  967. *
  968. * This routine deletes a specified SCSI physical device structure.
  969. *
  970. * RETURNS: OK, or ERROR if `pScsiPhysDev' is NULL or SCSI_BLK_DEVs have
  971. * been created on the device.
  972. */
  973. LOCAL STATUS scsi2PhysDevDelete
  974.     (
  975.     FAST SCSI_PHYS_DEV *pScsiPhysDev    /* ptr to SCSI physical device info */
  976.     )
  977.     {
  978.     FAST SCSI_CTRL *pScsiCtrl;
  979.     if ((pScsiPhysDev == (SCSI_PHYS_DEV *) NULL)        ||
  980. (lstCount (&pScsiPhysDev->blkDevList)     != 0) ||
  981. (lstCount (&pScsiPhysDev->activeThreads)  != 0) ||
  982. (lstCount (&pScsiPhysDev->waitingThreads) != 0))
  983. return (ERROR);
  984.     pScsiCtrl = pScsiPhysDev->pScsiCtrl;
  985.     pScsiCtrl->physDevArr [(pScsiPhysDev->pScsiTarget->scsiDevBusId << 3) |
  986.    pScsiPhysDev->scsiDevLUN] = (SCSI_PHYS_DEV *) NULL;
  987.     if (pScsiPhysDev->pReqSenseData != NULL)
  988.         (void) free ((char *) pScsiPhysDev->pReqSenseData);
  989.     if (pScsiPhysDev->pTagInfo != 0)
  990. (void) free ((char *) pScsiPhysDev->pTagInfo);
  991.     if (pScsiPhysDev->mutexSem != 0)
  992. (void) semDelete (pScsiPhysDev->mutexSem);
  993.     (void) free ((char *) pScsiPhysDev);
  994.     return (OK);
  995.     }
  996. /*******************************************************************************
  997. *
  998. * scsi2PhysDevCreate - create a SCSI physical device structure
  999. *
  1000. * This routine enables access to a SCSI device and must be invoked first.
  1001. * It should be called once for each physical device on the SCSI bus.
  1002. *
  1003. * If `reqSenseLength' is specified as NULL (0), one or more REQUEST_SENSE
  1004. * commands are issued to the device to determine the number of bytes of
  1005. * sense data it typically returns.  Note that if the device returns variable
  1006. * amounts of sense data depending on its state, consult the device manual 
  1007. * to determine the maximum amount of sense data that can be returned.
  1008. *
  1009. * An INQUIRY command is issued to determine information about the device
  1010. * including its type, make and model number, and its ability to accept
  1011. * SCSI-2 features such as tagged commands.  The scsiShow() routine displays
  1012. * this information.
  1013. *
  1014. * If the type device is a Direct Access, a Write Once Read Multiple, or a
  1015. * Opticial Memory Device then a READ_CAPACITY command is issued to determine 
  1016. * the values of `numBlocks' and `blockSize'.  For these types of devices, 
  1017. * values passed into `numBlocks' and `blockSize' are ignored.
  1018. *
  1019. * For Sequential Access devices the values specified in  `numBlocks' and 
  1020. * `blockSize' are entered into the SCSI_PHYS_DEV structure.
  1021. *
  1022. * RETURNS: A pointer to the created SCSI_PHYS_DEV structure, or NULL if the
  1023. * routine is unable to create the physical device structure.
  1024. *
  1025. * NOTE: the `devType' and `removable' arguments are ignored.
  1026. */
  1027. LOCAL SCSI_PHYS_DEV *scsi2PhysDevCreate
  1028.     (
  1029.     SCSI_CTRL *pScsiCtrl,       /* ptr to SCSI controller info */
  1030.     int devBusId,               /* device's SCSI bus ID */
  1031.     int devLUN,                 /* device's logical unit number */
  1032.     int reqSenseLength,         /* length of REQUEST SENSE data dev returns */
  1033.     int devType,                /* type of SCSI device */
  1034.     BOOL removable,             /* whether medium is removable */
  1035.     int numBlocks,              /* number of blocks on device */
  1036.     int blockSize               /* size of a block in bytes */
  1037.     )
  1038.     {
  1039.     SCSI_PHYS_DEV *pScsiPhysDev; /* ptr to SCSI physical dev. struct */
  1040.     SCSI_TARGET   *pScsiTarget;      /* ptr to SCSI target structure */
  1041. /* REQ SENSE data for auto-sizing */
  1042.     UINT8 reqSenseData [REQ_SENSE_ADD_LENGTH_BYTE + 1];
  1043.     UINT8 inquiryData  [DEFAULT_INQUIRY_DATA_LENGTH];
  1044.     /* check bus ID and LUN are within limits */
  1045.     if ((devBusId < SCSI_MIN_BUS_ID) ||
  1046. (devBusId > SCSI_MAX_BUS_ID) ||
  1047. (devLUN < SCSI_MIN_LUN) ||
  1048. (devLUN > SCSI_MAX_LUN))
  1049. {
  1050. errnoSet (S_scsiLib_ILLEGAL_PARAMETER);
  1051. return ((SCSI_PHYS_DEV *) NULL);
  1052. }
  1053.     /* Check if this device was already created */
  1054.     if (scsiPhysDevIdGet (pScsiCtrl, devBusId, devLUN) != NULL)
  1055.         {
  1056.         errnoSet (S_scsiLib_DEVICE_EXIST);
  1057.         return ((SCSI_PHYS_DEV *) NULL);
  1058. }
  1059.     /* create a SCSI physical device structure */
  1060.     pScsiPhysDev = (SCSI_PHYS_DEV *) calloc (1, sizeof (*pScsiPhysDev));
  1061.     if (pScsiPhysDev == NULL)
  1062.         return ((SCSI_PHYS_DEV *) NULL);
  1063.     /* create device mutual exclusion semaphore */
  1064.     if ((pScsiPhysDev->mutexSem = semMCreate (scsiPhysDevMutexOptions)) == NULL)
  1065.         {
  1066.         SCSI_DEBUG_MSG ("scsiPhysDevCreate: semMCreate of mutexSem failed.n",
  1067. 0, 0, 0, 0, 0, 0);
  1068. goto failed;
  1069.         }
  1070.     /* initialize miscellaneous fields in the SCSI_PHYS_DEV struct */
  1071.     pScsiTarget = &pScsiCtrl->targetArr [devBusId];
  1072.     
  1073.     pScsiPhysDev->pScsiCtrl   = pScsiCtrl;
  1074.     pScsiPhysDev->pScsiTarget = pScsiTarget;
  1075.     pScsiPhysDev->scsiDevLUN  = devLUN;
  1076.     
  1077.     pScsiCtrl->physDevArr [(devBusId << 3) | devLUN] = pScsiPhysDev;
  1078.     /* initialize block device list */
  1079.     lstInit (&pScsiPhysDev->blkDevList);
  1080.     /* initialize sequential dev ptr */
  1081.     pScsiPhysDev->pScsiSeqDev = NULL;
  1082.     /* initialize lists of active and waiting threads */
  1083.     lstInit (&pScsiPhysDev->activeThreads);
  1084.     lstInit (&pScsiPhysDev->waitingThreads);
  1085.     /* initialize state variables */
  1086.     pScsiPhysDev->connected = FALSE;
  1087.     pScsiPhysDev->pendingCA = FALSE;
  1088.     pScsiPhysDev->curTag       = SCSI_TAG_NONE;
  1089.     pScsiPhysDev->nexus        = SCSI_NEXUS_NONE;
  1090.     pScsiPhysDev->savedNexus   = SCSI_NEXUS_NONE;
  1091.     pScsiPhysDev->nTaggedNexus = 0;
  1092.     
  1093.     /* initialise tags: do not use tags until after the INQUIRY command ! */
  1094.     pScsiPhysDev->tagType   = SCSI_TAG_UNTAGGED;
  1095.     pScsiPhysDev->nTags     = 0;
  1096.     pScsiPhysDev->pTagInfo  = 0;
  1097.     scsiMgrPhysDevTagInit (pScsiPhysDev);
  1098.     /*
  1099.      * Issue a Request Sense command to establish length of sense data,
  1100.      * if not specified by caller.
  1101.      */
  1102.     if (reqSenseLength != 0)
  1103. {
  1104. pScsiPhysDev->reqSenseDataLength = reqSenseLength;
  1105. if (reqSenseLength <= NON_EXT_SENSE_DATA_LENGTH)
  1106.     pScsiPhysDev->extendedSense = FALSE;
  1107. else
  1108.     pScsiPhysDev->extendedSense = TRUE;
  1109. }
  1110.     else
  1111. {
  1112.         /* determine if device uses Extended Sense Data Format */
  1113.         if (scsiReqSense (pScsiPhysDev, (char *) reqSenseData,
  1114.   REQ_SENSE_ADD_LENGTH_BYTE + 1) == ERROR)
  1115.     {
  1116.     SCSI_DEBUG_MSG ("scsiPhysDevCreate: REQUEST SENSE failed.n",
  1117.     0, 0, 0, 0, 0, 0);
  1118.     goto failed;
  1119.     }
  1120.         SCSI_DEBUG_MSG ("scsiPhysDevCreate: reqSenseData[0] = %xn",
  1121.         reqSenseData[0], 0, 0, 0, 0, 0);
  1122.         if ((reqSenseData[0] & SCSI_SENSE_DATA_CLASS) != SCSI_EXT_SENSE_CLASS)
  1123.     {
  1124.     /* device uses Nonextended Sense Data Format */
  1125.     pScsiPhysDev->extendedSense      = FALSE;
  1126.     pScsiPhysDev->reqSenseDataLength = NON_EXT_SENSE_DATA_LENGTH;
  1127.     }
  1128.         else if ((reqSenseData[0] & SCSI_SENSE_DATA_CODE) !=
  1129.   SCSI_EXT_SENSE_CODE)
  1130.     {
  1131.     /* device uses Unknown Sense Data Format */
  1132.     errnoSet (S_scsiLib_DEV_UNSUPPORTED);
  1133.     SCSI_DEBUG_MSG ("scsiPhysDevCreate: Unknown Sense Data Format ",
  1134.     0, 0, 0, 0, 0, 0);
  1135.     SCSI_DEBUG_MSG ("(device not supported)n", 0, 0, 0, 0, 0, 0);
  1136.     goto failed;
  1137.     }
  1138.         else
  1139.     {
  1140.     /* device uses Extended Sense Data Format */
  1141.     SCSI_DEBUG_MSG ("scsiPhysDevCreate: reqSenseData[7] = %xn",
  1142.     reqSenseData[REQ_SENSE_ADD_LENGTH_BYTE],
  1143.     0, 0, 0, 0, 0);
  1144.     pScsiPhysDev->extendedSense      = TRUE;
  1145.     pScsiPhysDev->reqSenseDataLength = REQ_SENSE_ADD_LENGTH_BYTE +
  1146.         (int) reqSenseData [REQ_SENSE_ADD_LENGTH_BYTE] + 1;
  1147.     }
  1148. }
  1149.     if ((pScsiPhysDev->pReqSenseData =
  1150. (UINT8 *) calloc (pScsiPhysDev->reqSenseDataLength,
  1151.   sizeof (UINT8))) == NULL)
  1152. {
  1153. goto failed;
  1154. }
  1155.     /*
  1156.      * Issue an INQUIRY command: retry while a reset condition persists
  1157.      */
  1158.     bzero ((char *) inquiryData, sizeof (inquiryData));
  1159.     while (scsiInquiry (pScsiPhysDev, (char *) inquiryData,
  1160.                sizeof  (inquiryData)) != OK)
  1161. {
  1162.      if (!pScsiPhysDev->resetFlag)
  1163.     goto failed;
  1164. pScsiPhysDev->resetFlag = FALSE;
  1165. SCSI_DEBUG_MSG ("retrying scsiInquiry...n", 0, 0, 0, 0, 0, 0);
  1166. }
  1167.     /*
  1168.      * The INQUIRY command was successful: is there a device on this LUN ?
  1169.      */
  1170.     if (inquiryData[SCSI_INQUIRY_DEV_TYPE] == SCSI_LUN_NOT_PRESENT)
  1171. {
  1172. SCSI_DEBUG_MSG ("scsiPhysDevCreate: LUN not present.n",
  1173. 0, 0, 0, 0, 0, 0);
  1174. errnoSet (S_scsiLib_LUN_NOT_PRESENT);
  1175. goto failed;
  1176. }
  1177.     /*
  1178.      * There is a supported device on this LUN
  1179.      */
  1180.     {
  1181.     int  devType      = inquiryData[SCSI_INQUIRY_DEV_TYPE] &
  1182.                    SCSI_INQUIRY_DEV_TYPE_MASK;
  1183.     
  1184.     BOOL removable    = inquiryData[SCSI_INQUIRY_DEV_MODIFIER] &
  1185.                             SCSI_INQUIRY_REMOVABLE_MASK;
  1186.     
  1187.     int  ansiVersion  = inquiryData[SCSI_INQUIRY_VERSION] &
  1188.                             SCSI_INQUIRY_ANSI_VSN_MASK;
  1189.     
  1190.     BOOL supportsTags = inquiryData[SCSI_INQUIRY_FLAGS] &
  1191.                             SCSI_INQUIRY_CMD_QUEUE_MASK;
  1192.     BOOL syncSupport  = inquiryData[SCSI_INQUIRY_FLAGS] & 0x10;
  1193.     BOOL wideSupport  = (inquiryData[SCSI_INQUIRY_FLAGS] & 
  1194.                          SCSI_INQUIRY_WIDE_16_MASK) |
  1195.                         (inquiryData[SCSI_INQUIRY_FLAGS] & 
  1196.                          SCSI_INQUIRY_WIDE_32_MASK);
  1197.     /* 
  1198.      * set the appropriate fields to indicate if the target
  1199.      * supports wide / synchronous transfers.
  1200.      */
  1201.     pScsiTarget->wideSupport   = wideSupport;
  1202.     pScsiTarget->syncSupport   = syncSupport;
  1203.     
  1204.     pScsiPhysDev->scsiDevType = devType;
  1205.     
  1206.     pScsiPhysDev->removable   = removable;
  1207.     pScsiPhysDev->tagType = (ansiVersion >= 2) && supportsTags
  1208.             ? pScsiTarget->tagType
  1209.   : SCSI_TAG_UNTAGGED;
  1210.     pScsiPhysDev->nTags   = (pScsiPhysDev->tagType != SCSI_TAG_UNTAGGED)
  1211.             ? pScsiTarget->maxTags
  1212.   : 0;
  1213.     if (pScsiPhysDev->nTags != 0)
  1214. {
  1215. /*
  1216.  *  Allocate tag info. table; re-initialise tag system
  1217.  */
  1218. if ((pScsiPhysDev->pTagInfo = malloc (pScsiPhysDev->nTags *
  1219.       sizeof (SCSI_TAG_INFO))) == 0)
  1220.     {
  1221.     SCSI_DEBUG_MSG ("scsiPhysDevCreate: can't allocate tag info.n",
  1222.     0, 0, 0, 0, 0, 0);
  1223.     goto failed;
  1224.     }
  1225. scsiMgrPhysDevTagInit (pScsiPhysDev);
  1226. }
  1227.     
  1228.     /*
  1229.      *  Save product info. strings in physical device structure
  1230.      */
  1231.     bcopy ((char *) &inquiryData[SCSI_INQUIRY_VENDOR_ID],
  1232.    pScsiPhysDev->devVendorID,
  1233.    SCSI_INQUIRY_VENDOR_ID_LENGTH);
  1234.     
  1235.     bcopy ((char *) &inquiryData[SCSI_INQUIRY_PRODUCT_ID],
  1236.    pScsiPhysDev->devProductID,
  1237.    SCSI_INQUIRY_PRODUCT_ID_LENGTH);
  1238.     
  1239.     bcopy ((char *) &inquiryData[SCSI_INQUIRY_REV_LEVEL],
  1240.    pScsiPhysDev->devRevLevel,
  1241.    SCSI_INQUIRY_REV_LEVEL_LENGTH);
  1242.     
  1243.     pScsiPhysDev->devVendorID  [SCSI_INQUIRY_VENDOR_ID_LENGTH]  = EOS;
  1244.     pScsiPhysDev->devProductID [SCSI_INQUIRY_PRODUCT_ID_LENGTH] = EOS;
  1245.     pScsiPhysDev->devRevLevel  [SCSI_INQUIRY_REV_LEVEL_LENGTH]  = EOS;
  1246.     }
  1247.     /* record numBlocks and blockSize in physical device */
  1248.     if ((pScsiPhysDev->scsiDevType == SCSI_DEV_DIR_ACCESS) ||
  1249.       (pScsiPhysDev->scsiDevType == SCSI_DEV_WORM) ||
  1250.       (pScsiPhysDev->scsiDevType == SCSI_DEV_RO_DIR_ACCESS)) 
  1251.         {     
  1252. int lastLogBlkAdrs;
  1253. int blkLength;
  1254.         /*
  1255.  * Issue a READ_CAPACITY command: retry while reset condition occurs
  1256.  */
  1257. while (scsiReadCapacity (pScsiPhysDev, &lastLogBlkAdrs, &blkLength) 
  1258.        != OK)
  1259.          {
  1260.             /* Test for removable & additional sense code MEDIUM NOT PRESENT */ 
  1261.             if (pScsiPhysDev->removable && 
  1262.                 (pScsiPhysDev->lastAddSenseCode == SCSI_ADD_SENSE_NO_MEDIUM))
  1263.                 {
  1264.         pScsiPhysDev->numBlocks = 0;
  1265.         pScsiPhysDev->blockSize = 0;
  1266.                 break;
  1267.                 }
  1268.             else
  1269.                 {      
  1270.         /* if command failed, then the device must have been reset */
  1271.         if (!pScsiPhysDev->resetFlag)
  1272.             goto failed;
  1273.     
  1274.         pScsiPhysDev->resetFlag = FALSE;
  1275.         SCSI_DEBUG_MSG ("retrying scsiReadCapacity...n",
  1276.                     0, 0, 0, 0, 0, 0);
  1277.                 }
  1278.     }
  1279.     pScsiPhysDev->numBlocks = lastLogBlkAdrs + 1;
  1280.     pScsiPhysDev->blockSize = blkLength;
  1281.         }
  1282.     else if (pScsiPhysDev->scsiDevType == SCSI_DEV_SEQ_ACCESS)
  1283.         {
  1284. int    pMaxBlockLength;     /* where to return maximum block length */
  1285. UINT16 pMinBlockLength;
  1286.         while (scsiReadBlockLimits (pScsiPhysDev, &pMaxBlockLength, 
  1287.         &pMinBlockLength) != OK)
  1288.     {
  1289.     /* if the command failed, then the device must have been reset */
  1290.     if (!pScsiPhysDev->resetFlag)
  1291.         goto failed;
  1292.             pScsiPhysDev->resetFlag = FALSE;
  1293.     SCSI_DEBUG_MSG ("retrying scsiReadBlockLimits...n", 
  1294. 0, 0, 0, 0, 0, 0);
  1295.     }
  1296.         pScsiPhysDev->maxVarBlockLimit = pMaxBlockLength;
  1297.         /* for sequential access devices, these fields are not used */
  1298. pScsiPhysDev->numBlocks = numBlocks;
  1299. pScsiPhysDev->blockSize = blockSize;
  1300.         }
  1301.     return (pScsiPhysDev);
  1302. failed:
  1303.     if (pScsiPhysDev->mutexSem != 0)
  1304. (void) semDelete (pScsiPhysDev->mutexSem);
  1305.     if (pScsiPhysDev->pTagInfo != 0)
  1306. (void) free ((char *) pScsiPhysDev->pTagInfo);
  1307.     if (pScsiPhysDev->pReqSenseData != 0)
  1308. (void) free ((char *) pScsiPhysDev->pReqSenseData);
  1309.     (void) free ((char *) pScsiPhysDev);
  1310.     pScsiCtrl->physDevArr [(devBusId << 3) | devLUN] = NULL;
  1311.     return (NULL);
  1312.     }
  1313. /*******************************************************************************
  1314. *
  1315. * scsi2PhysDevIdGet - return a pointer to a SCSI_PHYS_DEV structure
  1316. *
  1317. * This routine returns a pointer to the SCSI_PHYS_DEV structure of the SCSI
  1318. * physical device located at a specified bus ID (`devBusId') and logical
  1319. * unit number (`devLUN') and attached to a specified SCSI controller
  1320. * (`pScsiCtrl').
  1321. *
  1322. * RETURNS: A pointer to the specified SCSI_PHYS_DEV structure, or NULL if the
  1323. * structure does not exist.
  1324. */
  1325. LOCAL SCSI_PHYS_DEV * scsi2PhysDevIdGet
  1326.     (
  1327.     SCSI_CTRL *pScsiCtrl,       /* ptr to SCSI controller info */
  1328.     int devBusId,               /* device's SCSI bus ID */
  1329.     int devLUN                  /* device's logical unit number */
  1330.     )
  1331.     {
  1332.     /* check for valid ptr to SCSI_CTRL */
  1333.     if (pScsiCtrl == NULL)
  1334. {
  1335. if (pSysScsiCtrl != NULL)
  1336.     pScsiCtrl = pSysScsiCtrl;
  1337. else
  1338.     {
  1339.     errnoSet (S_scsiLib_NO_CONTROLLER);
  1340.     SCSI_DEBUG_MSG ("No SCSI controller specified.n",
  1341.     0, 0, 0, 0, 0, 0);
  1342.     return ((SCSI_PHYS_DEV *) NULL);
  1343.     }
  1344. }
  1345.     return (pScsiCtrl->physDevArr [(devBusId << 3) | devLUN]);
  1346.     }
  1347. /*******************************************************************************
  1348. *
  1349. * scsi2AutoConfig - configure all devices connected to a SCSI controller
  1350. *
  1351. * This routine cycles through all legal SCSI bus IDs (and logical unit
  1352. * numbers (LUNs)), attempting a scsiPhysDevCreate() with default parameters
  1353. * on each.  All devices which support the INQUIRY routine are
  1354. * configured.  The scsiShow() routine can be used to find the system's table
  1355. * of SCSI physical devices attached to a specified SCSI controller.  In
  1356. * addition, scsiPhysDevIdGet() can be used programmatically to get a
  1357. * pointer to the SCSI_PHYS_DEV structure associated with the device at a
  1358. * specified SCSI bus ID and LUN.
  1359. *
  1360. * RETURNS: OK, or ERROR if `pScsiCtrl' and `pSysScsiCtrl' are both NULL.
  1361. */
  1362. LOCAL STATUS scsi2AutoConfig
  1363.     (
  1364.     SCSI_CTRL *pScsiCtrl       /* ptr to SCSI controller info */
  1365.     )
  1366.     {
  1367.     int busId, lun; /* loop indices */
  1368.     SCSI_PHYS_DEV *pScsiPhysDev; /* ptr to SCSI physical device info */
  1369.     /* check for valid input parameters */
  1370.     if (pScsiCtrl == (SCSI_CTRL *) NULL)
  1371. {
  1372. if (pSysScsiCtrl == (SCSI_CTRL *) NULL)
  1373.     {
  1374.     errnoSet (S_scsiLib_NO_CONTROLLER);
  1375.     printErr ("No SCSI controller specified.n");
  1376.     return (ERROR);
  1377.     }
  1378. pScsiCtrl = pSysScsiCtrl;
  1379. }
  1380.     /* loop through all SCSI bus ID's and LUN's (logical units); if a given
  1381.      * bus ID times out during selection, do not test for other LUN's at
  1382.      * that bus ID, since there cannot be any.
  1383.      */
  1384.     for (busId = SCSI_MIN_BUS_ID; busId <= SCSI_MAX_BUS_ID; busId++)
  1385. {
  1386. if (busId != pScsiCtrl->scsiCtrlBusId)
  1387.     {
  1388.             for (lun = SCSI_MIN_LUN; lun <= SCSI_MAX_LUN; lun++)
  1389.         {
  1390. SCSI_DEBUG_MSG ("scsiAutoConfig: bus ID = %d, LUN = %dn",
  1391.         busId, lun, 0, 0, 0, 0);
  1392.         if ((pScsiPhysDev = scsiPhysDevCreate
  1393. (pScsiCtrl, busId, lun, 0, NONE, 0,
  1394.  0, 0)) == (SCSI_PHYS_DEV *) NULL)
  1395.     {
  1396.     if (errnoGet () == S_scsiLib_SELECT_TIMEOUT)
  1397.         break;
  1398.     }
  1399.         }
  1400.     }
  1401. }
  1402.     return (OK);
  1403.     }
  1404. /*******************************************************************************
  1405. *
  1406. * strIsPrintable - determine whether a string contains all printable chars
  1407. *
  1408. * RETURNS: TRUE | FALSE.
  1409. */
  1410. LOCAL BOOL strIsPrintable
  1411.     (
  1412.     FAST char *pString          /* ptr to string to be tested */
  1413.     )
  1414.     {
  1415.     FAST char ch;
  1416.     while ((ch = *pString++) != EOS)
  1417. {
  1418. if (!isprint (ch))
  1419.     return (FALSE);
  1420. }
  1421.     return (TRUE);
  1422.     }
  1423. /*******************************************************************************
  1424. *
  1425. * scsi2Show - list the physical devices attached to a SCSI controller
  1426. *
  1427. * This routine displays the SCSI bus ID, logical unit number (LUN), vendor ID,
  1428. * product ID, firmware revision (rev.), device type, number of blocks,
  1429. * block size in bytes, and a pointer to the associated SCSI_PHYS_DEV
  1430. * structure for each physical SCSI device known to be attached to a specified
  1431. * SCSI controller.
  1432. *
  1433. * NOTE:
  1434. * If `pScsiCtrl' is NULL, the value of the global variable `pSysScsiCtrl'
  1435. * is used, unless it is also NULL.
  1436. *
  1437. * RETURNS: OK, or ERROR if both `pScsiCtrl' and `pSysScsiCtrl' are NULL.
  1438. */
  1439. LOCAL STATUS scsi2Show
  1440.     (
  1441.     FAST SCSI_CTRL *pScsiCtrl           /* ptr to SCSI controller info */
  1442.     )
  1443.     {
  1444.     FAST SCSI_PHYS_DEV *pScsiPhysDev; /* SCSI physical device info */
  1445.     FAST int ix; /* loop variable */
  1446.     if (pScsiCtrl == NULL)
  1447. {
  1448. if (pSysScsiCtrl != NULL)
  1449.     pScsiCtrl = pSysScsiCtrl;
  1450. else
  1451.     {
  1452.     errnoSet (S_scsiLib_NO_CONTROLLER);
  1453.     SCSI_DEBUG_MSG ("No SCSI controller specified.n",
  1454.     0, 0, 0, 0, 0, 0);
  1455.     return (ERROR);
  1456.     }
  1457. }
  1458.     printf ("ID LUN VendorID    ProductID     Rev. ");
  1459.     printf ("Type  Blocks  BlkSize pScsiPhysDev n");
  1460.     printf ("-- --- -------- ---------------- ---- ");
  1461.     printf ("---- -------- ------- ------------n");
  1462.     for (ix = 0; ix < SCSI_MAX_PHYS_DEVS; ix++)
  1463. if ((pScsiPhysDev = pScsiCtrl->physDevArr[ix]) !=
  1464.     (SCSI_PHYS_DEV *) NULL)
  1465.     {
  1466.     printf ("%2d " , pScsiPhysDev->pScsiTarget->scsiDevBusId);
  1467.     printf ("%2d " , pScsiPhysDev->scsiDevLUN);
  1468.     printf (" %8s" , strIsPrintable (pScsiPhysDev->devVendorID) ?
  1469.      pScsiPhysDev->devVendorID : "        ");
  1470.     printf (" %16s", strIsPrintable (pScsiPhysDev->devProductID) ?
  1471.      pScsiPhysDev->devProductID : "                ");
  1472.     printf (" %4s ", strIsPrintable (pScsiPhysDev->devRevLevel) ?
  1473.      pScsiPhysDev->devRevLevel : "    ");
  1474.     printf ("%3d"  , pScsiPhysDev->scsiDevType);
  1475.     printf (pScsiPhysDev->removable ? "R" : " ");
  1476.     printf (" %8d " , pScsiPhysDev->numBlocks);
  1477.     printf (" %5d " , pScsiPhysDev->blockSize);
  1478.     printf ("   0x%08x ", (int) pScsiPhysDev);
  1479.     printf ("n");
  1480.     }
  1481.     return (OK);
  1482.     }
  1483. /*******************************************************************************
  1484. *
  1485. * scsiThreadShow - show information for a SCSI thread
  1486. *
  1487. * Display the role, priority, tag type (and number, if appropriate) and
  1488. * state of a SCSI thread.  May be called at any time, but note that the
  1489. * state is a "snapshot".
  1490. *
  1491. * RETURNS: N/A
  1492. *
  1493. * NOMANUAL
  1494. */
  1495. void scsiThreadShow
  1496.     (
  1497.     SCSI_THREAD * pThread, /* thread to be displayed  */
  1498.     BOOL          noHeader /* do not print title line */
  1499.     )
  1500.     {
  1501.     char * role;
  1502.     char * tagType;
  1503.     char * state;
  1504.     
  1505.     switch (pThread->role)
  1506. {
  1507. case SCSI_ROLE_INITIATOR:  role = "init"; break;
  1508. case SCSI_ROLE_TARGET:     role = "targ"; break;
  1509. case SCSI_ROLE_IDENT_INIT: role = "id-i"; break;
  1510. case SCSI_ROLE_IDENT_TARG: role = "id-t"; break;
  1511. default:                   role = "????"; break;
  1512. }
  1513.     switch (pThread->tagType)
  1514. {
  1515. case SCSI_TAG_DEFAULT:    tagType = "default";  break;
  1516. case SCSI_TAG_UNTAGGED:       tagType = "untagged"; break;
  1517. case SCSI_TAG_SENSE_RECOVERY: tagType = "recovery"; break;
  1518. case SCSI_TAG_SIMPLE:         tagType = "simple";   break;
  1519. case SCSI_TAG_ORDERED:        tagType = "ordered";  break;
  1520. case SCSI_TAG_HEAD_OF_Q:      tagType = "queue hd"; break;
  1521. default:                      tagType = "????????"; break;
  1522. }
  1523.     switch (pThread->state)
  1524. {
  1525.      case SCSI_THREAD_INACTIVE:     state = "inact"; break;
  1526. case SCSI_THREAD_WAITING:      state = "wait";  break;
  1527. case SCSI_THREAD_DISCONNECTED: state = "disc."; break;
  1528. default:                       state = "conn."; break;
  1529. }
  1530.     
  1531.     if (!noHeader)
  1532. {
  1533.      printf ("Thread  ID  PhysDev ID  Role  Pri  Tag Type  (#)   Staten");
  1534.      printf ("----------  ----------  ----  ---  --------------  -----n");
  1535. }
  1536.     printf ("0x%08x  0x%08x  %4s  %3d  %-8s (%3d)  %5sn",
  1537.     (int) pThread,
  1538.     (int) pThread->pScsiPhysDev,
  1539.     role,
  1540.     pThread->priority,
  1541.     tagType,
  1542.     pThread->tagNumber,
  1543.     state);
  1544.     }
  1545. /*******************************************************************************
  1546. *
  1547. * scsiPhysDevShow - show status information for a physical device
  1548. *
  1549. * This routine shows the state, the current nexus type, the current tag
  1550. * number, the number of tagged commands in progress, and the number of
  1551. * waiting and active threads for a SCSI physical device.  Optionally, it shows
  1552. * the IDs of waiting and active threads, if any.  This routine may be called
  1553. * at any time, but note that all of the information displayed is volatile.
  1554. *
  1555. * RETURNS: N/A
  1556. */
  1557. void scsiPhysDevShow
  1558.     (
  1559.     SCSI_PHYS_DEV * pScsiPhysDev, /* physical device to be displayed */
  1560.     BOOL            showThreads,     /* show IDs of associated threads  */
  1561.     BOOL            noHeader /* do not print title line         */
  1562.     )
  1563.     {
  1564.     char * nexus;
  1565.     char * state;
  1566.     int    nWaiting = lstCount (&pScsiPhysDev->waitingThreads);
  1567.     int    nActive  = lstCount (&pScsiPhysDev->activeThreads);
  1568.     switch (pScsiPhysDev->nexus)
  1569. {
  1570. case SCSI_NEXUS_NONE: nexus = "none"; break;
  1571. case SCSI_NEXUS_IT:   nexus = "IT"  ; break;
  1572. case SCSI_NEXUS_ITL:  nexus = "ITL" ; break;
  1573. case SCSI_NEXUS_ITLQ: nexus = "ITLQ"; break;
  1574. default:              nexus = "????"; break;
  1575.         }
  1576.     state = pScsiPhysDev->connected ? "conn." : "disc.";
  1577.     
  1578.     if (!noHeader)
  1579. {
  1580.      printf ("PhysDev ID  State  Nexus  Tag  # Tags  # Threads (w/a)n");
  1581.      printf ("----------  -----  -----  ---  ------  ---------------n");
  1582. }
  1583.     printf ("0x%08x  %-5s  %-4s   %3d   %3d       %3d   %3dn",
  1584.     (int) pScsiPhysDev,
  1585.     state,
  1586.     nexus,
  1587.     pScsiPhysDev->curTag,
  1588.     pScsiPhysDev->nTaggedNexus,
  1589.     nWaiting,
  1590.     nActive);
  1591.     if (showThreads && (nWaiting != 0))
  1592. {
  1593. printf ("nWaiting threads:n");
  1594. scsiThreadListIdShow (&pScsiPhysDev->waitingThreads);
  1595. }
  1596.     if (showThreads && (nActive != 0))
  1597. {
  1598. printf ("nActive threads:n");
  1599. scsiThreadListIdShow (&pScsiPhysDev->activeThreads);
  1600. }
  1601.     }
  1602. /*******************************************************************************
  1603. *
  1604. * scsiThreadListIdShow - show IDs of all threads in a list
  1605. *
  1606. * Step through a list of threads, printing IDs of all threads in the list.
  1607. * A maximum of 6 IDs are printed per line of output.
  1608. *
  1609. * NOTE: this routine is naive about the list being updated while it is
  1610. * traversed, so is best used when there is no SCSI activity.
  1611. *
  1612. * RETURNS: N/A
  1613. *
  1614. * NOMANUAL
  1615. */
  1616. VOID scsiThreadListIdShow
  1617.     (
  1618.     LIST * pList
  1619.     )
  1620.     {
  1621.     NODE * pThread;
  1622.     int n;
  1623.     n = 0;
  1624.     for (pThread = lstFirst (pList); pThread != 0; pThread = lstNext (pThread))
  1625. {
  1626. printf ("0x%08x  ", (int) pThread);
  1627. if ((++n % 6) == 0)
  1628.     {
  1629.     printf ("n");
  1630.     n = 0;
  1631.     }
  1632. }
  1633.     if (n != 0)
  1634. printf ("n");
  1635.     }
  1636. /*******************************************************************************
  1637. *
  1638. * scsiThreadListShow - show info for all threads in a list
  1639. *
  1640. * Step through a list of threads, showing details of all threads in the list.
  1641. *
  1642. * NOTE: this routine is naive about the list being updated while it is
  1643. * traversed, so is best used when there is no SCSI activity.
  1644. *
  1645. * RETURNS: N/A
  1646. *
  1647. * NOMANUAL
  1648. */
  1649. void scsiThreadListShow
  1650.     (
  1651.     LIST * pList
  1652.     )
  1653.     {
  1654.     NODE * pThread;
  1655.     BOOL   noHeader;
  1656.     noHeader = FALSE;
  1657.     for (pThread = lstFirst (pList); pThread != 0; pThread = lstNext (pThread))
  1658. {
  1659. scsiThreadShow ((SCSI_THREAD *) pThread, noHeader);
  1660. noHeader = TRUE;
  1661. }
  1662.     }
  1663. /*******************************************************************************
  1664. *
  1665. * scsi2BusReset - pulse the reset signal on the SCSI bus
  1666. *
  1667. * This routine calls a controller-specific routine to reset a specified
  1668. * controller's SCSI bus.  If no controller is specified (`pScsiCtrl' is 0),
  1669. * the value in `pSysScsiCtrl' is used.
  1670. *
  1671. * RETURNS: OK, or ERROR if there is no controller or controller-specific
  1672. * routine.
  1673. *
  1674. * INTERNAL
  1675. *
  1676. * The SCSI manager must be notified that a SCSI bus reset has occurred.  This
  1677. * is normally done by the ISR for the SCSI controller hardware, assuming it
  1678. * can detect a bus reset.  If this is not the case "scsiBusResetNotify ()"
  1679. * must be called explicitly, perhaps by a board-specific ISR.
  1680. */
  1681. LOCAL STATUS scsi2BusReset
  1682.     (
  1683.     SCSI_CTRL *pScsiCtrl /* ptr to SCSI controller info */
  1684.     )
  1685.     {
  1686.     if (pScsiCtrl == (SCSI_CTRL *) NULL)
  1687. {
  1688. if (pSysScsiCtrl != (SCSI_CTRL *) NULL)
  1689.     pScsiCtrl = pSysScsiCtrl;
  1690. else 
  1691.     {
  1692.     errnoSet (S_scsiLib_NO_CONTROLLER);
  1693.     printErr ("No SCSI controller specified.n");
  1694.     return (ERROR);
  1695.     }
  1696. }
  1697.     (pScsiCtrl->scsiBusControl) (pScsiCtrl, SCSI_BUS_RESET);
  1698.     return (OK);
  1699.     }
  1700. /*******************************************************************************
  1701. *
  1702. * scsiBusResetNotify - notify the SCSI library that a bus reset has occurred.
  1703. *
  1704. * This function should not normally be called by application code.  It may be
  1705. * called from interrupt service routines (typically in the controller- or
  1706. * BSP-specific code which handles a SCSI bus reset interrupt).
  1707. *
  1708. * INTERNAL
  1709. * SCSI controller interrupts must be disabled while the synthesised
  1710. * bus reset event is posted to the controller, to ensure that the posting
  1711. * operation (which is not inherently atomic) is not interrupted by the ISR.
  1712. *
  1713. * NOMANUAL
  1714. */
  1715. void scsiBusResetNotify
  1716.     (
  1717.     SCSI_CTRL *pScsiCtrl /* ctrlr for bus which was reset */
  1718.     )
  1719.     {
  1720.     SCSI_EVENT event;
  1721.     int        key;
  1722.     event.type = SCSI_EVENT_BUS_RESET;
  1723.     key = intLock ();
  1724.     
  1725.     scsiMgrEventNotify (pScsiCtrl, &event, sizeof (event));
  1726.     intUnlock (key);
  1727.     }
  1728. /*******************************************************************************
  1729. *
  1730. * scsi2PhaseNameGet - get the name of a specified SCSI phase
  1731. *
  1732. * This routine returns a pointer to a string which is the name of the SCSI
  1733. * phase input as an integer.  It's primarily used to improve readability of
  1734. * debugging messages.
  1735. *
  1736. * RETURNS: A pointer to a string naming the SCSI phase input
  1737. */
  1738. LOCAL char *scsi2PhaseNameGet
  1739.     (
  1740.     int scsiPhase               /* phase whose name to look up */
  1741.     )
  1742.     {
  1743.     static char *phaseNameArray [] =
  1744. {
  1745. "DATA_OUT",
  1746. "DATA_IN ",
  1747. "COMMAND ",
  1748. "STATUS  ",
  1749. "UNDEF(4)",
  1750. "UNDEF(5)",
  1751. "MSG_OUT ",
  1752. "MSG_IN  "
  1753. };
  1754.     return ((scsiPhase < SCSI_DATA_OUT_PHASE ||
  1755.      scsiPhase > SCSI_MSG_IN_PHASE) ?
  1756.      "UNKNOWN " : phaseNameArray [scsiPhase]);
  1757.     }
  1758. /*******************************************************************************
  1759. *
  1760. * scsi2CmdBuild - fills in the fields of a SCSI command descriptor block
  1761. *
  1762. * Typically, this routine is not called directly by the user, but by other
  1763. * routines in scsiLib.  It fills in fields of a SCSI-command descriptor block
  1764. * based on the input parameters.  The field layouts vary based on the command
  1765. * group, which is determined from the `opCode'.
  1766. *
  1767. * RETURNS: ERROR if vendor-unique command group or out-of-bounds parameter,
  1768. * otherwise OK.
  1769. *
  1770. * NOMANUAL
  1771. */
  1772. LOCAL STATUS scsi2CmdBuild
  1773.     (
  1774.     SCSI_COMMAND scsiCmd,       /* command to be built */
  1775.     int *pCmdLength,            /* ptr to command length variable */
  1776.     UINT8 opCode,               /* SCSI opCode for command */
  1777.     int LUN,                    /* logical unit number for command */
  1778.     BOOL relAdrs,               /* whether to set relative address bit */
  1779.     int logBlockAdrs,           /* logical block address */
  1780.     int xferLength,             /* number of blocks or bytes to xfer */
  1781.     UINT8 controlByte           /* control byte for command */
  1782.     )
  1783.     {
  1784.     FAST int groupCode = (int) (opCode >> 5);
  1785.     FAST int cmdLength;
  1786.     /* array with the length of a SCSI command indexed by its group code
  1787.      * (NONE == vendor unique)
  1788.      */