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

VxWorks

开发平台:

C/C++

  1. /* scsi1Lib.c - Small Computer System Interface (SCSI) library (SCSI-1) */
  2. /* Copyright 1989-1994 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /*
  5. modification history
  6. --------------------
  7. 02e,09jul97,dgp  doc: correct fonts per SPR 7853
  8. 02d,29oct96,dgp  doc: editing for newly published SCSI libraries
  9. 02c,06may96,jds  and more doc fixes...
  10. 02b,01may96,jds  yet more doc fixes...
  11. 02a,13nov95,jds  more doc tweaks
  12. 01z,08nov95,jds  doc tweaks
  13. 01y,10oct94,jds  fixed for SCSI1 and SCSI2 backward compatability
  14. 01x,28feb93,jdi  doc: changed comment in scsiWrtSecs() from "read" to "write".
  15. 01w,27nov92,jdi  documentation cleanup, including SPR 1415.
  16. 01v,15sep92,ccc  reworked select timeout, fixed extended message to work
  17.  with new drive, documentation changes.
  18. 01u,10aug92,ccc  added timeouts to scsiXaction for each scsi command.
  19. 01t,28jul92,rrr  fixed decl of scsiSyncTarget
  20. 01s,22jul92,gae  added correct number of parameters to logMsg().
  21. 01r,20jul92,eve  Remove conditional INCLUDE_SYNC_SCSI compilation.
  22. 01q,18jul92,smb  Changed errno.h to errnoLib.h.
  23. 01p,13jul92,eve  added init of the current pScsiXaction in scsiPhaseSequence().
  24. 01o,08jul92,eve  supplies a reqSense buffer if there is no user buffer 
  25.  in scsiTransact routine.
  26. 01n,03jul92,eve  added new sync feature with NOMANUAL
  27. 01m,26may92,rrr  the tree shuffle
  28. 01l,16dec91,gae  added includes for ANSI; added parameters to logMsg() calls.
  29. 01k,19nov91,rrr  shut up some ansi warnings.
  30. 01j,04oct91,rrr  passed through the ansification filter
  31.                   -changed functions to ansi style
  32.   -changed READ, WRITE and UPDATE to O_RDONLY O_WRONLY and ...
  33.   -changed VOID to void
  34.   -changed copyright notice
  35. 01i,13mar91,jcc  misc. clean-up and enhancements.
  36. 01h,25oct90,jcc  lint.
  37. 01g,18oct90,jcc  removed call to printErrno() in scsiAutoConfig().
  38. 01f,02oct90,jcc  UTINY became UINT8; added scsiAutoConfig(), scsiPhysDevIdGet(),
  39.  and scsiIoctl() option FIODISKFORMAT;
  40.  changed all malloc()'s to calloc()'s in xxCreate() routines;
  41.  made changes associated with SEM_ID's becoming SEMAPHORE's
  42.  in created structures;
  43.  enhanced scsiPhysDevCreate() to determine amount and type
  44.  of REQUEST SENSE data returned by the device; miscellaneous.
  45. 01e,10aug90,dnw  fixed warnings caused by changing scsiBusReset to VOIDFUNCPTR.
  46. 01d,18jul90,jcc  made semTake() calls 5.0 compatible; clean-up.
  47. 01c,08jun90,jcc  modified incoming message handling; generalized scsiTransact
  48.  calls to a procedure variable to allow off-board SCSI
  49.  controller drivers; documentation.
  50. 01b,23mar90,jcc  lint.
  51. 01a,05may89,jcc  written.
  52. */
  53. /*
  54. DESCRIPTION
  55. This library implements the Small Computer System Interface (SCSI)
  56. protocol in a controller-independent manner.  It implements only the SCSI
  57. initiator function; the library does not support a VxWorks target
  58. acting as a SCSI target.  Furthermore, in the current implementation, a
  59. VxWorks target is assumed to be the only initiator on the SCSI bus,
  60. although there may be multiple targets (SCSI peripherals) on the bus.
  61. The implementation is transaction based.  A transaction is defined as the
  62. selection of a SCSI device by the initiator, the issuance of a SCSI command,
  63. and the sequence of data, status, and message phases necessary to perform
  64. the command.  A transaction normally completes with a "Command Complete" 
  65. message from
  66. the target, followed by disconnection from the SCSI bus.  If
  67. the status from the target is "Check Condition," the transaction continues;
  68. the initiator issues a "Request Sense" command to gain more information
  69. on the exception condition reported.
  70. Many of the subroutines in scsi1Lib facilitate the transaction of
  71. frequently used SCSI commands.  Individual command fields are passed as
  72. arguments from which SCSI Command Descriptor Blocks are constructed, and
  73. fields of a SCSI_TRANSACTION structure are filled in appropriately.  This
  74. structure, along with the SCSI_PHYS_DEV structure associated with the
  75. target SCSI device, is passed to the routine whose address is indicated by
  76. the 'scsiTransact' field of the SCSI_CTRL structure associated with the
  77. relevant SCSI controller.
  78. The function variable 'scsiTransact' is set by the individual SCSI
  79. controller driver.  For off-board SCSI controllers, this
  80. routine rearranges the fields of the SCSI_TRANSACTION structure into
  81. the appropriate structure for the specified hardware, which then carries out
  82. the transaction through firmware control.  Drivers for an on-board
  83. SCSI-controller chip can use the scsiTransact() routine in scsiLib (which
  84. invokes the scsi1Transact() routine in scsi1Lib), as long as they provide the 
  85. other functions specified in the SCSI_CTRL structure.
  86. Note that no disconnect/reconnect capability is currently supported.
  87. SUPPORTED SCSI DEVICES
  88. The scsi1Lib library supports use of SCSI peripherals conforming to the 
  89. standards specified in 
  90. .I "Common Command Set (CCS) of the SCSI, Rev. 4.B."
  91. Most SCSI peripherals currently offered support CCS.  
  92. While an attempt has been made
  93. to have scsi1Lib support non-CCS peripherals, not all commands or features
  94. of this library are guaranteed to work with them.  For example,
  95. auto-configuration may be impossible with non-CCS devices, if they do not
  96. support the INQUIRY command.
  97. Not all classes of SCSI devices are supported.  However, the scsiLib library
  98. provides the capability to transact any SCSI command on any SCSI device
  99. through the FIOSCSICOMMAND function of the scsiIoctl() routine.
  100. Only direct-access devices (disks) are supported by a file system.  For
  101. other types of devices, additional, higher-level software is necessary to
  102. map user-level commands to SCSI transactions.
  103. CONFIGURING SCSI CONTROLLERS
  104. The routines to create and initialize a specific SCSI controller are
  105. particular to the controller and normally are found in its library
  106. module.  The normal calling sequence is:
  107. .ne 4
  108. .CS
  109.     xxCtrlCreate (...); /@ parameters are controller specific @/
  110.     xxCtrlInit (...);   /@ parameters are controller specific @/
  111. .CE
  112. The conceptual difference between the two routines is that xxCtrlCreate()
  113. calloc's memory for the xx_SCSI_CTRL data structure and initializes
  114. information that is never expected to change (for example, clock rate).  The
  115. remaining fields in the xx_SCSI_CTRL structure are initialized by
  116. xxCtrlInit() and any necessary registers are written on the SCSI
  117. controller to effect the desired initialization.  This
  118. routine can be called multiple times, although this is rarely required.
  119. For example, the bus ID of the SCSI
  120. controller can be changed without rebooting the VxWorks system.
  121. CONFIGURING PHYSICAL SCSI DEVICES
  122. Before a device can be used, it must be "created," that is, declared.
  123. This is done with scsiPhysDevCreate() and can only be done after a
  124. SCSI_CTRL structure exists and has been properly initialized.
  125. .CS
  126. SCSI_PHYS_DEV *scsiPhysDevCreate
  127.     (
  128.     SCSI_CTRL * pScsiCtrl,/@ ptr to SCSI controller info @/
  129.     int  devBusId,        /@ device's SCSI bus ID @/
  130.     int  devLUN,          /@ device's logical unit number @/
  131.     int  reqSenseLength,  /@ length of REQUEST SENSE data dev returns @/
  132.     int  devType,         /@ type of SCSI device @/
  133.     BOOL removable,       /@ whether medium is removable @/
  134.     int  numBlocks,       /@ number of blocks on device @/
  135.     int  blockSize        /@ size of a block in bytes @/
  136.     )
  137. .CE
  138. Several of these parameters can be left unspecified, as follows:
  139. .iP <reqSenseLength>
  140. If 0, issue a REQUEST_SENSE to determine a request sense length.
  141. .iP <devType>
  142. If -1, issue an INQUIRY to determine the device type.
  143. .iP "<numBlocks>, <blockSize>"
  144. If 0, issue a READ_CAPACITY to determine the number of blocks.
  145. .LP
  146. The above values are recommended, unless the device does not support the
  147. required commands, or other non-standard conditions prevail.
  148. LOGICAL PARTITIONS ON BLOCK DEVICES
  149. It is possible to have more than one logical partition on a SCSI block
  150. device.  This capability is currently not supported for removable media
  151. devices.  A partition is an array of contiguously addressed blocks
  152. with a specified starting block address and a specified number of blocks.
  153. The scsiBlkDevCreate() routine is called once for each block device
  154. partition.  Under normal usage, logical partitions should not overlap.
  155. .ne 8
  156. .CS
  157. SCSI_BLK_DEV *scsiBlkDevCreate
  158.     (
  159.     SCSI_PHYS_DEV *  pScsiPhysDev,  /@ ptr to SCSI physical device info @/
  160.     int              numBlocks,     /@ number of blocks in block device @/
  161.     int              blockOffset    /@ address of first block in volume @/
  162.     )
  163. .CE
  164. Note that if <numBlocks> is 0, the rest of the device is used.
  165. ATTACHING FILE SYSTEMS TO LOGICAL PARTITIONS
  166. Files cannot be read or written to a disk partition until a file system
  167. (such as dosFs or rt11Fs) has been initialized on the partition.  For more
  168. information, see the documentation in dosFsLib or rt11FsLib.
  169. TRANSMITTING ARBITRARY COMMANDS TO SCSI DEVICES
  170. The scsi1Lib library provides routines that implement many common SCSI
  171. commands.  Still, there are situations that require commands that are not
  172. supported by scsi1Lib (for example, writing software to control non-direct 
  173. access devices).  Arbitrary commands are handled with the FIOSCSICOMMAND 
  174. option to scsiIoctl().  The <arg> parameter for FIOSCSICOMMAND is a pointer to 
  175. a valid SCSI_TRANSACTION structure.  Typically, a call to scsiIoctl() is 
  176. written as a subroutine of the form:
  177. .CS
  178. STATUS myScsiCommand
  179.     (
  180.     SCSI_PHYS_DEV *  pScsiPhysDev,  /@ ptr to SCSI physical device     @/
  181.     char *           buffer,        /@ ptr to data buffer              @/
  182.     int              bufLength,     /@ length of buffer in bytes       @/
  183.     int              someParam      /@ param. specifiable in cmd block @/
  184.     )
  185.     {
  186.     SCSI_COMMAND myScsiCmdBlock;        /@ SCSI command byte array @/
  187.     SCSI_TRANSACTION myScsiXaction;     /@ info on a SCSI transaction @/
  188.     /@ fill in fields of SCSI_COMMAND structure @/
  189.     myScsiCmdBlock [0] = MY_COMMAND_OPCODE;     /@ the required opcode @/
  190.     .
  191.     myScsiCmdBlock [X] = (UINT8) someParam;     /@ for example @/
  192.     .
  193.     myScsiCmdBlock [N-1] = MY_CONTROL_BYTE;     /@ typically == 0 @/
  194.     /@ fill in fields of SCSI_TRANSACTION structure @/
  195.     myScsiXaction.cmdAddress    = myScsiCmdBlock;
  196.     myScsiXaction.cmdLength     = <# of valid bytes in myScsiCmdBlock>;
  197.     myScsiXaction.dataAddress   = (UINT8 *) buffer;
  198.     myScsiXaction.dataDirection = <O_RDONLY (0) or O_WRONLY (1)>;
  199.     myScsiXaction.dataLength    = bufLength;
  200.     myScsiXaction.cmdTimeout    = timeout in usec;
  201.     /@ if dataDirection is O_RDONLY, and the length of the input data is
  202.      * variable, the following parameter specifies the byte # (min == 0)
  203.      * of the input data which will specify the additional number of
  204.      * bytes available
  205.      @/
  206.     myScsiXaction.addLengthByte = X;
  207.     if (scsiIoctl (pScsiPhysDev, FIOSCSICOMMAND, &myScsiXaction) == OK)
  208.         return (OK);
  209.     else
  210.         /@ optionally perform retry or other action based on value of
  211.          *  myScsiXaction.statusByte
  212.          @/
  213.         return (ERROR);
  214.     }
  215. .CE
  216. INCLUDE FILES
  217. scsiLib.h, scsi1Lib.h
  218. SEE ALSO: dosFsLib, rt11FsLib,
  219. .I  "American National Standards for Information Systems - Small Computer" 
  220. .I  "System Interface (SCSI), ANSI X3.131-1986,"
  221. .pG "I/O System, Local File Systems"
  222. */
  223. #include "vxWorks.h"
  224. #include "ioLib.h"
  225. #include "ctype.h"
  226. #include "stdlib.h"
  227. #include "errnoLib.h"
  228. #include "taskLib.h"
  229. #include "logLib.h"
  230. #include "string.h"
  231. #include "stdio.h"
  232. #include "scsiLib.h"
  233. /* forward static functions */
  234. LOCAL BOOL            strIsPrintable (char *);
  235. LOCAL STATUS          scsiDevSelect (SCSI_PHYS_DEV *, SCSI_TRANSACTION *);
  236. LOCAL STATUS          scsiStatusCheck (BLK_DEV *);
  237. LOCAL STATUS          scsiPhaseSequence (SCSI_PHYS_DEV *, SCSI_TRANSACTION *);
  238. LOCAL STATUS          scsiBlkDevIoctl (SCSI_BLK_DEV *, int, int);
  239. LOCAL STATUS          scsiSyncTarget (SCSI_PHYS_DEV *, int, int, 
  240.        SCSI_SYNC_AGREEMENT *);
  241. LOCAL STATUS          scsi1CtrlInit (SCSI_CTRL *);
  242. LOCAL STATUS          scsi1TestUnitRdy (SCSI_PHYS_DEV *);
  243. LOCAL SCSI_PHYS_DEV * scsi1PhysDevIdGet (SCSI_CTRL *, int, int);
  244. LOCAL STATUS          scsi1ReqSense (SCSI_PHYS_DEV *, char *, int);
  245. LOCAL STATUS          scsi1Inquiry (SCSI_PHYS_DEV *, char *, int);
  246. LOCAL STATUS          scsi1ReadCapacity (SCSI_PHYS_DEV *, int *, int *);
  247. LOCAL STATUS          scsi1RdSecs (SCSI_BLK_DEV *, int, int, char *);
  248. LOCAL STATUS          scsi1WrtSecs (SCSI_BLK_DEV *, int, int, char *);
  249. LOCAL STATUS          scsi1PhysDevDelete (FAST SCSI_PHYS_DEV *);
  250. LOCAL SCSI_PHYS_DEV * scsi1PhysDevCreate (SCSI_CTRL *, int, int, int, int, BOOL,
  251.                                         int, int);
  252. LOCAL STATUS          scsi1AutoConfig (SCSI_CTRL *);
  253. LOCAL BLK_DEV *       scsi1BlkDevCreate (SCSI_PHYS_DEV *, int, int);
  254. LOCAL void            scsi1BlkDevInit (SCSI_BLK_DEV *, int, int);
  255. LOCAL void            scsi1BlkDevShow (SCSI_PHYS_DEV *);
  256. LOCAL STATUS          scsi1Show (FAST SCSI_CTRL *);
  257. LOCAL STATUS          scsi1BusReset (SCSI_CTRL *);
  258. LOCAL STATUS          scsi1CmdBuild (SCSI_COMMAND, int *, UINT8, int, BOOL, int,
  259.           int, UINT8);
  260. LOCAL STATUS          scsi1Transact (SCSI_PHYS_DEV *, SCSI_TRANSACTION *);
  261. LOCAL STATUS          scsi1Ioctl (SCSI_PHYS_DEV *, int, int);
  262. LOCAL STATUS          scsi1FormatUnit (SCSI_PHYS_DEV *, BOOL, int, int, int, 
  263. char *,int);
  264. LOCAL STATUS          scsi1ModeSelect (SCSI_PHYS_DEV *, int, int, char *, int);
  265. LOCAL STATUS          scsi1ModeSense (SCSI_PHYS_DEV *, int, int, char *, int);
  266. LOCAL char *          scsi1PhaseNameGet (int);
  267. SCSI_FUNC_TBL scsi1IfTbl =
  268.     {
  269.     (FUNCPTR) scsi1CtrlInit,
  270.     (FUNCPTR) scsi1BlkDevInit,
  271.     (FUNCPTR) scsi1BlkDevCreate,
  272.     (FUNCPTR) scsi1BlkDevShow,
  273.     (FUNCPTR) scsi1PhaseNameGet,
  274.     (FUNCPTR) scsi1PhysDevCreate,
  275.     (FUNCPTR) scsi1PhysDevDelete,
  276.     (FUNCPTR) scsi1PhysDevIdGet,
  277.     (FUNCPTR) scsi1AutoConfig,
  278.     (FUNCPTR) scsi1Show,
  279.     (FUNCPTR) scsi1BusReset,
  280.     (FUNCPTR) scsi1CmdBuild,
  281.     (FUNCPTR) scsi1Transact,
  282.     (FUNCPTR) scsi1Ioctl,
  283.     (FUNCPTR) scsi1FormatUnit,
  284.     (FUNCPTR) scsi1ModeSelect,
  285.     (FUNCPTR) scsi1ModeSense,
  286.     (FUNCPTR) scsi1ReadCapacity,
  287.     (FUNCPTR) scsi1RdSecs,
  288.     (FUNCPTR) scsi1WrtSecs,
  289.     (FUNCPTR) scsi1TestUnitRdy,
  290.     (FUNCPTR) scsi1Inquiry,
  291.     (FUNCPTR) scsi1ReqSense
  292.     };
  293. /*******************************************************************************
  294. *
  295. * scsi1IfInit - initialize the SCSI1 interface to scsiLib
  296. *
  297. * NOMANUAL 
  298. */
  299. void scsi1IfInit ()
  300.     {
  301.     pScsiIfTbl = &scsi1IfTbl;
  302.     pScsiIfTbl->scsiCtrlInit      = (FUNCPTR) scsi1CtrlInit;
  303.     pScsiIfTbl->scsiPhysDevDelete = (FUNCPTR) scsi1PhysDevDelete;
  304.     pScsiIfTbl->scsiPhysDevCreate = (FUNCPTR) scsi1PhysDevCreate;
  305.     pScsiIfTbl->scsiAutoConfig    = (FUNCPTR) scsi1AutoConfig;
  306.     pScsiIfTbl->scsiBlkDevCreate  = (FUNCPTR) scsi1BlkDevCreate;
  307.     pScsiIfTbl->scsiPhysDevIdGet  = (FUNCPTR) scsi1PhysDevIdGet;
  308.     pScsiIfTbl->scsiBlkDevInit    = (FUNCPTR) scsi1BlkDevInit;
  309.     pScsiIfTbl->scsiBlkDevShow    = (FUNCPTR) scsi1BlkDevShow;
  310.     pScsiIfTbl->scsiShow          = (FUNCPTR) scsi1Show;
  311.     pScsiIfTbl->scsiBusReset      = (FUNCPTR) scsi1BusReset;
  312.     pScsiIfTbl->scsiCmdBuild      = (FUNCPTR) scsi1CmdBuild;
  313.     pScsiIfTbl->scsiTransact      = (FUNCPTR) scsi1Transact;
  314.     pScsiIfTbl->scsiIoctl         = (FUNCPTR) scsi1Ioctl;
  315.     pScsiIfTbl->scsiFormatUnit    = (FUNCPTR) scsi1FormatUnit;
  316.     pScsiIfTbl->scsiModeSelect    = (FUNCPTR) scsi1ModeSelect;
  317.     pScsiIfTbl->scsiModeSense     = (FUNCPTR) scsi1ModeSense;
  318.     pScsiIfTbl->scsiPhaseNameGet  = (FUNCPTR) scsi1PhaseNameGet;
  319.     pScsiIfTbl->scsiReadCapacity  = (FUNCPTR) scsi1ReadCapacity;
  320.     pScsiIfTbl->scsiRdSecs        = (FUNCPTR) scsi1RdSecs;
  321.     pScsiIfTbl->scsiWrtSecs       = (FUNCPTR) scsi1WrtSecs;
  322.     pScsiIfTbl->scsiTestUnitRdy   = (FUNCPTR) scsi1TestUnitRdy;
  323.     pScsiIfTbl->scsiInquiry       = (FUNCPTR) scsi1Inquiry;
  324.     pScsiIfTbl->scsiReqSense      = (FUNCPTR) scsi1ReqSense;
  325.     }
  326. /*******************************************************************************
  327. *
  328. * scsi1CtrlInit - initialize generic fields of a SCSI_CTRL structure
  329. *
  330. * This routine should be called by the SCSI controller libraries' xxCtrlCreate
  331. * routines, which are responsible for initializing any fields not herein
  332. * initialized.  It is NOT intended to be called directly by a user.
  333. *
  334. * NOTE
  335. * As a matter of good practice, the SCSI_CTRL structure should be
  336. * calloc()'ed by the xxCtrlCreate() routine, so that all fields are
  337. * initially zero.  If this is done, some of the work of this routine will be
  338. * redundant.
  339. *
  340. * RETURNS: OK, or ERROR if a semaphore initialization fails.
  341. *
  342. * NOMANUAL
  343. */
  344. LOCAL STATUS scsi1CtrlInit
  345.     (
  346.     SCSI_CTRL *pScsiCtrl        /* ptr to SCSI_CTRL struct to initialize */
  347.     )
  348.     {
  349.     int ix; /* loop index */
  350.     /* initialize controller mutual exclusion semaphore */
  351.     if (semMInit (&pScsiCtrl->ctrlMutexSem, scsiCtrlMutexOptions) == ERROR)
  352.         {
  353.         printErr ("scsi1CtrlInit: semMInit of ctrlMutexSem failed.n");
  354.         return (ERROR);
  355.         }
  356.     /* initialize controller interrupt waiting semaphore */
  357.     if (semBInit (&pScsiCtrl->ctrlSyncSem, scsiCtrlSemOptions,
  358.   SEM_EMPTY) == ERROR)
  359. {
  360. printErr ("scsi1CtrlInit: semBInit of ctrlSyncSem failed.n");
  361. return (ERROR);
  362. }
  363.     /* initialize the scsiBusReset to NULL (set by individual drivers) */
  364.     pScsiCtrl->scsiBusReset = (VOIDFUNCPTR) NULL;
  365.     /* initialize the scsiPriority to NONE (set by individual drivers) */
  366.     pScsiCtrl->scsiPriority = NONE;
  367.     /* initialize array of ptrs to SCSI_PHYS_DEV structures to NULL */
  368.     for (ix = 0; ix < MAX_SCSI_PHYS_DEVS; ix++)
  369. {
  370. pScsiCtrl->physDevArr [ix] = (SCSI_PHYS_DEV *) NULL;
  371. }
  372.     return (OK);
  373.     }
  374. /*******************************************************************************
  375. *
  376. * scsi1PhysDevDelete - delete a SCSI physical device structure
  377. *
  378. * This routine deletes a specified SCSI physical device structure.
  379. *
  380. * RETURNS: OK, or ERROR if `pScsiPhysDev' is NULL or SCSI_BLK_DEVs have
  381. * been created on the device.
  382. */
  383. LOCAL STATUS scsi1PhysDevDelete
  384.     (
  385.     FAST SCSI_PHYS_DEV *pScsiPhysDev    /* ptr to SCSI physical device info */
  386.     )
  387.     {
  388.     FAST SCSI_CTRL *pScsiCtrl;
  389.     STATUS status;
  390.     if ((pScsiPhysDev == (SCSI_PHYS_DEV *) NULL) ||
  391. (pScsiPhysDev->pScsiBlkDev != (SCSI_BLK_DEV *) NULL))
  392. return (ERROR);
  393.     /* Reset target if the sync capacity is existing */
  394.     if ( pScsiPhysDev->syncXfer == TRUE )
  395.         {
  396.         SCSI_SYNC_AGREEMENT syncAgreement;
  397.         /* Send a sync message for async protocol */
  398.         status = scsiSyncTarget(pScsiPhysDev, pScsiPhysDev->syncXferPeriod
  399. , 0, &syncAgreement);
  400.         /* Clear the next check status */
  401.         status = scsiTestUnitRdy(pScsiPhysDev);
  402.         }
  403.     pScsiCtrl = pScsiPhysDev->pScsiCtrl;
  404.     pScsiCtrl->physDevArr [(pScsiPhysDev->scsiDevBusId << 3) |
  405.    pScsiPhysDev->scsiDevLUN] = (SCSI_PHYS_DEV *) NULL;
  406.     if (pScsiPhysDev->pReqSenseData != NULL)
  407.         (void) free ((char *) pScsiPhysDev->pReqSenseData);
  408.     (void) free ((char *) pScsiPhysDev);
  409.     return (OK);
  410.     }
  411. /*******************************************************************************
  412. *
  413. * scsi1PhysDevCreate - create a SCSI physical device structure
  414. *
  415. * This routine enables access to a SCSI device and must be invoked first.
  416. * It should be called once for each physical device on the SCSI bus.
  417. *
  418. * If `reqSenseLength' is specified as NULL (0), one or more REQUEST_SENSE
  419. * commands are issued to the device to determine the number of bytes of
  420. * sense data it typically returns.  Note that if the device returns variable
  421. * amounts of sense data depending on its state, consult the device manual 
  422. * to determine the maximum amount of sense data that can be returned.
  423. *
  424. * If `devType' is specified as NONE (-1), an INQUIRY command is issued to
  425. * determine the device type, with the added benefit of acquiring the device's
  426. * make and model number.  The scsiShow() routine displays this information.
  427. * Common values of `devType' can be found in scsiLib.h or in the SCSI
  428. * specification.
  429. *
  430. * If `numBlocks' or `blockSize' are specified as NULL (0), a READ_CAPACITY
  431. * command is issued to determine those values.  This will occur
  432. * only for device types which support READ_CAPACITY.
  433. *
  434. * RETURNS: A pointer to the created SCSI_PHYS_DEV structure, or NULL if the
  435. * routine is unable to create the physical device structure.
  436. */
  437. LOCAL SCSI_PHYS_DEV *scsi1PhysDevCreate
  438.     (
  439.     SCSI_CTRL *pScsiCtrl,       /* ptr to SCSI controller info */
  440.     int devBusId,               /* device's SCSI bus ID */
  441.     int devLUN,                 /* device's logical unit number */
  442.     int reqSenseLength,         /* length of REQUEST SENSE data dev returns */
  443.     int devType,                /* type of SCSI device */
  444.     BOOL removable,             /* whether medium is removable */
  445.     int numBlocks,              /* number of blocks on device */
  446.     int blockSize               /* size of a block in bytes */
  447.     )
  448.     {
  449.     SCSI_PHYS_DEV *pScsiPhysDev; /* ptr to SCSI physical dev. struct */
  450. /* REQ SENSE data for auto-sizing */
  451.     UINT8 reqSenseData [REQ_SENSE_ADD_LENGTH_BYTE + 1];
  452.     SCSI_PHYS_DEV *pPhysDev;    /* use to check if it's already created */
  453.      
  454.     /* check bus ID and LUN are within limits */
  455.     if ((devBusId < SCSI_MIN_BUS_ID) ||
  456. (devBusId > SCSI_MAX_BUS_ID) ||
  457. (devLUN < SCSI_MIN_LUN) ||
  458. (devLUN > SCSI_MAX_LUN))
  459. {
  460. errnoSet (S_scsiLib_ILLEGAL_PARAMETER);
  461. return ((SCSI_PHYS_DEV *) NULL);
  462. }
  463.     /* Check if this device was already create and if it's support sync 
  464.      * capacity.
  465.      */
  466.        pPhysDev = scsiPhysDevIdGet (pScsiCtrl,devBusId,devLUN);
  467.     if (pPhysDev != (SCSI_PHYS_DEV *)NULL)
  468.         {
  469.         errnoSet (S_scsiLib_DEVICE_EXIST);
  470.         return ((SCSI_PHYS_DEV *) NULL);
  471. }
  472.     /* create a SCSI physical device structure */
  473.     pScsiPhysDev = (SCSI_PHYS_DEV *) calloc (1, sizeof (*pScsiPhysDev));
  474.     if (pScsiPhysDev == NULL)
  475.         return ((SCSI_PHYS_DEV *) NULL);
  476.     /* initialize device mutual exclusion semaphore */
  477.     if (semMInit (&pScsiPhysDev->devMutexSem, scsiPhysDevMutexOptions) == ERROR)
  478.         {
  479.         SCSI_DEBUG_MSG ("scsiPhysDevCreate: semMInit of devMutexSem failed.n",
  480. 0, 0, 0, 0, 0, 0);
  481. (void) free ((char *) pScsiPhysDev);
  482.         return ((SCSI_PHYS_DEV *) NULL);
  483.         }
  484.     /* initialize device interrupt waiting semaphore */
  485.     if (semBInit (&pScsiPhysDev->devSyncSem, scsiPhysDevSemOptions,
  486.   SEM_EMPTY) == ERROR)
  487.         {
  488.         SCSI_DEBUG_MSG ("scsiPhysDevCreate: semBInit of devSyncSem failed.n",
  489. 0, 0, 0, 0, 0, 0);
  490. (void) free ((char *) pScsiPhysDev);
  491.         return ((SCSI_PHYS_DEV *) NULL);
  492.         }
  493.     /* initialize miscellaneous fields in the SCSI_PHYS_DEV struct */
  494.     pScsiPhysDev->scsiDevBusId = devBusId;
  495.     pScsiPhysDev->scsiDevLUN = devLUN;
  496.     pScsiPhysDev->devStatus  = IDLE;
  497.     (*pScsiCtrl->scsiSelTimeOutCvt) (pScsiCtrl, scsiSelectTimeout,
  498.      &pScsiPhysDev->selTimeOut);
  499.     pScsiPhysDev->pScsiCtrl = pScsiCtrl;
  500.     pScsiCtrl->physDevArr [(devBusId << 3) | devLUN] = pScsiPhysDev;
  501.     /* initialize block device list */
  502.     semMInit (&pScsiPhysDev->blkDevList.listMutexSem, blkDevListMutexOptions);
  503.     lstInit (&pScsiPhysDev->blkDevList.blkDevNodes);
  504.     if (reqSenseLength == 0)
  505. {
  506.         /* determine if device uses Extended Sense Data Format */
  507.         if (scsiReqSense (pScsiPhysDev, (char *) reqSenseData, 1) == ERROR)
  508.     {
  509.     SCSI_DEBUG_MSG ("scsiPhysDevCreate: REQUEST SENSE failed.n",
  510.     0, 0, 0, 0, 0, 0);
  511.             (void) scsiPhysDevDelete (pScsiPhysDev);
  512.     return ((SCSI_PHYS_DEV *) NULL);
  513.     }
  514.         SCSI_DEBUG_MSG ("scsiPhysDevCreate: reqSenseData[0] = %xn",
  515.         reqSenseData[0], 0, 0, 0, 0, 0);
  516.         if ((reqSenseData[0] & SCSI_SENSE_DATA_CLASS) != SCSI_EXT_SENSE_CLASS)
  517.     {
  518.     /* device uses Nonextended Sense Data Format */
  519.     pScsiPhysDev->extendedSense      = FALSE;
  520.     pScsiPhysDev->reqSenseDataLength = NON_EXT_SENSE_DATA_LENGTH;
  521.     }
  522.         else if ((reqSenseData[0] & SCSI_SENSE_DATA_CODE) !=
  523.   SCSI_EXT_SENSE_CODE)
  524.     {
  525.     /* device uses Unknown Sense Data Format */
  526.     errnoSet (S_scsiLib_DEV_UNSUPPORTED);
  527.     SCSI_DEBUG_MSG ("scsiPhysDevCreate: Unknown Sense Data Format ",
  528.     0, 0, 0, 0, 0, 0);
  529.     SCSI_DEBUG_MSG ("(device not supported)n", 0, 0, 0, 0, 0, 0);
  530.             (void) scsiPhysDevDelete (pScsiPhysDev);
  531.     return ((SCSI_PHYS_DEV *) NULL);
  532.     }
  533.         else
  534.     {
  535.     /* device uses Extended Sense Data Format */
  536.     if (scsiReqSense (pScsiPhysDev, (char *) reqSenseData,
  537.         REQ_SENSE_ADD_LENGTH_BYTE + 1) == ERROR)
  538.         {
  539.         SCSI_DEBUG_MSG ("scsiPhysDevCreate: REQUEST SENSE failed.n",
  540. 0, 0, 0, 0, 0, 0);
  541.                 (void) scsiPhysDevDelete (pScsiPhysDev);
  542.         return ((SCSI_PHYS_DEV *) NULL);
  543.         }
  544.     SCSI_DEBUG_MSG ("scsiPhysDevCreate: reqSenseData[7] = %xn",
  545.     reqSenseData[REQ_SENSE_ADD_LENGTH_BYTE],
  546.     0, 0, 0, 0, 0);
  547.     pScsiPhysDev->extendedSense      = TRUE;
  548.     pScsiPhysDev->reqSenseDataLength = REQ_SENSE_ADD_LENGTH_BYTE +
  549.         (int) reqSenseData [REQ_SENSE_ADD_LENGTH_BYTE] + 1;
  550.     }
  551. }
  552.     else
  553. {
  554. pScsiPhysDev->reqSenseDataLength = reqSenseLength;
  555. if (reqSenseLength == 4)
  556.     pScsiPhysDev->extendedSense = FALSE;
  557. else
  558.     pScsiPhysDev->extendedSense = TRUE;
  559. }
  560.     if ((pScsiPhysDev->pReqSenseData =
  561. (UINT8 *) calloc (pScsiPhysDev->reqSenseDataLength,
  562.   sizeof (UINT8))) == NULL)
  563. {
  564.         (void) scsiPhysDevDelete (pScsiPhysDev);
  565. return ((SCSI_PHYS_DEV *) NULL);
  566. }
  567.     /* transact an INQUIRY command if devType is unspecified */
  568.     if ((devType == NONE) || (removable == NONE))
  569.         {
  570. UINT8 inquiryData [DEFAULT_INQUIRY_DATA_LENGTH];
  571. int ix;
  572.         /* do an INQUIRY command */
  573. for (ix = 0; ix < DEFAULT_INQUIRY_DATA_LENGTH; ix++)
  574.     inquiryData[ix] = (UINT8) 0;
  575. inquiryRetry:
  576. if ((scsiInquiry (pScsiPhysDev, (char *) inquiryData,
  577.  sizeof (inquiryData)) == OK) &&
  578.     (inquiryData[0] != SCSI_LUN_NOT_PRESENT))
  579.     {
  580.     pScsiPhysDev->scsiDevType = inquiryData[0];
  581.     pScsiPhysDev->removable = (BOOL) (inquiryData[1] &
  582.       INQUIRY_REMOVABLE_MED_BIT);
  583.     bcopy ((char *) &inquiryData[8], pScsiPhysDev->devVendorID,
  584.    VENDOR_ID_LENGTH);
  585.     bcopy ((char *) &inquiryData[16], pScsiPhysDev->devProductID,
  586.    PRODUCT_ID_LENGTH);
  587.     bcopy ((char *) &inquiryData[32], pScsiPhysDev->devRevLevel,
  588.    REV_LEVEL_LENGTH);
  589.     pScsiPhysDev->devVendorID [VENDOR_ID_LENGTH] = EOS;
  590.     pScsiPhysDev->devProductID [PRODUCT_ID_LENGTH] = EOS;
  591.     pScsiPhysDev->devRevLevel [REV_LEVEL_LENGTH] = EOS;
  592.     }
  593. else if (pScsiPhysDev->resetFlag == TRUE)
  594.     {
  595.     pScsiPhysDev->resetFlag = FALSE;
  596.     SCSI_DEBUG_MSG ("retrying scsiInquiry...n", 0, 0, 0, 0, 0, 0);
  597.     goto inquiryRetry;
  598.     }
  599. else
  600.     {
  601.     if (inquiryData[0] == SCSI_LUN_NOT_PRESENT)
  602. {
  603. SCSI_DEBUG_MSG ("scsiPhysDevCreate: LUN not present.n",
  604. 0, 0, 0, 0, 0, 0);
  605. errnoSet (S_scsiLib_LUN_NOT_PRESENT);
  606. }
  607.     (void) scsiPhysDevDelete (pScsiPhysDev);
  608.     return ((SCSI_PHYS_DEV *) NULL);
  609.     }
  610.         }
  611.     else
  612.         {
  613. pScsiPhysDev->scsiDevType = (UINT8) devType;
  614. pScsiPhysDev->removable = removable;
  615.         }
  616.     /* record numBlocks and blockSize in physical device */
  617.     if (((pScsiPhysDev->scsiDevType == SCSI_DEV_DIR_ACCESS) ||
  618.       (pScsiPhysDev->scsiDevType == SCSI_DEV_WORM) ||
  619.       (pScsiPhysDev->scsiDevType == SCSI_DEV_RO_DIR_ACCESS)) &&
  620. ((numBlocks == 0) || (blockSize == 0)))
  621.         {
  622. int lastLogBlkAdrs;
  623. int blkLength;
  624.         /* do a READ_CAPACITY command */
  625. readCapRetry:
  626. if (scsiReadCapacity (pScsiPhysDev, &lastLogBlkAdrs, &blkLength) == OK)
  627.     {
  628.     pScsiPhysDev->numBlocks = lastLogBlkAdrs + 1;
  629.     pScsiPhysDev->blockSize = blkLength;
  630.     }
  631. else if (pScsiPhysDev->resetFlag == TRUE)
  632.     {
  633.     pScsiPhysDev->resetFlag = FALSE;
  634.     SCSI_DEBUG_MSG ("retrying scsiReadCapacity...n",
  635.     0, 0, 0, 0, 0, 0);
  636.     goto readCapRetry;
  637.     }
  638. else
  639.     {
  640.             (void) scsiPhysDevDelete (pScsiPhysDev);
  641.     return ((SCSI_PHYS_DEV *) NULL);
  642.     }
  643.         }
  644.     else
  645.         {
  646. pScsiPhysDev->numBlocks = numBlocks;
  647. pScsiPhysDev->blockSize = blockSize;
  648.         }
  649.     return (pScsiPhysDev);
  650.     }
  651. /*******************************************************************************
  652. *
  653. * scsi1PhysDevIdGet - return a pointer to a SCSI_PHYS_DEV structure
  654. *
  655. * This routine returns a pointer to the SCSI_PHYS_DEV structure of the SCSI
  656. * physical device located at a specified bus ID (`devBusId') and logical
  657. * unit number (`devLUN') and attached to a specified SCSI controller
  658. * (`pScsiCtrl').
  659. *
  660. * RETURNS: A pointer to the specified SCSI_PHYS_DEV structure, or NULL if the
  661. * structure does not exist.
  662. */
  663. LOCAL SCSI_PHYS_DEV * scsi1PhysDevIdGet
  664.     (
  665.     SCSI_CTRL *pScsiCtrl,       /* ptr to SCSI controller info */
  666.     int devBusId,               /* device's SCSI bus ID */
  667.     int devLUN                  /* device's logical unit number */
  668.     )
  669.     {
  670.     /* check for valid ptr to SCSI_CTRL */
  671.     if (pScsiCtrl == NULL)
  672. {
  673. if (pSysScsiCtrl != NULL)
  674.     pScsiCtrl = pSysScsiCtrl;
  675. else
  676.     {
  677.     errnoSet (S_scsiLib_NO_CONTROLLER);
  678.     SCSI_DEBUG_MSG ("No SCSI controller specified.n",
  679.     0, 0, 0, 0, 0, 0);
  680.     return ((SCSI_PHYS_DEV *) NULL);
  681.     }
  682. }
  683.     return (pScsiCtrl->physDevArr [(devBusId << 3) | devLUN]);
  684.     }
  685. /*******************************************************************************
  686. *
  687. * scsi1AutoConfig - configure all devices connected to a SCSI controller
  688. *
  689. * This routine cycles through all legal SCSI bus IDs (and logical unit
  690. * numbers (LUNs)), attempting a scsiPhysDevCreate() with default parameters
  691. * on each.  All devices which support the INQUIRY routine are
  692. * configured.  The scsiShow() routine can be used to find the system's table
  693. * of SCSI physical devices attached to a specified SCSI controller.  In
  694. * addition, scsiPhysDevIdGet() can be used programmatically to get a
  695. * pointer to the SCSI_PHYS_DEV structure associated with the device at a
  696. * specified SCSI bus ID and LUN.
  697. *
  698. * RETURNS: OK, or ERROR if `pScsiCtrl' and `pSysScsiCtrl' are both NULL.
  699. */
  700. LOCAL STATUS scsi1AutoConfig
  701.     (
  702.     SCSI_CTRL *pScsiCtrl       /* ptr to SCSI controller info */
  703.     )
  704.     {
  705.     int busId, lun; /* loop indices */
  706.     SCSI_PHYS_DEV *pScsiPhysDev; /* ptr to SCSI physical device info */
  707.     /* check for valid input parameters */
  708.     if (pScsiCtrl == (SCSI_CTRL *) NULL)
  709. {
  710. if (pSysScsiCtrl == (SCSI_CTRL *) NULL)
  711.     {
  712.     errnoSet (S_scsiLib_NO_CONTROLLER);
  713.     printErr ("No SCSI controller specified.n");
  714.     return (ERROR);
  715.     }
  716. pScsiCtrl = pSysScsiCtrl;
  717. }
  718.     /* loop through all SCSI bus ID's and LUN's (logical units); if a given
  719.      * bus ID times out during selection, do not test for other LUN's at
  720.      * that bus ID, since there cannot be any.
  721.      */
  722.     for (busId = SCSI_MIN_BUS_ID; busId <= SCSI_MAX_BUS_ID; busId++)
  723. {
  724. if (busId != pScsiCtrl->scsiCtrlBusId)
  725.     {
  726.             for (lun = SCSI_MIN_LUN; lun <= SCSI_MAX_LUN; lun++)
  727.         {
  728. SCSI_DEBUG_MSG ("scsiAutoConfig: bus ID = %d, LUN = %dn",
  729.         busId, lun, 0, 0, 0, 0);
  730.         if ((pScsiPhysDev = scsiPhysDevCreate
  731. (pScsiCtrl, busId, lun, 0, NONE, 0,
  732.  0, 0)) == (SCSI_PHYS_DEV *) NULL)
  733.     {
  734.     if (errnoGet () == S_scsiLib_SELECT_TIMEOUT)
  735.         break;
  736.     }
  737.         }
  738.     }
  739. }
  740.     return (OK);
  741.     }
  742. /*******************************************************************************
  743. *
  744. * strIsPrintable - determine whether a string contains all printable chars
  745. *
  746. * RETURNS: TRUE | FALSE.
  747. */
  748. LOCAL BOOL strIsPrintable
  749.     (
  750.     FAST char *pString          /* ptr to string to be tested */
  751.     )
  752.     {
  753.     FAST char ch;
  754.     while ((ch = *pString++) != EOS)
  755. {
  756. if (!isprint (ch))
  757.     return (FALSE);
  758. }
  759.     return (TRUE);
  760.     }
  761. /*******************************************************************************
  762. *
  763. * scsi1Show - list the physical devices attached to a SCSI controller
  764. *
  765. * This routine displays the SCSI bus ID, logical unit number (LUN), vendor ID,
  766. * product ID, firmware revision (rev.), device type, number of blocks,
  767. * block size in bytes, and a pointer to the associated SCSI_PHYS_DEV
  768. * structure for each physical SCSI device known to be attached to a specified
  769. * SCSI controller.
  770. *
  771. * NOTE:
  772. * If `pScsiCtrl' is NULL, the value of the global variable `pSysScsiCtrl'
  773. * is used, unless it is also NULL.
  774. *
  775. * RETURNS: OK, or ERROR if both `pScsiCtrl' and `pSysScsiCtrl' are NULL.
  776. */
  777. LOCAL STATUS scsi1Show
  778.     (
  779.     FAST SCSI_CTRL *pScsiCtrl           /* ptr to SCSI controller info */
  780.     )
  781.     {
  782.     FAST SCSI_PHYS_DEV *pScsiPhysDev; /* SCSI physical device info */
  783.     FAST int ix; /* loop variable */
  784.     if (pScsiCtrl == NULL)
  785. {
  786. if (pSysScsiCtrl != NULL)
  787.     pScsiCtrl = pSysScsiCtrl;
  788. else
  789.     {
  790.     errnoSet (S_scsiLib_NO_CONTROLLER);
  791.     SCSI_DEBUG_MSG ("No SCSI controller specified.n",
  792.     0, 0, 0, 0, 0, 0);
  793.     return (ERROR);
  794.     }
  795. }
  796.     printf ("ID LUN VendorID    ProductID     Rev. ");
  797.     printf ("Type  Blocks  BlkSize pScsiPhysDev n");
  798.     printf ("-- --- -------- ---------------- ---- ");
  799.     printf ("---- -------- ------- ------------n");
  800.     for (ix = 0; ix < MAX_SCSI_PHYS_DEVS; ix++)
  801. if ((pScsiPhysDev = pScsiCtrl->physDevArr[ix]) !=
  802.     (SCSI_PHYS_DEV *) NULL)
  803.     {
  804.     printf ("%2d " , pScsiPhysDev->scsiDevBusId);
  805.     printf ("%2d " , pScsiPhysDev->scsiDevLUN);
  806.     printf (" %8s" , strIsPrintable (pScsiPhysDev->devVendorID) ?
  807.      pScsiPhysDev->devVendorID : "        ");
  808.     printf (" %16s", strIsPrintable (pScsiPhysDev->devProductID) ?
  809.      pScsiPhysDev->devProductID : "                ");
  810.     printf (" %4s ", strIsPrintable (pScsiPhysDev->devRevLevel) ?
  811.      pScsiPhysDev->devRevLevel : "    ");
  812.     printf ("%3d"  , pScsiPhysDev->scsiDevType);
  813.     printf (pScsiPhysDev->removable ? "R" : " ");
  814.     printf (" %7d " , pScsiPhysDev->numBlocks);
  815.     printf (" %5d " , pScsiPhysDev->blockSize);
  816.     printf ("   0x%08x ", (int) pScsiPhysDev);
  817.     printf ("n");
  818.     }
  819.     return (OK);
  820.     }
  821. /*******************************************************************************
  822. *
  823. * scsi1BlkDevCreate - define a logical partition on a SCSI block device
  824. *
  825. * This routine creates and initializes a BLK_DEV structure, which
  826. * describes a logical partition on a SCSI physical block device.  A logical
  827. * partition is an array of contiguously addressed blocks; it can be completely
  828. * described by the number of blocks and the address of the first block in
  829. * the partition.  In normal configurations, partitions do not overlap, although
  830. * such a condition is not an error.
  831. *
  832. * NOTE:
  833. * If `numBlocks' is 0, the rest of device is used.
  834. *
  835. * RETURNS: A pointer to the created BLK_DEV, or NULL if parameters exceed
  836. * physical device boundaries, the physical device is not a block device, or
  837. * memory is insufficient for the structures.
  838. */
  839. LOCAL BLK_DEV *scsi1BlkDevCreate
  840.     (
  841.     SCSI_PHYS_DEV *pScsiPhysDev, /* ptr to SCSI physical device info */
  842.     int numBlocks,               /* number of blocks in block device */
  843.     int blockOffset              /* address of first block in volume */
  844.     )
  845.     {
  846.     SCSI_BLK_DEV      *pScsiBlkDev; /* ptr to SCSI block dev struct */
  847.     SCSI_BLK_DEV_NODE *pScsiBlkDevNode; /* ptr to SCSI block dev node struct */
  848.     /* check parameters for validity */
  849.     if ((pScsiPhysDev == NULL) ||
  850.         (numBlocks < 0) || (blockOffset < 0) ||
  851. ((blockOffset + numBlocks) > pScsiPhysDev->numBlocks))
  852. {
  853. errnoSet (S_scsiLib_ILLEGAL_PARAMETER);
  854. SCSI_DEBUG_MSG ("scsi1BlkDevCreate: Invalid input parameter(s).n",
  855. 0, 0, 0, 0, 0, 0);
  856. return ((BLK_DEV *) NULL);
  857. }
  858.     /* return NULL if sequential access (or other non-block) device */
  859.     if (!((pScsiPhysDev->scsiDevType == SCSI_DEV_DIR_ACCESS) ||
  860.        (pScsiPhysDev->scsiDevType == SCSI_DEV_WORM) ||
  861.        (pScsiPhysDev->scsiDevType == SCSI_DEV_RO_DIR_ACCESS)))
  862. {
  863. errnoSet (S_scsiLib_ILLEGAL_OPERATION);
  864. SCSI_DEBUG_MSG ("scsi1BlkDevCreate:", 0, 0, 0, 0, 0, 0);
  865. SCSI_DEBUG_MSG ("Physical device is not a block device.n",
  866. 0, 0, 0, 0, 0, 0);
  867. return ((BLK_DEV *) NULL);
  868. }
  869.     /* disallow multiple partitions on removable media */
  870.     if ((pScsiPhysDev->pScsiBlkDev != NULL) &&
  871. pScsiPhysDev->removable)
  872. {
  873. printErr ("scsi1BlkDevCreate: ");
  874. printErr ("Can't create multiple partitions on removable media.n");
  875. return ((BLK_DEV *) NULL);
  876. }
  877.     /* create a SCSI block device node structure */
  878.     pScsiBlkDevNode =
  879. (SCSI_BLK_DEV_NODE *) calloc (1, sizeof (SCSI_BLK_DEV_NODE));
  880.     if (pScsiBlkDevNode == NULL)
  881.         return ((BLK_DEV *) NULL);
  882.     pScsiBlkDev = &pScsiBlkDevNode->scsiBlkDev;
  883.     /* fill in the member data */
  884.     pScsiBlkDev->blkDev.bd_blkRd  = (FUNCPTR) scsiRdSecs;
  885.     pScsiBlkDev->blkDev.bd_blkWrt = (FUNCPTR) scsiWrtSecs;
  886.     pScsiBlkDev->blkDev.bd_ioctl  = (FUNCPTR) scsiBlkDevIoctl;
  887.     pScsiBlkDev->blkDev.bd_reset  = (FUNCPTR) NULL;
  888.     if (pScsiPhysDev->removable)
  889. pScsiBlkDev->blkDev.bd_statusChk = (FUNCPTR) scsiStatusCheck;
  890.     else
  891. pScsiBlkDev->blkDev.bd_statusChk = (FUNCPTR) NULL;
  892.     pScsiBlkDev->blkDev.bd_removable = pScsiPhysDev->removable;
  893.     pScsiBlkDev->blkDev.bd_nBlocks = (ULONG)
  894. (numBlocks == 0 ? pScsiPhysDev->numBlocks - blockOffset : numBlocks);
  895.     pScsiBlkDev->blkDev.bd_bytesPerBlk = (ULONG) pScsiPhysDev->blockSize;
  896.     pScsiBlkDev->blkDev.bd_retry = 1;
  897.     pScsiBlkDev->blkDev.bd_mode = O_RDWR;
  898.     pScsiBlkDev->blkDev.bd_readyChanged = TRUE;
  899.     pScsiBlkDev->pScsiPhysDev = pScsiPhysDev;
  900.     pScsiBlkDev->blockOffset = blockOffset;
  901.     pScsiBlkDev->numBlocks   = (int) pScsiBlkDev->blkDev.bd_nBlocks;
  902.     /* add block device to list created on the physical device */
  903.     semTake (&pScsiPhysDev->blkDevList.listMutexSem, WAIT_FOREVER);
  904.     lstAdd (&pScsiPhysDev->blkDevList.blkDevNodes,
  905.     &pScsiBlkDevNode->blkDevNode);
  906.     semGive (&pScsiPhysDev->blkDevList.listMutexSem);
  907.     return (&pScsiBlkDev->blkDev);
  908.     }
  909. /*******************************************************************************
  910. *
  911. * scsi1BlkDevInit - initialize fields in a SCSI logical partition
  912. *
  913. * This routine specifies the disk geometry parameters required by certain
  914. * file systems (e.g., dosFs).  It should be called after a SCSI_BLK_DEV
  915. * structure is created via scsiBlkDevCreate(), but before a file system
  916. * initialization routine.  It is generally required only for removable media
  917. * devices.
  918. *
  919. * RETURNS: N/A
  920. */
  921. LOCAL void scsi1BlkDevInit
  922.     (
  923.     SCSI_BLK_DEV *pScsiBlkDev,  /* ptr to SCSI block dev. struct */
  924.     int blksPerTrack,           /* blocks per track */
  925.     int nHeads                  /* number of heads */
  926.     )
  927.     {
  928.     pScsiBlkDev->blkDev.bd_blksPerTrack = (ULONG) blksPerTrack;
  929.     pScsiBlkDev->blkDev.bd_nHeads = (ULONG) nHeads;
  930.     }
  931. /*******************************************************************************
  932. *
  933. * scsi1BlkDevShow - show the BLK_DEV structures on a specified physical device
  934. *
  935. * This routine displays all of the BLK_DEV structures created on a specified
  936. * physical device.  This routine is called by scsiShow(), but may also be
  937. * invoked directly, usually from the shell.
  938. *
  939. * RETURNS: N/A
  940. */
  941. LOCAL void scsi1BlkDevShow
  942.     (
  943.     SCSI_PHYS_DEV *pScsiPhysDev  /* ptr to SCSI physical device info */
  944.     )
  945.     {
  946.     SCSI_BLK_DEV_NODE *pScsiBlkDevNode;
  947.     int ix = 0;
  948.     printf ("Block Device #       physical address     size (blocks)n");
  949.     printf ("--------------       ----------------     -------------n");
  950.     if (lstCount (&pScsiPhysDev->blkDevList.blkDevNodes) == 0)
  951. return;
  952.     semTake (&pScsiPhysDev->blkDevList.listMutexSem, WAIT_FOREVER);
  953.     for (pScsiBlkDevNode = (SCSI_BLK_DEV_NODE *)
  954.        lstFirst (&pScsiPhysDev->blkDevList.blkDevNodes);
  955.          pScsiBlkDevNode != NULL;
  956.          pScsiBlkDevNode = (SCSI_BLK_DEV_NODE *)
  957.        lstNext (&pScsiBlkDevNode->blkDevNode))
  958.         {
  959. printf ("%8d              %8d                %8dn", ix++,
  960. pScsiBlkDevNode->scsiBlkDev.blockOffset,
  961. pScsiBlkDevNode->scsiBlkDev.numBlocks);
  962. }
  963.     semGive (&pScsiPhysDev->blkDevList.listMutexSem);
  964.     }
  965. /*******************************************************************************
  966. *
  967. * scsi1BusReset - pulse the reset signal on the SCSI bus
  968. *
  969. * This routine calls a controller-specific routine to reset a specified
  970. * controller's SCSI bus.  If no controller is specified (`pScsiCtrl' is 0),
  971. * the value in `pSysScsiCtrl' is used.
  972. *
  973. * RETURNS: OK, or ERROR if there is no controller or controller-specific
  974. * routine.
  975. */
  976. LOCAL STATUS scsi1BusReset
  977.     (
  978.     SCSI_CTRL *pScsiCtrl /* ptr to SCSI controller info */
  979.     )
  980.     {
  981.     if (pScsiCtrl->scsiBusReset == (VOIDFUNCPTR) NULL)
  982. return (ERROR);
  983.     else
  984. {
  985. if (pScsiCtrl == (SCSI_CTRL *) NULL)
  986.     {
  987.     if (pSysScsiCtrl != (SCSI_CTRL *) NULL)
  988.         pScsiCtrl = pSysScsiCtrl;
  989.     else
  990. {
  991.         errnoSet (S_scsiLib_NO_CONTROLLER);
  992.         printErr ("No SCSI controller specified.n");
  993. return (ERROR);
  994. }
  995.     }
  996. (pScsiCtrl->scsiBusReset) (pScsiCtrl);
  997. return (OK);
  998. }
  999.     }
  1000. /*******************************************************************************
  1001. *
  1002. * scsiDevSelect - call the scsiDevSelect routine in the SCSI_CTRL structure
  1003. *
  1004. * This routine is not intended to be called directly by users, but rather
  1005. * by other routines in scsiLib.  It merely calls a driver-specific routine
  1006. * to select the desired SCSI physical device.
  1007. *
  1008. * RETURNS: OK if device was successfully selected, otherwise ERROR.
  1009. */
  1010. LOCAL STATUS scsiDevSelect
  1011.     (
  1012.     SCSI_PHYS_DEV *pScsiPhysDev,        /* ptr to SCSI physical device */
  1013.     SCSI_TRANSACTION *pScsiXaction      /* ptr to SCSI transaction info */
  1014.     )
  1015.     {
  1016.     return ((*pScsiPhysDev->pScsiCtrl->scsiDevSelect)
  1017.         (pScsiPhysDev, pScsiXaction));
  1018.     }
  1019. /*******************************************************************************
  1020. *
  1021. * scsi1PhaseNameGet - get the name of a specified SCSI phase
  1022. *
  1023. * This routine returns a pointer to a string which is the name of the SCSI
  1024. * phase input as an integer.  It's primarily used to improve readability of
  1025. * debugging messages.
  1026. *
  1027. * RETURNS: A pointer to a string naming the SCSI phase input
  1028. *
  1029. * NOMANUAL
  1030. */
  1031. LOCAL char *scsi1PhaseNameGet
  1032.     (
  1033.     int scsiPhase               /* phase whose name to look up */
  1034.     )
  1035.     {
  1036.     static char *phaseNameArray [] =
  1037. {
  1038. "DATA_OUT",
  1039. "DATA_IN ",
  1040. "COMMAND ",
  1041. "STATUS  ",
  1042. "UNDEF(4)",
  1043. "UNDEF(5)",
  1044. "MSG_OUT ",
  1045. "MSG_IN  "
  1046. };
  1047.     return ((scsiPhase < SCSI_DATA_OUT_PHASE ||
  1048.      scsiPhase > SCSI_MSG_IN_PHASE) ?
  1049.      "UNKNOWN " : phaseNameArray [scsiPhase]);
  1050.     }
  1051. /*******************************************************************************
  1052. *
  1053. * scsi1CmdBuild - fills in the fields of a SCSI command descriptor block
  1054. *
  1055. * Typically, this routine is not called directly by the user, but by other
  1056. * routines in scsiLib.  It fills in fields of a SCSI-command descriptor block
  1057. * based on the input parameters.  The field layouts vary based on the command
  1058. * group, which is determined from the `opCode'.
  1059. *
  1060. * RETURNS: ERROR if vendor-unique command group or out-of-bounds parameter,
  1061. * otherwise OK.
  1062. *
  1063. * NOMANUAL
  1064. */
  1065. LOCAL STATUS scsi1CmdBuild
  1066.     (
  1067.     SCSI_COMMAND scsiCmd,       /* command to be built */
  1068.     int *pCmdLength,            /* ptr to command length variable */
  1069.     UINT8 opCode,               /* SCSI opCode for command */
  1070.     int LUN,                    /* logical unit number for command */
  1071.     BOOL relAdrs,               /* whether to set relative address bit */
  1072.     int logBlockAdrs,           /* logical block address */
  1073.     int xferLength,             /* number of blocks or bytes to xfer */
  1074.     UINT8 controlByte           /* control byte for command */
  1075.     )
  1076.     {
  1077.     FAST int groupCode = (int) (opCode >> 5);
  1078.     FAST int cmdLength;
  1079.     /* array with the length of a SCSI command indexed by its group code
  1080.      * (NONE == vendor unique)
  1081.      */
  1082.     LOCAL int scsiCmdLength [8] =
  1083.         {
  1084.         SCSI_GROUP_0_CMD_LENGTH,
  1085.         SCSI_GROUP_1_CMD_LENGTH,
  1086.         NONE,
  1087.         NONE,
  1088.         NONE,
  1089.         SCSI_GROUP_5_CMD_LENGTH,
  1090.         NONE,
  1091.         NONE
  1092.         };
  1093.     if ((*pCmdLength = cmdLength = scsiCmdLength [groupCode]) == NONE)
  1094. return (ERROR);
  1095.     if ((groupCode == 0) && (logBlockAdrs > 0x1fffff || xferLength > 0xff))
  1096. return (ERROR);
  1097.     else if (xferLength > 0xffff)
  1098. return (ERROR);
  1099.     scsiCmd[0] = opCode;
  1100.     scsiCmd[1] = (UINT8) ((LUN & 0x7) << 5);
  1101.     switch (groupCode)
  1102. {
  1103. case 0:
  1104.     scsiCmd[1] |= (UINT8) ((logBlockAdrs >> 16) & 0x1f);
  1105.     scsiCmd[2]  = (UINT8) ((logBlockAdrs >>  8) & 0xff);
  1106.     scsiCmd[3]  = (UINT8) ((logBlockAdrs      ) & 0xff);
  1107.     scsiCmd[4]  = (UINT8) xferLength;
  1108.     scsiCmd[5]  = controlByte;
  1109.     break;
  1110. case 1:
  1111. case 5:
  1112.     scsiCmd[1] |= (UINT8) (relAdrs ? 1 : 0);
  1113.     scsiCmd[2]  = (UINT8) ((logBlockAdrs >> 24) & 0xff);
  1114.     scsiCmd[3]  = (UINT8) ((logBlockAdrs >> 16) & 0xff);
  1115.     scsiCmd[4]  = (UINT8) ((logBlockAdrs >>  8) & 0xff);
  1116.     scsiCmd[5]  = (UINT8) ((logBlockAdrs      ) & 0xff);
  1117.     scsiCmd[6]  = (UINT8) 0;
  1118.     if (groupCode == 5)
  1119. {
  1120.         scsiCmd[7]  = (UINT8) 0;
  1121.         scsiCmd[8]  = (UINT8) 0;
  1122. }
  1123.     scsiCmd [cmdLength - 3] = (UINT8) ((xferLength >> 8) & 0xff);
  1124.     scsiCmd [cmdLength - 2] = (UINT8) ((xferLength     ) & 0xff);
  1125.     scsiCmd [cmdLength - 1] = controlByte;
  1126.     break;
  1127. }
  1128.     return (OK);
  1129.     }
  1130. /*******************************************************************************
  1131. *
  1132. * scsi1TestUnitRdy - issue a TEST_UNIT_READY command to a SCSI device
  1133. *
  1134. * This routine issues a TEST_UNIT_READY command to a specified SCSI device.
  1135. *
  1136. * RETURNS: OK, or ERROR if the command fails.
  1137. */
  1138. LOCAL STATUS scsi1TestUnitRdy
  1139.     (
  1140.     SCSI_PHYS_DEV *pScsiPhysDev         /* ptr to SCSI physical device */
  1141.     )
  1142.     {
  1143.     SCSI_COMMAND testUnitRdyCommand; /* SCSI command byte array */
  1144.     SCSI_TRANSACTION scsiXaction; /* info on a SCSI transaction */
  1145.     SCSI_DEBUG_MSG ("scsiTestUnitRdy:n", 0, 0, 0, 0, 0, 0);
  1146.     if (scsiCmdBuild (testUnitRdyCommand, &scsiXaction.cmdLength,
  1147. SCSI_OPCODE_TEST_UNIT_READY, pScsiPhysDev->scsiDevLUN, FALSE,
  1148. 0, 0, (UINT8) 0)
  1149. == ERROR)
  1150.     return (ERROR);
  1151.     scsiXaction.cmdAddress    = testUnitRdyCommand;
  1152.     scsiXaction.dataAddress   = NULL;
  1153.     scsiXaction.dataDirection = NONE;
  1154.     scsiXaction.dataLength    = 0;
  1155.     scsiXaction.addLengthByte = NONE;
  1156.     scsiXaction.cmdTimeout    = SCSI_TIMEOUT_5SEC;
  1157.     return ((*pScsiPhysDev->pScsiCtrl->scsiTransact)
  1158.     (pScsiPhysDev, &scsiXaction));
  1159.     }
  1160. /*******************************************************************************
  1161. *
  1162. * scsiStatusCheck - called by filesystems before doing open()'s or creat()'s
  1163. *
  1164. * This routine issues a TEST_UNIT_READY command to a SCSI device to detect a
  1165. * medium change.
  1166. *
  1167. * RETURNS: OK or ERROR.
  1168. */
  1169. LOCAL STATUS scsiStatusCheck
  1170.     (
  1171.     BLK_DEV *pBlkDev                    /* ptr to a block dev */
  1172.     )
  1173.     {
  1174.     SCSI_PHYS_DEV *pScsiPhysDev; /* ptr to SCSI physical device */
  1175.     SCSI_COMMAND testUnitRdyCommand; /* SCSI command byte array */
  1176.     SCSI_TRANSACTION scsiXaction; /* info on a SCSI transaction */
  1177.     pScsiPhysDev = ((SCSI_BLK_DEV *) pBlkDev)->pScsiPhysDev;
  1178.     if (scsiCmdBuild (testUnitRdyCommand, &scsiXaction.cmdLength,
  1179. SCSI_OPCODE_TEST_UNIT_READY, pScsiPhysDev->scsiDevLUN, FALSE,
  1180. 0, 0, (UINT8) 0) == ERROR)
  1181. {
  1182.         return (ERROR);
  1183. }
  1184.     scsiXaction.cmdAddress    = testUnitRdyCommand;
  1185.     scsiXaction.dataAddress   = NULL;
  1186.     scsiXaction.dataDirection = NONE;
  1187.     scsiXaction.dataLength    = 0;
  1188.     scsiXaction.addLengthByte = NONE;
  1189.     scsiXaction.cmdTimeout    = SCSI_TIMEOUT_5SEC;
  1190.     (*pScsiPhysDev->pScsiCtrl->scsiTransact) (pScsiPhysDev, &scsiXaction);
  1191.     if ((pScsiPhysDev->lastSenseKey != SCSI_SENSE_KEY_NO_SENSE) &&
  1192.         (pScsiPhysDev->lastSenseKey != SCSI_SENSE_KEY_UNIT_ATTENTION))
  1193. {
  1194. SCSI_DEBUG_MSG ("scsiStatusCheck returning ERROR, last Sense = %xn",
  1195.         pScsiPhysDev->lastSenseKey, 0, 0, 0, 0, 0);
  1196. return (ERROR);
  1197. }
  1198.     else
  1199. return (OK);
  1200.     }
  1201. /*******************************************************************************
  1202. *
  1203. * scsi1FormatUnit - issue a FORMAT_UNIT command to a SCSI device
  1204. *
  1205. * This routine issues a FORMAT_UNIT command to a specified SCSI device.
  1206. *
  1207. * RETURNS: OK, or ERROR if the command fails.
  1208. */
  1209. LOCAL STATUS scsi1FormatUnit
  1210.     (
  1211.     SCSI_PHYS_DEV *pScsiPhysDev,/* ptr to SCSI physical device */
  1212.     BOOL cmpDefectList,         /* whether defect list is complete */
  1213.     int defListFormat,          /* defect list format */
  1214.     int vendorUnique,           /* vendor unique byte */
  1215.     int interleave,             /* interleave factor */
  1216.     char *buffer,               /* ptr to input data buffer */
  1217.     int bufLength               /* length of buffer in bytes */
  1218.     )
  1219.     {
  1220.     SCSI_COMMAND formatUnitCommand; /* SCSI command byte array */
  1221.     SCSI_TRANSACTION scsiXaction; /* info on a SCSI transaction */
  1222.     SCSI_DEBUG_MSG ("scsiFormatUnit:n", 0, 0, 0, 0, 0, 0);
  1223.     formatUnitCommand[0] = SCSI_OPCODE_FORMAT_UNIT;
  1224.     formatUnitCommand[1] = (UINT8) ((pScsiPhysDev->scsiDevLUN & 0x7) << 5);
  1225.     if (buffer != (char *) NULL)
  1226. {
  1227. formatUnitCommand[1] |= SCSI_FORMAT_DATA_BIT;
  1228. if (cmpDefectList)
  1229.     formatUnitCommand[1] |= SCSI_COMPLETE_LIST_BIT;
  1230. formatUnitCommand[1] |= (defListFormat & 0x07);
  1231. }
  1232.     formatUnitCommand[2]  = (UINT8) vendorUnique;
  1233.     formatUnitCommand[3]  = (UINT8) ((interleave >> 8) & 0xff);
  1234.     formatUnitCommand[4]  = (UINT8) ((interleave     ) & 0xff);
  1235.     formatUnitCommand[5]  = (UINT8) 0;
  1236.     scsiXaction.cmdAddress    = formatUnitCommand;
  1237.     scsiXaction.cmdLength     = SCSI_GROUP_0_CMD_LENGTH;
  1238.     scsiXaction.dataAddress   = (UINT8 *) buffer;
  1239.     scsiXaction.dataDirection = O_WRONLY;
  1240.     scsiXaction.dataLength    = bufLength;
  1241.     scsiXaction.addLengthByte = NONE;
  1242.     scsiXaction.cmdTimeout    = SCSI_TIMEOUT_FULL;
  1243.     return ((*pScsiPhysDev->pScsiCtrl->scsiTransact)
  1244.     (pScsiPhysDev, &scsiXaction));
  1245.     }
  1246. /*******************************************************************************
  1247. *
  1248. * scsi1Inquiry - issue an INQUIRY command to a SCSI device
  1249. *
  1250. * This routine issues an INQUIRY command to a specified SCSI device.
  1251. *
  1252. * RETURNS: OK, or ERROR if the command fails.
  1253. */
  1254. LOCAL STATUS scsi1Inquiry
  1255.     (
  1256.     SCSI_PHYS_DEV *pScsiPhysDev,/* ptr to SCSI physical device */
  1257.     char *buffer,               /* ptr to input data buffer */
  1258.     int bufLength               /* length of buffer in bytes */
  1259.     )
  1260.     {
  1261.     SCSI_COMMAND inquiryCommand; /* SCSI command byte array */
  1262.     SCSI_TRANSACTION scsiXaction; /* info on a SCSI transaction */
  1263.     SCSI_DEBUG_MSG ("scsiInquiry:n", 0, 0, 0, 0, 0, 0);
  1264.     if (scsiCmdBuild (inquiryCommand, &scsiXaction.cmdLength,
  1265. SCSI_OPCODE_INQUIRY, pScsiPhysDev->scsiDevLUN, FALSE,
  1266. 0, bufLength, (UINT8) 0)
  1267. == ERROR)
  1268.     return (ERROR);
  1269.     scsiXaction.cmdAddress    = inquiryCommand;
  1270.     scsiXaction.dataAddress   = (UINT8 *) buffer;
  1271.     scsiXaction.dataDirection = O_RDONLY;
  1272.     scsiXaction.dataLength    = bufLength;
  1273.     scsiXaction.addLengthByte = INQUIRY_ADD_LENGTH_BYTE;
  1274.     scsiXaction.cmdTimeout    = SCSI_TIMEOUT_5SEC;
  1275.     return ((*pScsiPhysDev->pScsiCtrl->scsiTransact)
  1276.     (pScsiPhysDev, &scsiXaction));
  1277.     }
  1278. /*******************************************************************************
  1279. *
  1280. * scsi1ModeSelect - issue a MODE_SELECT command to a SCSI device
  1281. *
  1282. * This routine issues a MODE_SELECT command to a specified SCSI device.
  1283. *
  1284. * RETURNS: OK, or ERROR if the command fails.
  1285. */
  1286. LOCAL STATUS scsi1ModeSelect
  1287.     (
  1288.     SCSI_PHYS_DEV *pScsiPhysDev,/* ptr to SCSI physical device */
  1289.     int pageFormat,             /* value of the page format bit (0-1) */
  1290.     int saveParams,             /* value of the save parameters bit (0-1) */
  1291.     char *buffer,               /* ptr to output data buffer */
  1292.     int bufLength               /* length of buffer in bytes */
  1293.     )
  1294.     {
  1295.     SCSI_COMMAND modeSelectCommand; /* SCSI command byte array */
  1296.     SCSI_TRANSACTION scsiXaction; /* info on a SCSI transaction */
  1297.     int tempLBAField; /* "logical block address" field */
  1298.     SCSI_DEBUG_MSG ("scsiModeSelect:n", 0, 0, 0, 0, 0, 0);
  1299.     tempLBAField = (pageFormat ? (1 << 20) : 0) | (saveParams ? (1 << 16) : 0);
  1300.     if (scsiCmdBuild (modeSelectCommand, &scsiXaction.cmdLength,
  1301. SCSI_OPCODE_MODE_SELECT, pScsiPhysDev->scsiDevLUN, FALSE,
  1302. tempLBAField, min (0xff, bufLength), (UINT8) 0)
  1303. == ERROR)
  1304.     return (ERROR);
  1305.     scsiXaction.cmdAddress    = modeSelectCommand;
  1306.     scsiXaction.dataAddress   = (UINT8 *) buffer;
  1307.     scsiXaction.dataDirection = O_WRONLY;
  1308.     scsiXaction.dataLength    = min (0xff, bufLength);
  1309.     scsiXaction.addLengthByte = NONE;
  1310.     scsiXaction.cmdTimeout    = SCSI_TIMEOUT_5SEC;
  1311.     return ((*pScsiPhysDev->pScsiCtrl->scsiTransact)
  1312.     (pScsiPhysDev, &scsiXaction));
  1313.     }
  1314. /*******************************************************************************
  1315. *
  1316. * scsi1ModeSense - issue a MODE_SENSE command to a SCSI device
  1317. *
  1318. * This routine issues a MODE_SENSE command to a specified SCSI device.
  1319. *
  1320. * RETURNS: OK, or ERROR if the command fails.
  1321. */
  1322. LOCAL STATUS scsi1ModeSense
  1323.     (
  1324.     SCSI_PHYS_DEV *pScsiPhysDev,/* ptr to SCSI physical device */
  1325.     int pageControl,            /* value of the page control field (0-3) */
  1326.     int pageCode,               /* value of the page code field (0-0x3f) */
  1327.     char *buffer,               /* ptr to input data buffer */
  1328.     int bufLength               /* length of buffer in bytes */
  1329.     )
  1330.     {
  1331.     SCSI_COMMAND modeSenseCommand; /* SCSI command byte array */
  1332.     SCSI_TRANSACTION scsiXaction; /* info on a SCSI transaction */
  1333.     SCSI_DEBUG_MSG ("scsiModeSense:n", 0, 0, 0, 0, 0, 0);
  1334.     if (scsiCmdBuild (modeSenseCommand, &scsiXaction.cmdLength,
  1335. SCSI_OPCODE_MODE_SENSE, pScsiPhysDev->scsiDevLUN, FALSE,
  1336. 0, min (0xff, bufLength), (UINT8) 0)
  1337. == ERROR)
  1338.     return (ERROR);
  1339.     modeSenseCommand [2] = (UINT8) ((pageControl << 6) | pageCode);
  1340.     scsiXaction.cmdAddress    = modeSenseCommand;
  1341.     scsiXaction.dataAddress   = (UINT8 *) buffer;
  1342.     scsiXaction.dataDirection = O_RDONLY;
  1343.     scsiXaction.dataLength    = min (0xff, bufLength);
  1344.     scsiXaction.addLengthByte = MODE_SENSE_ADD_LENGTH_BYTE;
  1345.     scsiXaction.cmdTimeout    = SCSI_TIMEOUT_5SEC;
  1346.     return ((*pScsiPhysDev->pScsiCtrl->scsiTransact)
  1347.     (pScsiPhysDev, &scsiXaction));
  1348.     }
  1349. /*******************************************************************************
  1350. *
  1351. * scsi1ReadCapacity - issue a READ_CAPACITY command to a SCSI device
  1352. *
  1353. * This routine issues a READ_CAPACITY command to a specified SCSI device.
  1354. *
  1355. * RETURNS: OK, or ERROR if the command fails.
  1356. */
  1357. LOCAL STATUS scsi1ReadCapacity
  1358.     (
  1359.     SCSI_PHYS_DEV *pScsiPhysDev,/* ptr to SCSI physical device */
  1360.     int *pLastLBA,              /* where to return last logical block address */
  1361.     int *pBlkLength             /* where to return block length */
  1362.     )
  1363.     {
  1364.     SCSI_COMMAND readCapCommand; /* SCSI command byte array */
  1365.     RD_CAP_DATA readCapData; /* data structure for results */
  1366.     SCSI_TRANSACTION scsiXaction; /* info on a SCSI transaction */
  1367.     SCSI_DEBUG_MSG ("scsiReadCapacity:n", 0, 0, 0, 0, 0, 0);
  1368.     if (scsiCmdBuild (readCapCommand, &scsiXaction.cmdLength,
  1369. SCSI_OPCODE_READ_CAPACITY, pScsiPhysDev->scsiDevLUN, FALSE,
  1370. 0, 0, (UINT8) 0)
  1371. == ERROR)
  1372.     return (ERROR);
  1373.     scsiXaction.cmdAddress    = readCapCommand;
  1374.     scsiXaction.dataAddress   = (UINT8 *) &readCapData;
  1375.     scsiXaction.dataDirection = O_RDONLY;
  1376.     scsiXaction.dataLength    = sizeof (readCapData);
  1377.     scsiXaction.addLengthByte = NONE;
  1378.     scsiXaction.cmdTimeout    = SCSI_TIMEOUT_5SEC;
  1379.     if ((*pScsiPhysDev->pScsiCtrl->scsiTransact) (pScsiPhysDev, &scsiXaction)
  1380. == ERROR)
  1381. return (ERROR);
  1382.     else
  1383. {
  1384. *pLastLBA   = readCapData.lastLogBlkAdrs;
  1385. *pBlkLength = readCapData.blkLength;
  1386. SCSI_SWAB (pLastLBA, sizeof (*pLastLBA));
  1387. SCSI_SWAB (pBlkLength, sizeof (*pBlkLength));
  1388. return (OK);
  1389. }
  1390.     }
  1391. /*******************************************************************************
  1392. *
  1393. * scsi1RdSecs - read sector(s) from a SCSI block device
  1394. *
  1395. * This routine reads the specified physical sector(s) from a specified
  1396. * physical device.
  1397. *
  1398. * RETURNS: OK, or ERROR if the sector cannot be read.
  1399. */
  1400. LOCAL STATUS scsi1RdSecs
  1401.     (
  1402.     SCSI_BLK_DEV *pScsiBlkDev,  /* ptr to SCSI block device info */
  1403.     int sector,                 /* sector number to read */
  1404.     int numSecs,                /* total sectors to read */
  1405.     char *buffer                /* ptr to input data buffer */
  1406.     )
  1407.     {
  1408.     SCSI_COMMAND readCommand; /* SCSI command byte array */
  1409.     SCSI_TRANSACTION scsiXaction; /* info on a SCSI transaction */
  1410.     SCSI_PHYS_DEV *pScsiPhysDev = pScsiBlkDev->pScsiPhysDev;
  1411.     int startSec = sector + pScsiBlkDev->blockOffset;
  1412.     SCSI_DEBUG_MSG ("scsiRdSecs:n", 0, 0, 0, 0, 0, 0);
  1413.     if (startSec <= 0x1FFFFF && numSecs <= 256)
  1414.         {
  1415.         /* build a 21 bit logical block address 'O_RDONLY' command */
  1416. if (scsiCmdBuild (readCommand, &scsiXaction.cmdLength,
  1417.   SCSI_OPCODE_READ, pScsiPhysDev->scsiDevLUN, FALSE,
  1418.   startSec, (numSecs == 256 ? 0 : numSecs), (UINT8) 0)
  1419.     == ERROR)
  1420.     return (ERROR);
  1421.         }
  1422.     else
  1423.         {
  1424.         /* build a 32 bit logical block address 'READ_EXTENDED' command */
  1425. if (scsiCmdBuild (readCommand, &scsiXaction.cmdLength,
  1426.   SCSI_OPCODE_READ_EXT, pScsiPhysDev->scsiDevLUN, FALSE,
  1427.   startSec, numSecs, (UINT8) 0)
  1428.     == ERROR)
  1429.     return (ERROR);
  1430.         }
  1431.     scsiXaction.cmdAddress    = readCommand;
  1432.     scsiXaction.dataAddress   = (UINT8 *) buffer;
  1433.     scsiXaction.dataDirection = O_RDONLY;
  1434.     scsiXaction.dataLength    = numSecs * pScsiPhysDev->blockSize;
  1435.     scsiXaction.addLengthByte = NONE;
  1436.     if (numSecs < 2000)
  1437. scsiXaction.cmdTimeout = SCSI_TIMEOUT_5SEC +
  1438.  (SCSI_TIMEOUT_1SEC * numSecs);
  1439.     else
  1440. scsiXaction.cmdTimeout = SCSI_TIMEOUT_FULL;
  1441.     return ((*pScsiPhysDev->pScsiCtrl->scsiTransact)
  1442.     (pScsiPhysDev, &scsiXaction));
  1443.     }
  1444. /*******************************************************************************
  1445. *
  1446. * scsi1WrtSecs - write sector(s) to a SCSI block device
  1447. *
  1448. * This routine writes the specified physical sector(s) to a specified physical
  1449. * device.
  1450. *
  1451. * RETURNS: OK, or ERROR if the sector cannot be written.
  1452. */
  1453. LOCAL STATUS scsi1WrtSecs
  1454.     (
  1455.     SCSI_BLK_DEV *pScsiBlkDev,  /* ptr to SCSI block device info */
  1456.     int sector,                 /* sector number to write */
  1457.     int numSecs,                /* total sectors to write */
  1458.     char *buffer                /* ptr to input data buffer */
  1459.     )
  1460.     {
  1461.     SCSI_COMMAND writeCommand; /* SCSI command byte array */
  1462.     SCSI_TRANSACTION scsiXaction; /* info on a SCSI transaction */
  1463.     SCSI_PHYS_DEV *pScsiPhysDev = pScsiBlkDev->pScsiPhysDev;
  1464.     int startSec = sector + pScsiBlkDev->blockOffset;
  1465.     SCSI_DEBUG_MSG ("scsiWrtSecs:n", 0, 0, 0, 0, 0, 0);
  1466.     if (startSec <= 0x1FFFFF && numSecs <= 256)
  1467.         {
  1468.         /* build a 21 bit logical block address 'O_WRONLY' command */
  1469. if (scsiCmdBuild (writeCommand, &scsiXaction.cmdLength,
  1470.   SCSI_OPCODE_WRITE, pScsiPhysDev->scsiDevLUN, FALSE,
  1471.   startSec, (numSecs == 256 ? 0 : numSecs), (UINT8) 0)
  1472.     == ERROR)
  1473.     {
  1474.     return (ERROR);
  1475.     }
  1476.         }
  1477.     else
  1478.         {
  1479.         /* build a 32 bit logical block address 'WRITE_EXTENDED' command */
  1480. if (scsiCmdBuild (writeCommand, &scsiXaction.cmdLength,
  1481.   SCSI_OPCODE_WRITE_EXT, pScsiPhysDev->scsiDevLUN,
  1482.   FALSE, startSec, numSecs, (UINT8) 0)
  1483.     == ERROR)
  1484.     return (ERROR);
  1485.         }
  1486.     scsiXaction.cmdAddress    = writeCommand;
  1487.     scsiXaction.dataAddress   = (UINT8 *) buffer;
  1488.     scsiXaction.dataDirection = O_WRONLY;
  1489.     scsiXaction.dataLength    = numSecs * pScsiPhysDev->blockSize;
  1490.     scsiXaction.addLengthByte = NONE;
  1491.     if (numSecs < 2000)
  1492. scsiXaction.cmdTimeout = SCSI_TIMEOUT_5SEC +
  1493.  (SCSI_TIMEOUT_1SEC * numSecs);
  1494.     else
  1495. scsiXaction.cmdTimeout = SCSI_TIMEOUT_FULL;
  1496.     return ((*pScsiPhysDev->pScsiCtrl->scsiTransact)
  1497.     (pScsiPhysDev, &scsiXaction));
  1498.     }
  1499. /*******************************************************************************
  1500. *
  1501. * scsi1ReqSense - issue a REQUEST_SENSE command to a device and read the results
  1502. *
  1503. * This routine issues a REQUEST_SENSE command to a specified SCSI device and
  1504. * read the results.
  1505. *
  1506. * RETURNS: OK, or ERROR if the command fails.
  1507. */
  1508. LOCAL STATUS scsi1ReqSense
  1509.     (
  1510.     SCSI_PHYS_DEV *pScsiPhysDev,/* ptr to SCSI physical device */
  1511.     char *buffer,               /* ptr to input data buffer */
  1512.     int bufLength               /* length of buffer in bytes */
  1513.     )
  1514.     {
  1515.     SCSI_COMMAND reqSenseCommand; /* SCSI command byte array */
  1516.     SCSI_TRANSACTION scsiXaction; /* info on a SCSI transaction */
  1517.     SCSI_DEBUG_MSG ("scsiReqSense:n", 0, 0, 0, 0, 0, 0);
  1518.     if (scsiCmdBuild (reqSenseCommand, &scsiXaction.cmdLength,
  1519.       SCSI_OPCODE_REQUEST_SENSE, pScsiPhysDev->scsiDevLUN,
  1520.       FALSE, 0, bufLength, (UINT8) 0)
  1521.         == ERROR)
  1522.         return (ERROR);
  1523.     scsiXaction.cmdAddress    = reqSenseCommand;
  1524.     scsiXaction.dataAddress   = (UINT8 *) buffer;
  1525.     scsiXaction.dataDirection = O_RDONLY;
  1526.     scsiXaction.dataLength    = bufLength;
  1527.     scsiXaction.addLengthByte = REQ_SENSE_ADD_LENGTH_BYTE;
  1528.     scsiXaction.cmdTimeout    = SCSI_TIMEOUT_5SEC;
  1529.     return ((*pScsiPhysDev->pScsiCtrl->scsiTransact)
  1530.     (pScsiPhysDev, &scsiXaction));
  1531.     }
  1532. /*******************************************************************************
  1533. *
  1534. * scsiPhaseSequence - manage all phases of a single SCSI bus sequence
  1535. *
  1536. * This routine is called by scsiTransact after a device has been successfully
  1537. * selected.  It repeated calls the appropriate routine to detect the current
  1538. * SCSI bus phase.  It takes whatever action is specified in the supplied
  1539. * SCSI_TRANSACTION structure, usually calling the appropiate routines to
  1540. * input or output bytes to the device.
  1541. *
  1542. * RETURNS: OK, or ERROR if not successful for any reason.
  1543. */
  1544. LOCAL STATUS scsiPhaseSequence
  1545.     (
  1546.     SCSI_PHYS_DEV *pScsiPhysDev,        /* ptr to the target device */
  1547.     SCSI_TRANSACTION *pScsiXaction      /* ptr to the transaction info */
  1548.     )
  1549.     {
  1550.     SCSI_CTRL *pScsiCtrl; /* SCSI controller info for device */
  1551.     STATUS status; /* routine return status */
  1552.     int scsiPhase; /* passed to scsiBusPhaseGet routine */
  1553.     UINT8 msgIn [MAX_MSG_IN_BYTES]; /* message returned from the SCSI device */
  1554.     UINT8 *pMsgIn; /* ptr to next dest. for a message in */
  1555.     BOOL transactionComplete; /* set TRUE upon 'disconn' or 'comm complete' */
  1556.     pScsiCtrl = pScsiPhysDev->pScsiCtrl;
  1557.     /* save current command context requested */
  1558.     pScsiPhysDev->pScsiXaction = pScsiXaction;
  1559.     transactionComplete = FALSE;
  1560.     if ((status = scsiDevSelect (pScsiPhysDev, pScsiXaction)) == ERROR)
  1561. {
  1562. SCSI_DEBUG_MSG ("scsiPhaseSequence: Unable to select device.n",
  1563. 0, 0, 0, 0, 0, 0);
  1564. return (ERROR);
  1565. }
  1566.     do
  1567. {
  1568. if ((*pScsiCtrl->scsiBusPhaseGet) (pScsiCtrl, pScsiXaction->cmdTimeout,
  1569.    &scsiPhase) != OK)
  1570.     {
  1571.     SCSI_DEBUG_MSG ("scsiBusPhaseGet returned ERROR.n",
  1572.     0, 0, 0, 0, 0, 0);
  1573.     return (ERROR);
  1574.     }
  1575. phaseSwitch:
  1576.         switch (scsiPhase)
  1577.     {
  1578.     case SCSI_DATA_OUT_PHASE:
  1579.         status = (*pScsiCtrl->scsiBytesOut)
  1580.      (pScsiPhysDev, pScsiXaction->dataAddress,
  1581.       pScsiXaction->dataLength, scsiPhase);
  1582. if (status == ERROR)
  1583.     {
  1584.     return (ERROR);
  1585.     }
  1586.         break;
  1587.     case SCSI_DATA_IN_PHASE:
  1588. {
  1589. int addLengthByte = pScsiXaction->addLengthByte;
  1590. int dataLength = pScsiXaction->dataLength;
  1591. UINT8 *dataAddress = pScsiXaction->dataAddress;
  1592. if ((addLengthByte == NONE) ||
  1593.     (dataLength <= (addLengthByte + 1)))
  1594.     {
  1595.             status = (*pScsiCtrl->scsiBytesIn)
  1596.          (pScsiPhysDev, dataAddress,
  1597.           dataLength, scsiPhase);
  1598.     if (status == ERROR)
  1599.         {
  1600.         return (ERROR);
  1601.         }
  1602.     }
  1603. else
  1604.     {
  1605.             status = (*pScsiCtrl->scsiBytesIn)
  1606.          (pScsiPhysDev, dataAddress,
  1607.           addLengthByte + 1, scsiPhase);
  1608.     if (status == ERROR)
  1609.         {
  1610.         return (ERROR);
  1611.         }
  1612.     if ((*pScsiCtrl->scsiBusPhaseGet) (pScsiCtrl, 0, &scsiPhase) != OK)
  1613.         {
  1614. SCSI_DEBUG_MSG ("scsiBusPhaseGet returned ERROR.n",
  1615. 0, 0, 0, 0, 0, 0);
  1616.         return (ERROR);
  1617.         }
  1618. if (scsiPhase != SCSI_DATA_IN_PHASE)
  1619.     goto phaseSwitch;
  1620.             status = (*pScsiCtrl->scsiBytesIn)
  1621.          (pScsiPhysDev,
  1622.   dataAddress + addLengthByte + 1,
  1623.   min (dataAddress [addLengthByte],
  1624.        dataLength - (addLengthByte + 1)),
  1625.   scsiPhase);
  1626.     if (status == ERROR)
  1627.         {
  1628.         return (ERROR);
  1629.         }
  1630.     }
  1631.         break;
  1632. }
  1633.     case SCSI_COMMAND_PHASE:
  1634. status = (*pScsiCtrl->scsiBytesOut)
  1635.      (pScsiPhysDev, pScsiXaction->cmdAddress,
  1636.       pScsiXaction->cmdLength, scsiPhase);
  1637. if (status != OK)
  1638.     {
  1639.     return (ERROR);
  1640.     }
  1641. break;
  1642.     case SCSI_STATUS_PHASE:
  1643.         status = (*pScsiCtrl->scsiBytesIn)
  1644.      (pScsiPhysDev, &pScsiXaction->statusByte,
  1645.       sizeof (pScsiXaction->statusByte), scsiPhase);
  1646. if (status == ERROR)
  1647.     {
  1648.     return (ERROR);
  1649.     }
  1650.         break;
  1651.     case SCSI_MSG_OUT_PHASE:
  1652.         status = (*pScsiCtrl->scsiBytesOut)
  1653.      (pScsiPhysDev, pScsiPhysDev->msgOutArray,
  1654.       pScsiPhysDev->msgLength, scsiPhase);
  1655. if (status == ERROR)
  1656.     {
  1657.     return (ERROR);
  1658.     }
  1659. else
  1660.     pScsiPhysDev->msgLength = 0;
  1661.         break;
  1662.     case SCSI_MSG_IN_PHASE:
  1663. pMsgIn = msgIn;
  1664.         status = (*pScsiCtrl->scsiBytesIn)
  1665.      (pScsiPhysDev, pMsgIn++, sizeof (UINT8),
  1666.       scsiPhase);
  1667. if (status == ERROR)
  1668.     {
  1669.     return (ERROR);
  1670.     }
  1671. switch (msgIn[0])
  1672.     {
  1673.     case SCSI_MSG_COMMAND_COMPLETE:
  1674. SCSI_DEBUG_MSG ("Command Complete message received.n",
  1675. 0, 0, 0, 0, 0, 0);
  1676. break;
  1677.     case SCSI_MSG_EXTENDED_MESSAGE:
  1678.         if ((*pScsiCtrl->scsiBusPhaseGet) (pScsiCtrl,
  1679. pScsiXaction->cmdTimeout, &scsiPhase) != OK)
  1680.                  {
  1681.                  SCSI_DEBUG_MSG ("scsiBusPhaseGet returned ERROR.n",
  1682.                                  0, 0, 0, 0, 0, 0);
  1683.                  return (ERROR);
  1684.                  }
  1685. if (scsiPhase != SCSI_MSG_IN_PHASE)
  1686.     break;
  1687.          status = (*pScsiCtrl->scsiBytesIn)
  1688.           (pScsiPhysDev, pMsgIn++, sizeof (UINT8),
  1689.            scsiPhase);
  1690. if (status == ERROR)
  1691.          {
  1692.          return (ERROR);
  1693.          }
  1694.         if ((*pScsiCtrl->scsiBusPhaseGet) (pScsiCtrl,
  1695. pScsiXaction->cmdTimeout, &scsiPhase) != OK)
  1696.                  {
  1697.                  SCSI_DEBUG_MSG ("scsiBusPhaseGet returned ERROR.n",
  1698.                                  0, 0, 0, 0, 0, 0);
  1699.                  return (ERROR);
  1700.                  }
  1701. if (scsiPhase != SCSI_MSG_IN_PHASE)
  1702.     break;
  1703.          status = (*pScsiCtrl->scsiBytesIn)
  1704.           (pScsiPhysDev, pMsgIn, (int) msgIn[1],
  1705.            scsiPhase);
  1706. if (status == ERROR)
  1707.          {
  1708.          return (ERROR);
  1709.          }
  1710. switch (msgIn[2])
  1711.     {
  1712. /*XXX
  1713. SYNC transfer not supported for 5.1 version.
  1714.     case SCSI_EXT_MSG_SYNC_XFER_REQ:
  1715. pScsiPhysDev->syncXferPeriod = msgIn[3] * 4;
  1716. if (msgIn[4] > 0)
  1717.     {
  1718.     pScsiPhysDev->syncXferOffset = msgIn[4];
  1719.     pScsiPhysDev->syncXfer = (TBOOL) TRUE;
  1720.     }
  1721. break;
  1722. XXX*/
  1723.     default:
  1724. SCSI_DEBUG_MSG ("unknown extended messagen",
  1725. 0, 0, 0, 0, 0, 0);
  1726.     }
  1727. break;
  1728.     case SCSI_MSG_SAVE_DATA_POINTER:
  1729. SCSI_DEBUG_MSG ("Save Data Pointer message inn",
  1730. 0, 0, 0, 0, 0, 0);
  1731. break;
  1732.     case SCSI_MSG_RESTORE_POINTERS:
  1733. SCSI_DEBUG_MSG ("Restore Pointers message inn",
  1734. 0, 0, 0, 0, 0, 0);
  1735. break;
  1736.     case SCSI_MSG_DISCONNECT:
  1737. SCSI_DEBUG_MSG ("Disconnect message inn",
  1738. 0, 0, 0, 0, 0, 0);
  1739. break;
  1740.     case SCSI_MSG_MESSAGE_REJECT:
  1741. SCSI_DEBUG_MSG ("Message Reject message inn",
  1742. 0, 0, 0, 0, 0, 0);
  1743. break;
  1744.     case SCSI_MSG_NO_OP:
  1745. SCSI_DEBUG_MSG ("No Operation message inn",
  1746. 0, 0, 0, 0, 0, 0);
  1747. break;
  1748.     default:
  1749. if (msgIn[0] & SCSI_MSG_IDENTIFY)
  1750.     {
  1751.     SCSI_DEBUG_MSG ("Identify message inn",
  1752.     0, 0, 0, 0, 0, 0);
  1753.     }
  1754. else
  1755.     {
  1756.     SCSI_DEBUG_MSG ("message (%x) inn",
  1757.     msgIn[0], 0, 0, 0, 0, 0);
  1758.     }
  1759. break;
  1760.     }
  1761.         break;
  1762.     case SCSI_BUS_FREE_PHASE:
  1763. transactionComplete = TRUE;
  1764. status = OK;
  1765.         break;
  1766.     }
  1767. } while (!transactionComplete);
  1768.     return (status);
  1769.     }
  1770. /*******************************************************************************
  1771. *
  1772. * scsi1Transact - obtain exclusive use of SCSI controller for a transaction
  1773. *
  1774. * This routine calls scsiPhaseSequence() to execute the command specified.
  1775. * If there are physical path management errors, then this routine returns
  1776. * ERROR.  If not, then the status returned from the command is checked.  If
  1777. * it is "Check Condition", then a "Request Sense" CCS command is executed
  1778. * and the sense key is examined.  An indication of the success of the
  1779. * command is returned (OK or ERROR).
  1780. *
  1781. * RETURNS: OK, or ERROR if a path management error occurs
  1782. * or the status or sense information indicates an error.
  1783. *
  1784. * NOMANUAL
  1785. */
  1786. LOCAL STATUS scsi1Transact
  1787.     (
  1788.     SCSI_PHYS_DEV *pScsiPhysDev,        /* ptr to the target device */
  1789.     SCSI_TRANSACTION *pScsiXaction      /* ptr to the transaction info */
  1790.     )
  1791.     {
  1792.     SCSI_CTRL *pScsiCtrl; /* SCSI controller info for device */
  1793.     SCSI_BLK_DEV_NODE *pBlkDevNode; /* ptr for looping through BLK_DEV list */
  1794.     STATUS status; /* routine return status */
  1795.     int senseKey; /* extended sense key from target */
  1796.     int addSenseCode; /* additional sense code from target */
  1797.     int taskId = taskIdSelf (); /* calling task's ID */
  1798.     int taskPriority; /* calling task's current priority */
  1799.     pScsiCtrl = pScsiPhysDev->pScsiCtrl;
  1800.     /* set task priority to SCSI controller's (if != NONE) */
  1801.     if (pScsiCtrl->scsiPriority != NONE)
  1802. {
  1803. taskPriorityGet (taskId, &taskPriority);
  1804. taskPrioritySet (taskId, pScsiCtrl->scsiPriority);
  1805. }
  1806.     /* take the device and controller semaphores */
  1807.     semTake (&pScsiPhysDev->devMutexSem, WAIT_FOREVER);
  1808.     semTake (&pScsiCtrl->ctrlMutexSem, WAIT_FOREVER);
  1809.     if ((status = scsiPhaseSequence (pScsiPhysDev, pScsiXaction)) == ERROR)
  1810. {
  1811. SCSI_DEBUG_MSG ("scsiTransact: scsiPhaseSequence ERROR.n",
  1812. 0, 0, 0, 0, 0, 0);
  1813. goto cleanExit;
  1814. }
  1815.     /* check device status and take appropriate action */
  1816.     switch (pScsiXaction->statusByte & SCSI_STATUS_MASK)
  1817. {
  1818. case SCSI_STATUS_GOOD:
  1819.     status = OK;
  1820.     pScsiPhysDev->lastSenseKey = SCSI_SENSE_KEY_NO_SENSE;
  1821.     pScsiPhysDev->lastAddSenseCode = (UINT8) 0;
  1822.     goto cleanExit;
  1823. case SCSI_STATUS_CHECK_CONDITION:
  1824.     {
  1825.     SCSI_COMMAND reqSenseCmd; /* REQUEST SENSE command */
  1826.     SCSI_TRANSACTION reqSenseXaction; /* REQUEST SENSE xaction */
  1827. /* REQUEST SENSE buffer  */
  1828.             UINT8 reqSenseData [REQ_SENSE_ADD_LENGTH_BYTE + 1];
  1829.     /* build a REQUEST SENSE command and transact it */
  1830.     (void) scsiCmdBuild (reqSenseCmd, &reqSenseXaction.cmdLength,
  1831.     SCSI_OPCODE_REQUEST_SENSE,
  1832.  pScsiPhysDev->scsiDevLUN, FALSE, 0,
  1833.  pScsiPhysDev->reqSenseDataLength, (UINT8) 0);
  1834.     reqSenseXaction.cmdAddress    = (UINT8 *) reqSenseCmd;
  1835.     /* if there is no user request sense buffer ,supply it */
  1836.     if ( pScsiPhysDev->pReqSenseData == (UINT8 *)NULL )
  1837. {
  1838.                 reqSenseXaction.dataAddress  = reqSenseData;
  1839. if (!pScsiPhysDev->extendedSense)
  1840.     reqSenseXaction.dataLength    = 4;
  1841.                 else
  1842.     reqSenseXaction.dataLength = REQ_SENSE_ADD_LENGTH_BYTE + 1;
  1843.                 } 
  1844.             else
  1845. {
  1846.         reqSenseXaction.dataAddress   = pScsiPhysDev->pReqSenseData;
  1847.         reqSenseXaction.dataLength    = 
  1848.                            pScsiPhysDev->reqSenseDataLength;
  1849.                 }
  1850.     reqSenseXaction.dataDirection = O_RDONLY;
  1851.     reqSenseXaction.addLengthByte = REQ_SENSE_ADD_LENGTH_BYTE;
  1852.     reqSenseXaction.cmdTimeout    = SCSI_TIMEOUT_5SEC;
  1853.     SCSI_DEBUG_MSG ("scsiTransact: issuing a REQUEST SENSE command.n",
  1854.     0, 0, 0, 0, 0, 0);
  1855.     if ((status = scsiPhaseSequence (pScsiPhysDev, &reqSenseXaction))
  1856. == ERROR)
  1857. {
  1858. SCSI_DEBUG_MSG ("scsiTransact: scsiPhaseSequence ERROR.n",
  1859. 0, 0, 0, 0, 0, 0);
  1860. goto cleanExit;
  1861. }
  1862.     /* REQUEST SENSE command status != GOOD indicates fatal error */
  1863.     if (reqSenseXaction.statusByte != SCSI_STATUS_GOOD)
  1864. {
  1865. SCSI_DEBUG_MSG ("scsiTransact: non-zero REQ SENSE status.n",
  1866. 0, 0, 0, 0, 0, 0);
  1867. errnoSet (S_scsiLib_REQ_SENSE_ERROR);
  1868. status = ERROR;
  1869. goto cleanExit;
  1870. }
  1871.     /* if device uses Nonextended Sense Data Format, return now */
  1872.     if (!pScsiPhysDev->extendedSense)
  1873. {
  1874. status = ERROR;
  1875. goto cleanExit;
  1876. }
  1877.     /* check sense key and take appropriate action */
  1878.     pScsiPhysDev->lastSenseKey =
  1879. (pScsiPhysDev->pReqSenseData)[2] & SCSI_SENSE_KEY_MASK;
  1880.     pScsiPhysDev->lastAddSenseCode = (pScsiPhysDev->pReqSenseData)[12];
  1881.     addSenseCode = (int) pScsiPhysDev->lastAddSenseCode;
  1882.     switch (senseKey = (int) pScsiPhysDev->lastSenseKey)
  1883.         {
  1884.         case SCSI_SENSE_KEY_NO_SENSE:
  1885.             {
  1886.             SCSI_DEBUG_MSG ("scsiTransact: No Sensen",
  1887.     0, 0, 0, 0, 0, 0);
  1888.             status = OK;
  1889.             goto cleanExit;
  1890.             }
  1891.         case SCSI_SENSE_KEY_RECOVERED_ERROR:
  1892.             {
  1893.     SCSI_DEBUG_MSG ("scsiTransact: Recovered Error Sense,",
  1894.     0, 0, 0, 0, 0, 0);
  1895.     SCSI_DEBUG_MSG ("Additional Sense Code = 0x%02xn",
  1896.     addSenseCode, 0, 0, 0, 0, 0);
  1897.             status = OK;
  1898.             goto cleanExit;
  1899.             }
  1900.         case SCSI_SENSE_KEY_NOT_READY:
  1901.             {
  1902.     SCSI_DEBUG_MSG ("scsiTransact: Not Ready Sense,",
  1903.     0, 0, 0, 0, 0, 0);
  1904.     SCSI_DEBUG_MSG ("Additional Sense Code = 0x%02xn",
  1905.     addSenseCode, 0, 0, 0, 0, 0);
  1906.             errnoSet (S_scsiLib_DEV_NOT_READY);
  1907.             status = ERROR;
  1908.             goto cleanExit;
  1909.             }
  1910.         case SCSI_SENSE_KEY_UNIT_ATTENTION:
  1911.             {
  1912.     SCSI_DEBUG_MSG ("scsiTransact: Unit Attention Sense,",
  1913.     0, 0, 0, 0, 0, 0);
  1914.     SCSI_DEBUG_MSG ("Additional Sense Code = 0x%02xn",
  1915.     addSenseCode, 0, 0, 0, 0, 0);
  1916.     if (addSenseCode == 0x28)
  1917. {
  1918.      semTake (&pScsiPhysDev->blkDevList.listMutexSem, WAIT_FOREVER);
  1919.      for (pBlkDevNode = (SCSI_BLK_DEV_NODE *)
  1920.          lstFirst
  1921.      (&pScsiPhysDev->blkDevList.blkDevNodes);
  1922.                pBlkDevNode != NULL;
  1923.                pBlkDevNode = (SCSI_BLK_DEV_NODE *)
  1924.  lstNext (&pBlkDevNode->blkDevNode))
  1925.       {
  1926.     pBlkDevNode->scsiBlkDev.blkDev.bd_readyChanged =
  1927.         TRUE;
  1928.                }
  1929.      semGive (&pScsiPhysDev->blkDevList.listMutexSem);
  1930. }
  1931.     else if (addSenseCode == 0x29)
  1932. {
  1933. pScsiPhysDev->resetFlag = TRUE;
  1934. }
  1935.     /* issue a MODE SENSE command */
  1936.          {
  1937.          UINT8 modeSenseHeader [4];    /* mode sense data header */
  1938.          SCSI_COMMAND modeSenseCommand;/* SCSI command byte array */
  1939.          SCSI_TRANSACTION scsiXaction; /* info on a SCSI xaction */
  1940.          if (scsiCmdBuild (modeSenseCommand, &scsiXaction.cmdLength,
  1941.       SCSI_OPCODE_MODE_SENSE,
  1942.       pScsiPhysDev->scsiDevLUN, FALSE,
  1943.       0, sizeof (modeSenseHeader), (UINT8) 0)
  1944. == ERROR)
  1945. goto cleanExit;
  1946.          scsiXaction.cmdAddress    = modeSenseCommand;
  1947.          scsiXaction.dataAddress   = modeSenseHeader;
  1948.          scsiXaction.dataDirection = O_RDONLY;
  1949.          scsiXaction.dataLength    = sizeof (modeSenseHeader);
  1950.          scsiXaction.addLengthByte = MODE_SENSE_ADD_LENGTH_BYTE;
  1951.     scsiXaction.cmdTimeout    = SCSI_TIMEOUT_5SEC;
  1952.          SCSI_DEBUG_MSG ("scsiTransact: issuing a MODE SENSE cmd.n",
  1953.     0, 0, 0, 0, 0, 0);
  1954.          if ((status = scsiPhaseSequence (pScsiPhysDev,
  1955.      &scsiXaction)) == ERROR)
  1956. {
  1957. SCSI_DEBUG_MSG ("scsiPhaseSequence returned ERRORn",
  1958. 0, 0, 0, 0, 0, 0);
  1959. goto cleanExit;
  1960. }
  1961.          /* MODE SENSE command status != GOOD indicates
  1962.      * fatal error
  1963.      */
  1964.          if (scsiXaction.statusByte != SCSI_STATUS_GOOD)
  1965. {
  1966. SCSI_DEBUG_MSG ("scsiTransact: bad MODE SELECT stat.n",
  1967. 0, 0, 0, 0, 0, 0);
  1968. status = ERROR;
  1969. goto cleanExit;
  1970. }
  1971.          else
  1972. {
  1973.      semTake (&pScsiPhysDev->blkDevList.listMutexSem, WAIT_FOREVER);
  1974.      for (pBlkDevNode = (SCSI_BLK_DEV_NODE *)
  1975.          lstFirst
  1976.      (&pScsiPhysDev->blkDevList.blkDevNodes);
  1977.                pBlkDevNode != NULL;
  1978.                pBlkDevNode = (SCSI_BLK_DEV_NODE *)
  1979.  lstNext (&pBlkDevNode->blkDevNode))
  1980.       {
  1981.     pBlkDevNode->scsiBlkDev.blkDev.bd_mode =
  1982.              (modeSenseHeader [2] & (UINT8) 0x80) ? O_RDONLY
  1983.      : O_RDWR;
  1984.                }
  1985.      semGive (&pScsiPhysDev->blkDevList.listMutexSem);
  1986. SCSI_DEBUG_MSG ("Write-protect bit = %x.n",
  1987.              (modeSenseHeader [2] & (UINT8) 0x80),
  1988. 0, 0, 0, 0, 0);
  1989. }
  1990.          }
  1991.     errnoSet (S_scsiLib_UNIT_ATTENTION);
  1992.             status = ERROR;
  1993.             goto cleanExit;
  1994.             }
  1995.         case SCSI_SENSE_KEY_DATA_PROTECT:
  1996.             {
  1997.     SCSI_DEBUG_MSG ("scsiTransact: Data Protect Sense,",
  1998.     0, 0, 0, 0, 0, 0);
  1999.     SCSI_DEBUG_MSG ("Additional Sense Code = 0x%02xn",
  2000.     addSenseCode, 0, 0, 0, 0, 0);
  2001.     if (addSenseCode == 0x27)
  2002. errnoSet (S_scsiLib_WRITE_PROTECTED);
  2003.             status = ERROR;
  2004.             goto cleanExit;
  2005.             }
  2006.         default:
  2007.     {
  2008.     SCSI_DEBUG_MSG ("scsiTransact: Sense = %x,",
  2009.     senseKey, 0, 0, 0, 0, 0);
  2010.     SCSI_DEBUG_MSG ("Additional Sense Code = 0x%02xn",
  2011.     addSenseCode, 0, 0, 0, 0, 0);
  2012.             status = ERROR;
  2013.             goto cleanExit;
  2014.             }
  2015.         }
  2016.     }
  2017. case SCSI_STATUS_BUSY:
  2018.     errnoSet (S_scsiLib_DEV_NOT_READY);
  2019.     SCSI_DEBUG_MSG ("device returned busy status.n", 0, 0, 0, 0, 0, 0);
  2020.     status = ERROR;
  2021.     break;
  2022. default:
  2023.     status = ERROR;
  2024. }
  2025. cleanExit:
  2026.     /* give back controller and device mutual exclusion semaphores */
  2027.     semGive (&pScsiCtrl->ctrlMutexSem);
  2028.     semGive (&pScsiPhysDev->devMutexSem);
  2029.     /* restore task's normal priority, if previously altered */
  2030.     if (pScsiCtrl->scsiPriority != NONE)
  2031.         taskPrioritySet (taskId, taskPriority);
  2032.     return (status);
  2033.     }
  2034. /*******************************************************************************
  2035. *
  2036. * scsi1Ioctl - perform a device-specific control function
  2037. *
  2038. * This routine performs a specified function using a specified SCSI block 
  2039. * device.
  2040. *
  2041. * RETURNS: The status of the request, or ERROR if the request is unsupported.
  2042. */
  2043. LOCAL STATUS scsi1Ioctl
  2044.     (
  2045.     SCSI_PHYS_DEV *pScsiPhysDev,/* ptr to SCSI block device info */
  2046.     int function,               /* function code */
  2047.     int arg                     /* argument to pass called function */
  2048.     )
  2049.     {
  2050.     switch (function)
  2051.         {
  2052.         case FIOSCSICOMMAND:
  2053.     return ((*pScsiPhysDev->pScsiCtrl->scsiTransact)
  2054.     (pScsiPhysDev, (SCSI_TRANSACTION *) arg));
  2055.         case FIODISKFORMAT:
  2056.     /* issue a FORMAT UNIT command with default parameters */
  2057.     return (scsiFormatUnit (pScsiPhysDev, 0, 0, 0, 0,
  2058.     (char *) NULL, 0));
  2059.         default:
  2060.     errnoSet (S_ioLib_UNKNOWN_REQUEST);
  2061.     return (ERROR);
  2062.         }
  2063.     }
  2064. /*******************************************************************************
  2065. *
  2066. * scsiBlkDevIoctl - call scsiIoctl() with pointer to SCSI physical device
  2067. *     associated with the specified SCSI block device
  2068. *
  2069. * RETURNS: Status of scsiIoctl call.
  2070. */
  2071. LOCAL STATUS scsiBlkDevIoctl
  2072.     (
  2073.     SCSI_BLK_DEV *pScsiBlkDev,  /* ptr to SCSI block device info */
  2074.     int function,               /* function code */
  2075.     int arg                     /* argument to pass called function */
  2076.     )
  2077.     {
  2078.     return (scsiIoctl (pScsiBlkDev->pScsiPhysDev, function, arg));
  2079.     }
  2080. /*******************************************************************************
  2081. *
  2082. *  scsiBuildByteMsgOut - Build a single byte message out. 
  2083. *
  2084. * Typically, this routine is not called directly by the user, but by other
  2085. * routines in scsiLib.  It fills an array supplied by the user with the message
  2086. * code and check if it's a legal message for an initiator.
  2087. * If the `scsiMsgType' is SCSI_MSG_IDENT_DISCONNECT or SCSI_MSG_IDENTIFY a 
  2088. * status ERROR will be returned.  The disconnect and identify message have to be 
  2089. * built by the driver. 
  2090. *
  2091. * RETURNS:OK  ,otherwise ERROR if pMsgout is NULL or the scsiMsgType is not
  2092. * supported or not correct for an initiator.
  2093. *
  2094. * NOMANUAL
  2095. */
  2096. STATUS scsiBuildByteMsgOut
  2097.     (
  2098.     UINT8 *pMsgOut, /* ptr to message array */
  2099.     UINT8 scsiMsgType  /* Single byte message code to send */
  2100.     )
  2101.     {
  2102.     if (pMsgOut == NULL )
  2103.         return (ERROR);
  2104.     /* Check for a legal Message */
  2105.     switch ( scsiMsgType )
  2106. {
  2107.         case SCSI_MSG_COMMAND_COMPLETE:
  2108.         case SCSI_MSG_EXTENDED_MESSAGE: 
  2109. case SCSI_MSG_SAVE_DATA_POINTER:
  2110. case SCSI_MSG_RESTORE_POINTERS: 
  2111. case SCSI_MSG_DISCONNECT:
  2112. case SCSI_MSG_LINK_CMD_COMPLETE:
  2113. case SCSI_MSG_LINK_CMD_FLAG_COMP:
  2114.         case SCSI_MSG_IDENT_DISCONNECT:
  2115.         case SCSI_MSG_IDENTIFY:
  2116.             /* That could not be send by an initiator or that 's handle by the 
  2117.                driver ( identify message ) */
  2118.             return ( ERROR);
  2119.         
  2120. case SCSI_MSG_INITOR_DETECT_ERR:
  2121. case SCSI_MSG_ABORT:
  2122. case SCSI_MSG_MESSAGE_REJECT:
  2123. case SCSI_MSG_NO_OP:
  2124. case SCSI_MSG_MSG_PARITY_ERR:
  2125. case SCSI_MSG_BUS_DEVICE_RESET:
  2126.             *pMsgOut = scsiMsgType;
  2127.             break;
  2128. default:
  2129.             /* unknown message */
  2130.             return (ERROR);
  2131. }
  2132.     return (OK);
  2133.     }
  2134. /*******************************************************************************
  2135. *
  2136. *  scsiBuildExtMsgOut - Build a skeleton for an extended message out. 
  2137. *
  2138. * Typically, this routine is not called directly by the user, but by other
  2139. * routines in scsiLib.  It fills an array supplied by the user with the message
  2140. * code and checks if it's a legal message.  The `scsiMsgType' is the extended
  2141. * message type code.  It fills only the fixed fields in the message out 
  2142. * array.  The specific values for the extended message have to be filled by
  2143. * the caller. 
  2144. *    
  2145. *
  2146. * RETURNS:OK  ,otherwise ERROR if pMsgout is NULL or the scsiMsgType is not 
  2147. * supported.
  2148. *
  2149. * NOMANUAL
  2150. */
  2151. STATUS scsiBuildExtMsgOut
  2152.     (
  2153.     UINT8 *pMsgOut, /* ptr to message array */
  2154.     UINT8 scsiMsgType  /* Single byte message code to send */
  2155.     )
  2156.     {
  2157.     if (pMsgOut == NULL )
  2158.         return (ERROR);
  2159.     /* Check for a legal Message */
  2160.     switch ( scsiMsgType )
  2161. {
  2162. case SCSI_EXT_MSG_SYNC_XFER_REQ:
  2163.     *pMsgOut++ = SCSI_MSG_EXTENDED_MESSAGE;
  2164.             *pMsgOut++ = SCSI_SYNC_XFER_REQ_MSG_LENGTH;
  2165.             *pMsgOut   = SCSI_EXT_MSG_SYNC_XFER_REQ;
  2166.     break;
  2167. case SCSI_EXT_MSG_WIDE_XFER_REQ:
  2168.     *pMsgOut++ = SCSI_MSG_EXTENDED_MESSAGE;
  2169.             *pMsgOut++ = SCSI_WIDE_XFER_REQ_MSG_LENGTH;
  2170.             *pMsgOut++ = SCSI_EXT_MSG_WIDE_XFER_REQ;
  2171.     break;
  2172. default:
  2173.             /* unknown message or not supportted by an initiator */
  2174.             return (ERROR);
  2175. }
  2176.     return (OK);
  2177.     }
  2178. /*******************************************************************************
  2179. *
  2180. *  scsiSyncTarget - initiate an agreement for a synchronous protocol
  2181. *
  2182. * This routine could be used to setup a synchronous protocol between the 
  2183. * initiator and a scsi target.  It uses the scsi test unit ready command with 
  2184. * a selection with attention to negotiate a pair of extended sync messages.
  2185. * It builds an extended sync message out with the `syncVal' and `offsetVal' 
  2186. * round up to the closest value supported by the controller.
  2187. *  
  2188. *.CS
  2189. * `pScsiPhysDev'  pointer to the SCSI_PHYS_DEV info.
  2190. *
  2191. * `syncVal'  wished scsi REQ/ACK period value in 4ns step 
  2192. * (e.g 40 means 160ns).
  2193. *
  2194. * `offsetVal'  wished offset value.
  2195. *
  2196. * `pSyncVal' pointer used to return the controller values used and 
  2197. * the target response values in a SCSI_SYNC_AGREEMENT 
  2198. * structure.
  2199. *.CE
  2200. *
  2201. * The last parameter allows the caller to know the round up values sent 
  2202. * in the initiator message out and what are the values returned by the 
  2203. * target.   
  2204. *.CS
  2205. *
  2206. * typedef struct 
  2207. *     {  
  2208. *     int syncPeriodCtrl;   /@ round up period available with the controller @/
  2209. *     int syncOffsetCtrl;   /@ round up offset available with the controller @/
  2210. *     int syncPeriodTarget; /@ Period value returned by the target @/
  2211. *     int syncOffsetTarget; /@ Offset value returned by the target @/
  2212. *     } SCSI_SYNC_AGREEMENT;
  2213. *
  2214. * NOTE: As this routine is setting up and using the SCSI_PHYS_DEV structure, it
  2215. * must be used when no scsi activity occurs on the device.
  2216. * A good matter to set up the synchronous protocol is to send this command 
  2217. * after a scsiPhysDevCreate and before any other scsi initialisation to be 
  2218. * sure that no other program is using this device.
  2219. * RETURNS: OK means that the agreement sync is OK with the target values 
  2220. * except if you get back an offset and/or sync equal to 0 
  2221. * (Async agreement value or reject message).
  2222. * If the driver does not support any synchronous capability, an error status 
  2223. * will be also returned with an `S_scsiLib_SYNC_UNSUPPORTED' error code.
  2224. *
  2225. * NOMANUAL
  2226. */
  2227. static STATUS scsiSyncTarget
  2228.     (
  2229.     SCSI_PHYS_DEV *pScsiPhysDev,    /* ptr to phys dev info */
  2230.     int syncVal,     /* Period value wishes */
  2231.     int offsetVal,     /* Offset value wishes */
  2232.     SCSI_SYNC_AGREEMENT *pSyncVal   /* where to return ctrl and target values */
  2233.     )
  2234.     {
  2235.     UINT8 *pMsgOut; /* pointer to msg out array */
  2236.     STATUS status;
  2237.     SCSI_CTRL *pCtrl;
  2238.     if ((pScsiPhysDev == (SCSI_PHYS_DEV *) NULL) ||
  2239.         (pSyncVal     == NULL ))
  2240. {
  2241.         errnoSet (S_scsiLib_ILLEGAL_PARAMETER);
  2242.         return (ERROR);
  2243. }
  2244.     pMsgOut = SCSI_GET_PTR_MSGOUT(pScsiPhysDev);
  2245.     pCtrl   = (SCSI_CTRL *)pScsiPhysDev->pScsiCtrl;
  2246.     /* Clear return parameter */
  2247.     pSyncVal->syncPeriodCtrl = 0;
  2248.     pSyncVal->syncOffsetCtrl = 0;
  2249.     pSyncVal->syncPeriodTarget = 0;
  2250.     pSyncVal->syncOffsetTarget = 0;
  2251.     /* Set Value for the device in SCSI_PHYS_DEV info,that will be used by 
  2252.      * the scsiTransact routine to set up the values in a message out.
  2253.      */
  2254.     pScsiPhysDev->syncXferPeriod = syncVal * SCSI_SYNC_STEP_PERIOD;
  2255.     pScsiPhysDev->syncXferOffset = offsetVal;
  2256.     /* Call the driver routine to find out the closest controller period/offset
  2257.      * values, just to send back to the caller the round up values possible
  2258.      * for the SCSI controller.  That checks also if the driver is supporting
  2259.      * a such functionality.
  2260.      */
  2261.     pMsgOut[3] = (UINT8) syncVal;
  2262.     pMsgOut[4] = (UINT8) offsetVal;
  2263.     if (pCtrl->scsiSyncMsgConvert == (FUNCPTR) NULL)
  2264.        {
  2265.        errnoSet (S_scsiLib_SYNC_UNSUPPORTED);
  2266.        return (ERROR);
  2267.        }
  2268.     status = (*pCtrl->scsiSyncMsgConvert) (pScsiPhysDev,pMsgOut,
  2269.                         &pSyncVal->syncPeriodCtrl,&pSyncVal->syncOffsetCtrl);
  2270.     if (status == ERROR)
  2271.         return (ERROR);
  2272.     /* Set useMsgout */
  2273.     pScsiPhysDev->useMsgout = SCSI_SYNC_MSGOUT;
  2274.     /* send an scsi command to negotiate for sync transfer */
  2275.     status = scsiTestUnitRdy(pScsiPhysDev);
  2276.     /* Reset useMsgout */
  2277.     pScsiPhysDev->useMsgout = SCSI_NO_MSGOUT;
  2278.     /* If the status is in error the target have been reset to be sure to keep 
  2279.      * the target in assync mode because the sync value can't be matched by the 
  2280.      * scsi controller or the target does not support sync protocol and
  2281.      * answer a reject message.  In case of reset ,the target will 
  2282.      * be send a sense key like "unit attention" on the next command 
  2283.      * , we send a new request to clear it on the target.
  2284.      */
  2285.     if (status == ERROR ) 
  2286.         {
  2287.         status = scsiTestUnitRdy(pScsiPhysDev);
  2288.         status = ERROR;
  2289.         }
  2290.     
  2291.     /* copy target value returned in structure */
  2292.     pSyncVal->syncPeriodTarget  = (pScsiPhysDev->syncXferPeriod)
  2293. /SCSI_SYNC_STEP_PERIOD;
  2294.     pSyncVal->syncOffsetTarget = pScsiPhysDev->syncXferOffset; 
  2295.     SCSI_DEBUG_MSG("scsiSyncTarget:target syncXferPeriod =%dn",
  2296. pScsiPhysDev->syncXferPeriod, 0, 0, 0, 0, 0);
  2297.     SCSI_DEBUG_MSG("scsiSyncTarget:target syncXferOffset =%dn",
  2298. pScsiPhysDev->syncXferOffset, 0, 0, 0, 0, 0);
  2299.     return(status);
  2300.     }