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

VxWorks

开发平台:

C/C++

  1. /* scsiSeqLib.c - SCSI sequential access device library (SCSI-2) */
  2. /* Copyright 1989-1994 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /*
  5. modification history
  6. --------------------
  7. 02k,21feb99,jdi  doc: listed errnos.
  8. 02j,09jul97,dgp  doc: correct fonts per SPR 7853
  9. 02i,06mar97,dds  SPR 8120: fixed scsiRdTape to return the actual number of
  10.                  bytes or blocks read, 0 if end of file, or ERROR.
  11. 02h,29oct96,dgp  doc: editing for newly published SCSI libraries
  12. 02g,16sep96,dds  removed compiler warnings.
  13. 02f,23jul96,dds  SPR 6718: added support for tranfers above 16 MB.
  14. 02e,06may96,jds  more doc tweaks
  15. 02d,01may96,jds  doc tweaks
  16. 02c,20sep95,jds  changed scsiStatusCheck to scsiSeqStatusCheck and made it
  17.  global
  18. 02b,26jul95,jds  maxVarBlockLimit to be set by scsiPhysDevCreate (Wrt & Rd) 
  19. 02a,10may95,jds  reworked for use with enhanced SCSI-2 library; added tagType,
  20.  and priority ; removed the idea of retrying command upon
  21.  UNIT_ATTENTION which should be managed by higher level layer.
  22. 01e,28jun94,ccc  doc tweaks.
  23. 01d,21jun94,ccc  changed dataAddress from NONE to NULL.
  24. 01c,27apr94,jdi  doc tweaks.
  25. 01b,20apr94,jds  enhanced scsiWrtTape and scsiRdTape to correctly handle fixed
  26.  block transfers and variable block transfers with maxBlockLimit
  27. 01a,24jan94,ccc  created to support sequential access SCSI devices.
  28. */
  29. /*
  30. DESCRIPTION
  31. This library contains commands common to all sequential-access SCSI devices.
  32. Sequential-access SCSI devices are usually SCSI tape devices.
  33. These routines are separated from scsi2Lib in order to create an additional
  34. layer for better support of all SCSI sequential devices.
  35. SCSI commands in this library include:
  36. .TS
  37. tab(|);
  38. lf3 lf3
  39. l l.
  40. Command | Op Code
  41. _
  42. ERASE | (0x19)
  43. MODE SELECT (6) | (0x15)
  44. MODE_SENSE (6) | (0x1a)
  45. READ (6) | (0x08)
  46. READ BLOCK LIMITS | (0x05)
  47. RELEASE UNIT | (0x17)
  48. RESERVE UNIT | (0x16)
  49. REWIND | (0x01)
  50. SPACE | (0x11)
  51. WRITE (6) | (0x0a)
  52. WRITE FILEMARKS | (0x10)
  53. LOAD/UNLOAD | (0x1b)
  54. .TE
  55. The SCSI routines implemented here operate mostly on a SCSI_SEQ_DEV
  56. structure.  This structure acts as an interface between this library
  57. and a higher-level layer.  The SEQ_DEV structure is analogous to the
  58. BLK_DEV structure for block devices.  
  59. The scsiSeqDevCreate() routine creates a SCSI_SEQ_DEV structure whose first 
  60. element is a SEQ_DEV, operated upon by higher layers.  This routine publishes
  61. all functions to be invoked by
  62. higher layers and maintains some state information (for example, block size)
  63. for tracking SCSI-sequential-device information.
  64. INCLUDE FILES
  65. scsiLib.h, scsi2Lib.h
  66. SEE ALSO: tapeFsLib, scsi2Lib,
  67. .pG "I/O System, Local File Systems"
  68. */
  69. #define  INCLUDE_SCSI2
  70. #include "vxWorks.h"
  71. #include "ioLib.h"
  72. #include "ctype.h"
  73. #include "stdlib.h"
  74. #include "errnoLib.h"
  75. #include "taskLib.h"
  76. #include "logLib.h"
  77. #include "string.h"
  78. #include "stdio.h"
  79. #include "scsiLib.h"
  80. #include "sysLib.h"
  81. #define MODE_BUF_LENGTH    0xff
  82. #define SCSI_MAX_XFER_BLOCKS  0xffffff
  83. #define SCSI_READ             0x00
  84. #define SCSI_WRITE            0x01
  85. /* globals */
  86. IMPORT BOOL scsiDebug; /* enable task level debug messages */
  87. IMPORT BOOL scsiIntsDebug; /* enable int level debug messages */
  88. /* select timeout to use when creating a SCSI_PHYS_DEV */
  89. IMPORT UINT32 scsiSelectTimeout;
  90. IMPORT SCSI_CTRL *pSysScsiCtrl; /* ptr to default SCSI_CTRL struct */
  91. LOCAL VOID scsiXactionFill (SCSI_TRANSACTION *, SCSI_COMMAND, BOOL, int, UINT,
  92.     int, UINT8 *);
  93. LOCAL VOID scsiCmdFill (SCSI_SEQ_DEV *, SCSI_COMMAND , BOOL, BOOL, int);
  94. LOCAL int scsiRdTapeFixedBlocks (SCSI_SEQ_DEV *, UINT, char * );
  95. LOCAL int scsiRdTapeVariableBlocks (SCSI_SEQ_DEV *, UINT, char * );
  96. LOCAL int scsiCalcDataRead (SCSI_SEQ_DEV *, UINT);
  97. /*******************************************************************************
  98. *
  99. * scsiSeqDevCreate - create a SCSI sequential device
  100. *
  101. * This routine creates a SCSI sequential device and saves a pointer to this
  102. * SEQ_DEV in the SCSI physical device. The following functions are
  103. * initialized in this structure:
  104. *
  105. * .TS
  106. * tab(|);
  107. * l l.
  108. * sd_seqRd           | -  scsiRdTape()
  109. * sd_seqWrt          | -  scsiWrtTape()
  110. * sd_ioctl           | -  scsiIoctl() (in scsiLib)
  111. * sd_seqWrtFileMarks | -  scsiWrtFileMarks()
  112. * sd_statusChk       | -  scsiSeqStatusCheck()
  113. * sd_reset           | -  (not used)
  114. * sd_rewind          | -  scsiRewind()
  115. * sd_reserve         | -  scsiReserve()
  116. * sd_release         | -  scsiRelease()
  117. * sd_readBlkLim      | -  scsiSeqReadBlockLimits()
  118. * sd_load            | -  scsiLoadUnit()
  119. * sd_space           | -  scsiSpace()
  120. * sd_erase           | -  scsiErase()
  121. * .TE
  122. *
  123. * Only one SEQ_DEV per SCSI_PHYS_DEV is allowed, unlike BLK_DEVs where an 
  124. * entire list is maintained. Therefore, this routine can be called only 
  125. * once per creation of a sequential device.
  126. *
  127. * RETURNS: A pointer to the SEQ_DEV structure, or NULL if the command fails. 
  128. */
  129. SEQ_DEV *scsiSeqDevCreate
  130.     (
  131.     SCSI_PHYS_DEV *pScsiPhysDev  /* ptr to SCSI physical device info */
  132.     )
  133.     {
  134.     SCSI_SEQ_DEV      *pScsiSeqDev;     /* ptr to SCSI sequential dev struct */
  135.     /* check parameter for validity */
  136.     if (pScsiPhysDev == NULL)
  137. {
  138. errnoSet (S_scsiLib_ILLEGAL_PARAMETER);
  139. SCSI_DEBUG_MSG ("scsiSeqDevCreate: Invalid input parameter(s).n",
  140. 0, 0, 0, 0, 0, 0);
  141. return ((SEQ_DEV *) NULL);
  142. }
  143.     /* Check if sequential device alread exists */
  144.     if (pScsiPhysDev->pScsiSeqDev != NULL)
  145. {
  146.         errnoSet (S_scsiLib_ILLEGAL_OPERATION);
  147.         SCSI_DEBUG_MSG ("scsiSeqDevCreate: SEQ_DEV already exists.n", 
  148. 0, 0, 0, 0, 0, 0);
  149.         return ((SEQ_DEV *) NULL);
  150.         }
  151.     /* return NULL if not a sequential access device */
  152.     if (pScsiPhysDev->scsiDevType != SCSI_DEV_SEQ_ACCESS)
  153.         {
  154.         errnoSet (S_scsiLib_ILLEGAL_OPERATION);
  155.         SCSI_DEBUG_MSG ("scsiSeqDevCreate:", 0, 0, 0, 0, 0, 0);
  156.         SCSI_DEBUG_MSG ("Physical device is not a sequential device.n",
  157.                         0, 0, 0, 0, 0, 0);
  158.         return ((SEQ_DEV *) NULL);
  159.         }
  160.     if (!pScsiPhysDev->removable)
  161.         SCSI_DEBUG_MSG ("scsiSeqDevCreate: Odd! Non removable tape!!n",
  162. 0, 0, 0, 0, 0, 0);
  163.     pScsiSeqDev = (SCSI_SEQ_DEV *) calloc (1, sizeof (SCSI_SEQ_DEV));
  164.     if (pScsiSeqDev == NULL)
  165. return ((SEQ_DEV *) NULL);
  166.     pScsiSeqDev->seqDev.sd_seqRd           = (FUNCPTR) scsiRdTape;
  167.     pScsiSeqDev->seqDev.sd_seqWrt          = (FUNCPTR) scsiWrtTape;
  168.     pScsiSeqDev->seqDev.sd_ioctl           = (FUNCPTR) scsiIoctl;
  169.     pScsiSeqDev->seqDev.sd_seqWrtFileMarks = (FUNCPTR) scsiWrtFileMarks;
  170.     pScsiSeqDev->seqDev.sd_rewind     = (FUNCPTR) scsiRewind;
  171.     pScsiSeqDev->seqDev.sd_reserve     = (FUNCPTR) scsiReserveUnit;
  172.     pScsiSeqDev->seqDev.sd_release     = (FUNCPTR) scsiReleaseUnit;
  173.     pScsiSeqDev->seqDev.sd_readBlkLim    = (FUNCPTR) scsiSeqReadBlockLimits;
  174.     pScsiSeqDev->seqDev.sd_load     = (FUNCPTR) scsiLoadUnit;
  175.     pScsiSeqDev->seqDev.sd_space     = (FUNCPTR) scsiSpace;
  176.     pScsiSeqDev->seqDev.sd_erase     = (FUNCPTR) scsiErase;
  177.     pScsiSeqDev->seqDev.sd_statusChk       = (FUNCPTR) scsiSeqStatusCheck;
  178.     pScsiSeqDev->seqDev.sd_reset           = (FUNCPTR) NULL;
  179.     pScsiSeqDev->seqDev.sd_readyChanged    = TRUE;
  180.     pScsiSeqDev->pScsiPhysDev = pScsiPhysDev;
  181.     pScsiPhysDev->pScsiSeqDev = pScsiSeqDev;
  182.     /* Note: sd_blkSize and sd_mode are left uninitialized */
  183.     /* this should be the same as returning (SEQ_DEV *) pScsiSeqDev ?? */
  184.     return (&pScsiSeqDev->seqDev);
  185.     }
  186.     
  187. /*******************************************************************************
  188. *
  189. * scsiErase - issue an ERASE command to a SCSI device
  190. *
  191. * This routine issues an ERASE command to a specified SCSI device.
  192. *
  193. * RETURNS: OK, or ERROR if the command fails.
  194. */
  195. STATUS scsiErase
  196.     (
  197.     SCSI_PHYS_DEV *pScsiPhysDev, /* ptr to SCSI physical device */
  198.     BOOL longErase /* TRUE for entire tape erase  */
  199.     )
  200.     {
  201.     SCSI_COMMAND eraseCommand; /* SCSI command byte array */
  202.     SCSI_TRANSACTION scsiXaction; /* info on a SCSI transaction */
  203.     STATUS status; /* status of transaction */
  204.     SCSI_DEBUG_MSG ("scsiErase:n", 0, 0, 0, 0, 0, 0);
  205.     /*
  206.      * Build the SCSI command. Do not use scsiCmdBuild, because that function
  207.      * is used only for direct access commands.
  208.      */
  209.     eraseCommand[0] = SCSI_OPCODE_ERASE;
  210.     eraseCommand[1] = (UINT8) ((pScsiPhysDev->scsiDevLUN & 0x7) << 5);
  211.     if (longErase)
  212. eraseCommand [1] |= 0x01; /* set long bit */
  213.     eraseCommand[2] = (UINT8) 0;
  214.     eraseCommand[3] = (UINT8) 0;
  215.     eraseCommand[4] = (UINT8) 0;
  216.     eraseCommand[5] = (UINT8) 0;
  217.     scsiXaction.cmdAddress    = eraseCommand;
  218.     scsiXaction.cmdLength     = SCSI_GROUP_0_CMD_LENGTH;
  219.     scsiXaction.dataAddress   = (UINT8 *) NULL;
  220.     scsiXaction.dataDirection = O_WRONLY;
  221.     scsiXaction.dataLength    = 0;
  222.     scsiXaction.addLengthByte = NULL;
  223.     scsiXaction.cmdTimeout    = SCSI_TIMEOUT_FULL;
  224.     scsiXaction.tagType       = SCSI_TAG_DEFAULT;
  225.     scsiXaction.priority      = SCSI_THREAD_TASK_PRIORITY;
  226.     status = (*pScsiPhysDev->pScsiCtrl->scsiTransact)
  227.       (pScsiPhysDev, &scsiXaction);
  228.     return (status);
  229.     }
  230. /*******************************************************************************
  231. *
  232. * scsiTapeModeSelect - issue a MODE_SELECT command to a SCSI tape device
  233. *
  234. * This routine issues a MODE_SELECT command to a specified SCSI device.
  235. *
  236. * RETURNS: OK, or ERROR if the command fails.
  237. */
  238. STATUS scsiTapeModeSelect
  239.     (
  240.     SCSI_PHYS_DEV *pScsiPhysDev,/* ptr to SCSI physical device            */
  241.     int pageFormat,             /* value of the page format bit (0-1)     */
  242.     int saveParams,             /* value of the save parameters bit (0-1) */
  243.     char *buffer,               /* ptr to output data buffer              */
  244.     int bufLength               /* length of buffer in bytes              */
  245.     )
  246.     {
  247.     SCSI_COMMAND scsiCommand; /* SCSI command byte array */
  248.     SCSI_TRANSACTION scsiXaction; /* info on a SCSI transaction */
  249.     STATUS status; /* status of transaction */
  250.     SCSI_DEBUG_MSG ("scsiTapeModeSelect:n", 0, 0, 0, 0, 0, 0);
  251.     scsiCommand[0] = SCSI_OPCODE_MODE_SELECT;
  252.     scsiCommand[1] = (UINT8) ((pScsiPhysDev->scsiDevLUN & 0x7) << 5);
  253.     scsiCommand[1] |= ((UINT8) ((pageFormat & 1) << 4) |
  254.        (UINT8) (saveParams & 1));
  255.     scsiCommand[2] = (UINT8) 0;
  256.     scsiCommand[3] = (UINT8) 0;
  257.     scsiCommand[4] = (UINT8) (bufLength & 0xff);
  258.     scsiCommand[5] = (UINT8) 0;
  259.     scsiXaction.cmdAddress    = scsiCommand;
  260.     scsiXaction.cmdLength     = SCSI_GROUP_0_CMD_LENGTH;
  261.     scsiXaction.dataAddress   = (UINT8 *) buffer;
  262.     scsiXaction.dataDirection = O_WRONLY;
  263.     scsiXaction.dataLength    = min (0xff, bufLength);
  264.     scsiXaction.addLengthByte = NULL;
  265.     scsiXaction.cmdTimeout    = SCSI_TIMEOUT_5SEC;
  266.     scsiXaction.tagType       = SCSI_TAG_DEFAULT;
  267.     scsiXaction.priority      = SCSI_THREAD_TASK_PRIORITY;
  268.     status = (*pScsiPhysDev->pScsiCtrl->scsiTransact)
  269.       (pScsiPhysDev, &scsiXaction);
  270.     return (status);
  271.     }
  272. /*******************************************************************************
  273. *
  274. * scsiTapeModeSense - issue a MODE_SENSE command to a SCSI tape device
  275. *
  276. * This routine issues a MODE_SENSE command to a specified SCSI tape device.
  277. *
  278. * RETURNS: OK, or ERROR if the command fails.
  279. */
  280. STATUS scsiTapeModeSense
  281.     (
  282.     SCSI_PHYS_DEV *pScsiPhysDev,/* ptr to SCSI physical device           */
  283.     int pageControl,            /* value of the page control field (0-3) */
  284.     int pageCode,               /* value of the page code field (0-0x3f) */
  285.     char *buffer,               /* ptr to input data buffer              */
  286.     int bufLength               /* length of buffer in bytes             */
  287.     )
  288.     {
  289.     SCSI_COMMAND scsiCommand; /* SCSI command byte array */
  290.     SCSI_TRANSACTION scsiXaction; /* info on a SCSI transaction */
  291.     STATUS status; /* status of transaction */
  292.     SCSI_DEBUG_MSG ("scsiModeSense: cmdAddress 0x%xn", (int) scsiCommand,
  293. 0, 0, 0, 0, 0);
  294.     scsiCommand[0] = SCSI_OPCODE_MODE_SENSE;
  295.     scsiCommand[1] = (UINT8) ((pScsiPhysDev->scsiDevLUN & 0x7) << 5);
  296.     scsiCommand[2] = (UINT8) ((pageControl << 6) | pageCode);
  297.     scsiCommand[3] = (UINT8) 0;
  298.     scsiCommand[4] = (UINT8) (bufLength & 0xff);
  299.     scsiCommand[5] = (UINT8) 0;
  300.     scsiXaction.cmdAddress    = scsiCommand;
  301.     scsiXaction.cmdLength     = SCSI_GROUP_0_CMD_LENGTH;
  302.     scsiXaction.dataAddress   = (UINT8 *) buffer;
  303.     scsiXaction.dataDirection = O_RDONLY;
  304.     scsiXaction.dataLength    = min (0xff, bufLength);
  305.     scsiXaction.addLengthByte = MODE_SENSE_ADD_LENGTH_BYTE;
  306.     scsiXaction.cmdTimeout    = SCSI_TIMEOUT_5SEC;
  307.     scsiXaction.tagType       = SCSI_TAG_DEFAULT;
  308.     scsiXaction.priority      = SCSI_THREAD_TASK_PRIORITY;
  309.     status = (*pScsiPhysDev->pScsiCtrl->scsiTransact)
  310.       (pScsiPhysDev, &scsiXaction);
  311.     return (status);
  312.     }
  313. /*******************************************************************************
  314. *
  315. * scsiReadBlockLimits - issue a READ_BLOCK_LIMITS command to a SCSI device
  316. *
  317. * This routine issues a READ_BLOCK_LIMITS command to a specified SCSI device.
  318. *
  319. * RETURNS: OK, or ERROR if the command fails.
  320. *
  321. * NOMANUAL
  322. */
  323. STATUS scsiReadBlockLimits
  324.     (
  325.     SCSI_PHYS_DEV * pScsiPhysDev,/* ptr to SCSI physical device          */
  326.     int    *pMaxBlockLength,     /* where to return maximum block length */
  327.     UINT16 *pMinBlockLength      /* where to return minimum block length */
  328.     )
  329.     {
  330.     SCSI_COMMAND readBlockLimitCommand; /* SCSI command byte array */
  331.     RD_BLOCK_LIMIT_DATA readBlkLimitData; /* data structure for results */
  332.     SCSI_TRANSACTION scsiXaction;   /* info on a SCSI transaction */
  333.     STATUS status;   /* status of the transaction */
  334.     SCSI_DEBUG_MSG ("scsiReadBlockLimit:n", 0, 0, 0, 0, 0, 0);
  335.     readBlockLimitCommand[0] = SCSI_OPCODE_READ_BLOCK_LIMITS;
  336.     readBlockLimitCommand[1] = (UINT8) ((pScsiPhysDev->scsiDevLUN & 0x7) << 5);
  337.     readBlockLimitCommand[2] = (UINT8) 0;
  338.     readBlockLimitCommand[3] = (UINT8) 0;
  339.     readBlockLimitCommand[4] = (UINT8) 0;
  340.     readBlockLimitCommand[5] = (UINT8) 0;
  341.     scsiXaction.cmdAddress    = readBlockLimitCommand;
  342.     scsiXaction.cmdLength     = SCSI_GROUP_0_CMD_LENGTH;
  343.     scsiXaction.dataAddress   = (UINT8 *) &readBlkLimitData;
  344.     scsiXaction.dataDirection = O_RDONLY;
  345.     scsiXaction.dataLength    = sizeof (readBlkLimitData);
  346.     scsiXaction.addLengthByte = NULL;
  347.     scsiXaction.cmdTimeout    = SCSI_TIMEOUT_5SEC;
  348.     scsiXaction.tagType       = SCSI_TAG_DEFAULT;
  349.     scsiXaction.priority      = SCSI_THREAD_TASK_PRIORITY;
  350.     status = (*pScsiPhysDev->pScsiCtrl->scsiTransact)
  351.       (pScsiPhysDev, &scsiXaction);
  352.     if (status == ERROR)
  353. return (ERROR);
  354.     *pMaxBlockLength = readBlkLimitData.maxBlockLength;
  355.     *pMinBlockLength = readBlkLimitData.minBlockLength;
  356.     SCSI_SWAB (pMaxBlockLength, sizeof (*pMaxBlockLength));
  357.     SCSI_SWAB (pMinBlockLength, sizeof (*pMinBlockLength));
  358.     return (OK);
  359.     }
  360. /*******************************************************************************
  361. *
  362. * scsiSeqReadBlockLimits - issue a READ_BLOCK_LIMITS command to a SCSI device
  363. *
  364. * This routine issues a READ_BLOCK_LIMITS command to a specified SCSI device.
  365. *
  366. * RETURNS: OK, or ERROR if the command fails.
  367. */
  368. STATUS scsiSeqReadBlockLimits
  369.     (
  370.     SCSI_SEQ_DEV * pScsiSeqDev,  /* ptr to SCSI sequential device        */
  371.     int    *pMaxBlockLength,     /* where to return maximum block length */
  372.     UINT16 *pMinBlockLength      /* where to return minimum block length */
  373.     )
  374.     {
  375.     SCSI_PHYS_DEV * pScsiPhysDev = pScsiSeqDev->pScsiPhysDev;
  376.     return (scsiReadBlockLimits (pScsiPhysDev, pMaxBlockLength, 
  377. pMinBlockLength));
  378.     }
  379. /*******************************************************************************
  380. *
  381. * scsiCmdFill - fill the SCSI_COMMAND structure.
  382. *
  383. * RETURNS: N/A.
  384. */
  385. LOCAL VOID scsiCmdFill 
  386.     ( 
  387.     SCSI_SEQ_DEV * pScsiSeqDev,
  388.     SCSI_COMMAND   scsiCommand,  /* scsi command structure to be filled */
  389.     BOOL           commandType,  /* read or write command               */
  390.     BOOL           fixed,        /* variable or fixed                   */
  391.     int            xferLength    /* total bytes or blocks to xfer       */
  392.     )
  393.     {
  394.     SCSI_PHYS_DEV *pScsiPhysDev; /* ptr to SCSI physical device info */
  395.     pScsiPhysDev = pScsiSeqDev->pScsiPhysDev;
  396.     if ( commandType == SCSI_READ )
  397. scsiCommand[0] = SCSI_OPCODE_READ;
  398.     else
  399. scsiCommand[0] = SCSI_OPCODE_WRITE;
  400.     scsiCommand[1] = (UINT8) ((pScsiPhysDev->scsiDevLUN & 0x7) << 5);
  401.     if (fixed)
  402. scsiCommand[1] |= 0x01; /* set for fixed block size */
  403.     scsiCommand[2] = (UINT8) ((xferLength >> 16) & 0xff);
  404.     scsiCommand[3] = (UINT8) ((xferLength >>  8) & 0xff);
  405.     scsiCommand[4] = (UINT8) (xferLength & 0xff);
  406.     scsiCommand[5] = (UINT8) 0;
  407.     }
  408. /*******************************************************************************
  409. *
  410. * scsiXactionFill - fill the SCSI_TRANSACTION structure.
  411. *
  412. * RETURNS: N/A.
  413. */
  414. LOCAL VOID scsiXactionFill 
  415.     ( 
  416.     SCSI_TRANSACTION * scsiXaction, /* scsi Transaction structure */
  417.     SCSI_COMMAND   scsiCommand,     /* scsi command structure     */
  418.     BOOL           commandType,     /* read or write command      */
  419.     int            cmdLength,       /* scsi command length        */
  420.     UINT           cmdTimeout,      /* scsi command timeout       */
  421.     int            dataXferLen,     /* data transfer length       */
  422.     UINT8 *        bufAdrs          /* scsi data address          */
  423.     )
  424.     {
  425.     if ( commandType == SCSI_READ )
  426. scsiXaction->dataDirection = O_RDONLY;
  427.     else
  428. scsiXaction->dataDirection = O_WRONLY;
  429.     scsiXaction->cmdAddress  = scsiCommand;
  430.     scsiXaction->cmdLength   = cmdLength;
  431.     scsiXaction->dataAddress = bufAdrs;
  432.     scsiXaction->dataLength  = dataXferLen;
  433.     scsiXaction->addLengthByte = NULL;
  434.     scsiXaction->cmdTimeout = cmdTimeout;
  435.     scsiXaction->tagType = SCSI_TAG_DEFAULT;
  436.     scsiXaction->priority = SCSI_THREAD_TASK_PRIORITY;
  437.     }
  438. /*******************************************************************************
  439. *
  440. * scsiRdTapeFixedBlocks - reads the number of blocks specified
  441. *
  442. * This routine reads the specified number of blocks from a specified
  443. * physical device.  If `numBlocks' is greater than the `maxBytesLimit' field
  444. * defined in the `pScsiPhysDev' structure, then more than one SCSI transaction
  445. * is used to transfer the data.
  446. *
  447. * RETURNS: Number of blocks actually read, 0 if EOF, or ERROR.
  448. */
  449. LOCAL int scsiRdTapeFixedBlocks
  450.     (
  451.     SCSI_SEQ_DEV *pScsiSeqDev,    /* ptr to SCSI sequential device info */
  452.     UINT numBlocks,                /* total # of blocks to be read       */
  453.     char * buffer                 /* ptr to iput data buffer            */    
  454.     )
  455.     {
  456.     SCSI_PHYS_DEV *pScsiPhysDev;  /* ptr to SCSI physical device info   */
  457.     SCSI_COMMAND readCommand;   /* SCSI command byte array            */
  458.     SCSI_TRANSACTION scsiXaction; /* info on a SCSI transaction         */
  459.     UINT8 * bufPtr;               /* ptr to input data buffer           */
  460.     UINT timeout;                 /* scsi command timeout               */
  461.     int  xferLength;              /* transfer length                    */
  462.     int  nBlocks = 0;             /* number of blocks read              */
  463.     int  xferBlocks;              /* number of blocks to be xferred     */
  464.     UINT blocksRead = 0;          /* actual number of blocks read       */
  465.     pScsiPhysDev = pScsiSeqDev->pScsiPhysDev;
  466.     
  467.     if (numBlocks > SCSI_MAX_XFER_BLOCKS)
  468. return (ERROR);
  469.     
  470.     /*
  471.      * Check if the number of blocks to be transferred is less than 
  472.      * the max permissible size 
  473.      */
  474.     
  475.     if (numBlocks <= (pScsiPhysDev->pScsiCtrl->maxBytesPerXfer / 
  476.       pScsiSeqDev->seqDev.sd_blkSize))
  477. {
  478. scsiCmdFill (pScsiSeqDev, readCommand, SCSI_READ, TRUE,
  479.      numBlocks);
  480. bufPtr = (UINT8 *) buffer;
  481. xferLength = numBlocks * pScsiSeqDev->seqDev.sd_blkSize;
  482. /* 
  483.  * timeout value is based on 100kB/sec xfer and a 5 
  484.  * sec threshold 
  485.  */
  486. timeout = SCSI_TIMEOUT_5SEC * 50 + (10 * numBlocks *
  487.     pScsiPhysDev->blockSize);
  488. scsiXactionFill (&scsiXaction, readCommand, SCSI_READ,
  489.  SCSI_GROUP_0_CMD_LENGTH, timeout, xferLength,
  490.  bufPtr);
  491.         if (((*pScsiPhysDev->pScsiCtrl->scsiTransact) 
  492.      (pScsiPhysDev, &scsiXaction)) == ERROR)
  493.     return (ERROR);
  494. if ((blocksRead = scsiCalcDataRead (pScsiSeqDev, numBlocks)) == ERROR)
  495.     return (ERROR);
  496. return (blocksRead);
  497. }
  498.     else
  499. {
  500. /* determine the max number of blocks that can be transferred */
  501. xferBlocks = (pScsiPhysDev->pScsiCtrl->maxBytesPerXfer) /
  502.      (pScsiSeqDev->seqDev.sd_blkSize);
  503. while (numBlocks > 0)
  504.     {
  505.     scsiCmdFill (pScsiSeqDev, readCommand, SCSI_READ, TRUE, 
  506.  xferBlocks);
  507.     bufPtr = (UINT8 *) buffer;
  508.     xferLength = xferBlocks * pScsiSeqDev->seqDev.sd_blkSize;
  509.     
  510.     /* 
  511.      * timeout value is based on 100kB/sec xfer and a 5 
  512.      * sec threshold 
  513.      */
  514.     
  515.     timeout = SCSI_TIMEOUT_5SEC * 50 + (10 * xferBlocks * 
  516. pScsiPhysDev->blockSize);
  517.     
  518.     scsiXactionFill (&scsiXaction, readCommand, SCSI_READ,
  519.      SCSI_GROUP_0_CMD_LENGTH, timeout, xferLength,
  520.      bufPtr);
  521.     if (((*pScsiPhysDev->pScsiCtrl->scsiTransact) 
  522.  (pScsiPhysDev, &scsiXaction)) == ERROR)
  523.            return (ERROR);
  524.     
  525.     if ((nBlocks = scsiCalcDataRead (pScsiSeqDev, numBlocks)) == ERROR)
  526.         return (ERROR);
  527.     
  528.     numBlocks -= xferBlocks;
  529.     buffer += (xferBlocks * pScsiSeqDev->seqDev.sd_blkSize);
  530.     
  531.     if (numBlocks <= 
  532. (pScsiPhysDev->pScsiCtrl->maxBytesPerXfer /
  533.  pScsiSeqDev->seqDev.sd_blkSize))
  534. xferBlocks = numBlocks;
  535.     
  536.     blocksRead += nBlocks;
  537.     }
  538. return (blocksRead);
  539. }
  540.     }
  541. /*******************************************************************************
  542. *
  543. * scsiRdTapeVariableBlocks - reads the number of bytes specified
  544. *
  545. * This routine reads the specified number of bytes from a specified
  546. * physical device.  If `numBytes' is greater than the `maxBytesLimit' field
  547. * defined in the `pScsiPhysDev' structure, then more than one SCSI transaction
  548. * is used to transfer the data.
  549. *
  550. * RETURNS: Number of bytes actually read, 0 if EOF, or ERROR.
  551. */
  552. LOCAL int scsiRdTapeVariableBlocks
  553.     (
  554.     SCSI_SEQ_DEV *pScsiSeqDev,    /* ptr to SCSI sequential device info */
  555.     UINT numBytes,                 /* total # of bytes to be read        */
  556.     char * buffer                 /* ptr to input data buffer           */    
  557.     )
  558.     {
  559.     SCSI_PHYS_DEV *pScsiPhysDev;  /* ptr to SCSI physical device info   */
  560.     SCSI_COMMAND readCommand;   /* SCSI command byte array            */
  561.     SCSI_TRANSACTION scsiXaction; /* info on a SCSI transaction         */
  562.     UINT8 * bufPtr;               /* ptr to input data buffer           */
  563.     UINT timeout;                 /* scsi command timeout               */
  564.     int  xferLength;              /* transfer length                    */
  565.     int  nBytes;                  /* number of bytes read               */
  566.     int  maxVarBlockLimit;        /* maximum variable block limit       */
  567.     UINT bytesRead = 0;           /* actual number of bytes read        */
  568.     int  readBytes;               /* for multiple read transactions     */
  569.     
  570.     
  571.     pScsiPhysDev = pScsiSeqDev->pScsiPhysDev;
  572.     
  573.     /* get the maximum variable block size for the device */    
  574.     
  575.     maxVarBlockLimit = pScsiPhysDev->maxVarBlockLimit;
  576.     
  577.     if (maxVarBlockLimit > pScsiPhysDev->pScsiCtrl->maxBytesPerXfer)
  578. maxVarBlockLimit = pScsiPhysDev->pScsiCtrl->maxBytesPerXfer;
  579.     
  580.     /* multiple transactions needed if numBytes > maxVarBlockLimit */
  581.     
  582.     for (readBytes=0; numBytes > maxVarBlockLimit; 
  583.  numBytes -= maxVarBlockLimit, readBytes += maxVarBlockLimit)
  584.         {
  585. scsiCmdFill (pScsiSeqDev, readCommand, SCSI_READ, FALSE, 
  586.      maxVarBlockLimit);
  587. bufPtr = (UINT8 *) buffer + readBytes;
  588. xferLength = maxVarBlockLimit;
  589. timeout = SCSI_TIMEOUT_5SEC * 50 + (maxVarBlockLimit * 10);
  590. scsiXactionFill (&scsiXaction, readCommand, SCSI_READ,
  591.  SCSI_GROUP_0_CMD_LENGTH, timeout, xferLength,
  592.  bufPtr);
  593.         if (((*pScsiPhysDev->pScsiCtrl->scsiTransact) 
  594.      (pScsiPhysDev, &scsiXaction)) == ERROR)
  595.     return (ERROR);
  596. if ((nBytes = scsiCalcDataRead (pScsiSeqDev, xferLength)) == ERROR)
  597.     return (ERROR);
  598. bytesRead += nBytes;
  599.         }
  600.     
  601.     if (numBytes > 0)
  602. {
  603. scsiCmdFill (pScsiSeqDev, readCommand, SCSI_READ, FALSE, numBytes);
  604. bufPtr = (UINT8 *) buffer + readBytes;
  605. timeout = SCSI_TIMEOUT_5SEC * 50 + (numBytes * 10);
  606. scsiXactionFill (&scsiXaction, readCommand, SCSI_READ,
  607.  SCSI_GROUP_0_CMD_LENGTH, timeout, numBytes,
  608.  bufPtr);
  609.         if (((*pScsiPhysDev->pScsiCtrl->scsiTransact)
  610.      (pScsiPhysDev, &scsiXaction)) == ERROR)
  611.             return (ERROR);
  612. if ((nBytes = scsiCalcDataRead (pScsiSeqDev, numBytes)) == ERROR)
  613.       return (ERROR);
  614. bytesRead  += nBytes;
  615. }
  616.     return (bytesRead);
  617.     }
  618. /*******************************************************************************
  619. *
  620. * scsiRdTape - read bytes or blocks from a SCSI tape device
  621. *
  622. * This routine reads the specified number of bytes or blocks from a specified
  623. * physical device.  If the boolean <fixedSize> is true, then <numBytes>
  624. * represents the number of blocks of size <blockSize>, defined in the 
  625. * `pScsiPhysDev' structure.  If variable block sizes are used
  626. * (<fixedSize> = FALSE), then <numBytes> represents the actual number of bytes
  627. * to be read. 
  628. *
  629. * RETURNS: Number of bytes or blocks actually read, 0 if EOF, or ERROR.
  630. */
  631. int scsiRdTape
  632.     (
  633.     SCSI_SEQ_DEV *pScsiSeqDev,    /* ptr to SCSI sequential device info */
  634.     UINT count,                   /* total bytes or blocks to be read   */
  635.     char *buffer,                 /* ptr to input data buffer           */
  636.     BOOL fixedSize   /* if variable size blocks            */
  637.     )
  638.     {
  639.     SCSI_PHYS_DEV *pScsiPhysDev;  /* ptr to SCSI physical device info   */
  640.     int            dataCount;     /* blocks or bytes read               */
  641.     
  642.     pScsiPhysDev = pScsiSeqDev->pScsiPhysDev;
  643.     
  644.     SCSI_DEBUG_MSG ("scsiRdTape:n", 0, 0, 0, 0, 0, 0);
  645.     
  646.     /* Invalidate the request sense data */
  647.     
  648.     pScsiPhysDev->pReqSenseData[0] &= 0x7f;
  649.     
  650.     if (fixedSize)
  651. dataCount = scsiRdTapeFixedBlocks (pScsiSeqDev, count, buffer);
  652.     else
  653. dataCount = scsiRdTapeVariableBlocks (pScsiSeqDev, count, buffer);
  654.     
  655.     return (dataCount);
  656.     }
  657. /*******************************************************************************
  658. *
  659. * scsiCalcDataRead - calculates the actual # of bytes read
  660. *
  661. * This routine calculates the actual number of bytes or blocks read after
  662. * a read operation, by examining the request sense data if it is valid.
  663. *
  664. * RETURNS: bytes or blocks read, 0 if EOF or ERROR if tape move was 
  665. * unsuccessful.
  666. *          
  667. * NOMANUAL
  668. */
  669. LOCAL int scsiCalcDataRead 
  670.     (
  671.     SCSI_SEQ_DEV *pScsiSeqDev,    /* ptr to SCSI sequential device info */
  672.     UINT numDataUnits              /* total bytes or blocks to be read   */
  673.     )
  674.     {
  675.     SCSI_PHYS_DEV *pScsiPhysDev;  /* ptr to SCSI physical device info */
  676.     int  residue;                 /* diff between requested & xfered data */
  677.     UINT unitsRead = 0;           /* actual number of bytes read          */
  678.     
  679.     pScsiPhysDev = pScsiSeqDev->pScsiPhysDev;
  680.     
  681.     /* if request sense data is valid */
  682.     
  683.     if (pScsiPhysDev->pReqSenseData[0] & 0x80)
  684. {
  685. residue = (pScsiPhysDev->pReqSenseData[3] << 24) +
  686.   (pScsiPhysDev->pReqSenseData[4] << 16) +
  687.   (pScsiPhysDev->pReqSenseData[5] <<  8) +
  688.   (pScsiPhysDev->pReqSenseData[6]);
  689. if (residue < 0)
  690.     unitsRead = numDataUnits;
  691. else
  692.     unitsRead = numDataUnits - residue;
  693. /* Invalidate the request sense data */
  694. pScsiPhysDev->pReqSenseData[0] = pScsiPhysDev->pReqSenseData[0] & 0x7f;
  695.         /*
  696.  * Check the request sense data to see if End of Filemark
  697.  * or End of Medium was encountered.
  698.  */
  699. if ((pScsiPhysDev->pReqSenseData[2] & 0x40) ||
  700.     (pScsiPhysDev->pReqSenseData[2] & 0x80))
  701.     {
  702.             /* move tape head to the beginning of filemark */
  703.     
  704.     if ((scsiSpace (pScsiSeqDev, -1, SPACE_CODE_FILEMARK)) == ERROR)
  705.         {
  706. printf ("Backward space unsuccessfuln");
  707.         return (ERROR);
  708. }
  709.        }
  710. return (unitsRead);
  711. }
  712.     return (numDataUnits);
  713.     }
  714. /*******************************************************************************
  715. *
  716. * scsiWrtTape - write data to a SCSI tape device
  717. *
  718. * This routine writes data to the current block on a specified physical
  719. * device.  If the boolean <fixedSize> is true, then <numBytes>
  720. * represents the number of blocks of size <blockSize>,  
  721. * defined in the `pScsiPhysDev' structure.  If variable block sizes are used
  722. * (<fixedSize> = FALSE), then <numBytes> represents the actual number of bytes
  723. * to be written.  If <numBytes> is greater than the `maxBytesLimit' field
  724. * defined in the `pScsiPhysDev' structure, then more than one SCSI transaction
  725. * is used to transfer the data.
  726. *
  727. * RETURNS: OK, or ERROR if the data cannot be written or zero bytes are 
  728. * written.
  729. */
  730. STATUS scsiWrtTape
  731.     (
  732.     SCSI_SEQ_DEV *pScsiSeqDev,    /* ptr to SCSI sequential device info  */
  733.     int numBytes,                 /* total bytes or blocks to be written */
  734.     char *buffer,                 /* ptr to input data buffer            */
  735.     BOOL fixedSize   /* if variable size blocks             */
  736.     )
  737.     {
  738.     SCSI_COMMAND scsiCommand;   /* SCSI command byte array          */
  739.     SCSI_TRANSACTION scsiXaction; /* info on a SCSI transaction       */
  740.     SCSI_PHYS_DEV *pScsiPhysDev;  /* ptr to SCSI physical device info */
  741.     STATUS status = ERROR;   /* status of transaction            */
  742.     UINT8 * bufPtr;               /*  ptr to input data buffer        */
  743.     UINT timeout;                 /* scsi command timeout             */
  744.     int  xferLength;              /* transfer length                  */
  745.     int  numBlocks;
  746.     int  maxVarBlockLimit;
  747.     int  writeBytes;
  748.     int  xferBlocks;
  749.     SCSI_DEBUG_MSG ("scsiWrtTape:n", 0, 0, 0, 0, 0, 0);
  750.     pScsiPhysDev = pScsiSeqDev->pScsiPhysDev;
  751.     /*
  752.      * Fixed block size transfer. The block size must be defined in 
  753.      * pScsiPhysDev prior to calling this function 
  754.      */
  755.     if (fixedSize)
  756.         {
  757. numBlocks = numBytes; /* numBytes means numBlocks for fixed blk size */
  758. if (numBlocks > SCSI_MAX_XFER_BLOCKS)
  759.     return (ERROR);
  760. /*
  761.  * Check if the number of blocks to be transferred
  762.  * is less than the max permissible size 
  763.  */
  764. if (numBlocks <= (pScsiPhysDev->pScsiCtrl->maxBytesPerXfer / 
  765.   pScsiSeqDev->seqDev.sd_blkSize))
  766.         {
  767.     scsiCmdFill (pScsiSeqDev, scsiCommand, SCSI_WRITE, TRUE, 
  768.  numBlocks);
  769.     bufPtr = (UINT8 *) buffer;
  770.     xferLength = numBlocks * pScsiSeqDev->seqDev.sd_blkSize;
  771.     /* 
  772.      * timeout value is based on 100kB/sec xfer and a 5 
  773.      * sec threshold 
  774.      */
  775.     timeout = SCSI_TIMEOUT_5SEC * 50 + (10 * numBlocks *
  776. pScsiPhysDev->blockSize);
  777.     scsiXactionFill (&scsiXaction, scsiCommand, SCSI_WRITE,
  778.      SCSI_GROUP_0_CMD_LENGTH, timeout, xferLength,
  779.      bufPtr);     
  780.     status = (*pScsiPhysDev->pScsiCtrl->scsiTransact)
  781.      (pScsiPhysDev, &scsiXaction);
  782.     return (status);
  783.     }
  784. else
  785.     {
  786.     /* determine the max number of blocks that can be transferred */
  787.             xferBlocks = (pScsiPhysDev->pScsiCtrl->maxBytesPerXfer) /
  788.                  (pScsiSeqDev->seqDev.sd_blkSize);
  789.     while (numBlocks > 0)
  790.                 {   
  791. scsiCmdFill (pScsiSeqDev, scsiCommand, SCSI_WRITE, TRUE, 
  792.      xferBlocks);
  793. bufPtr = (UINT8 *) buffer;
  794. xferLength = xferBlocks * pScsiSeqDev->seqDev.sd_blkSize;
  795. /* 
  796.  * timeout value is based on 100kB/sec xfer and a 5 
  797.  * sec threshold 
  798.  */
  799. timeout = SCSI_TIMEOUT_5SEC * 50 + (10 * xferBlocks *
  800.     pScsiPhysDev->blockSize);
  801. scsiXactionFill (&scsiXaction, scsiCommand, SCSI_WRITE,
  802.  SCSI_GROUP_0_CMD_LENGTH, timeout, xferLength,
  803.  bufPtr);
  804. status = (*pScsiPhysDev->pScsiCtrl->scsiTransact)
  805.   (pScsiPhysDev, &scsiXaction);
  806. if (status == OK )
  807.     {
  808.      numBlocks -= xferBlocks;
  809.      buffer += (xferBlocks * pScsiSeqDev->seqDev.sd_blkSize);
  810.      if (numBlocks <= 
  811.  (pScsiPhysDev->pScsiCtrl->maxBytesPerXfer /
  812.   pScsiSeqDev->seqDev.sd_blkSize))
  813.        xferBlocks = numBlocks; 
  814.     }
  815. else
  816.     return (status);   
  817. }
  818.     return (status);
  819.     }
  820. }
  821.     /* get the maximum variable block size for the device */    
  822.     
  823.     maxVarBlockLimit = pScsiPhysDev->maxVarBlockLimit;
  824.     if ( maxVarBlockLimit > pScsiPhysDev->pScsiCtrl->maxBytesPerXfer)
  825. maxVarBlockLimit = pScsiPhysDev->pScsiCtrl->maxBytesPerXfer;
  826.     /* multiple transactions needed if numBytes > maxVarBlockLimit */
  827.     for (writeBytes=0; numBytes > maxVarBlockLimit;
  828.         numBytes -= maxVarBlockLimit, writeBytes += maxVarBlockLimit)
  829.         {
  830. scsiCmdFill (pScsiSeqDev, scsiCommand, SCSI_WRITE, FALSE, 
  831.      maxVarBlockLimit);
  832. bufPtr = (UINT8 *) buffer + writeBytes;
  833. xferLength = maxVarBlockLimit;
  834. timeout = SCSI_TIMEOUT_5SEC * 50 + (maxVarBlockLimit * 10);
  835. scsiXactionFill (&scsiXaction, scsiCommand, SCSI_WRITE,
  836.  SCSI_GROUP_0_CMD_LENGTH, timeout, xferLength,
  837.  bufPtr);
  838.         status = (*pScsiPhysDev->pScsiCtrl->scsiTransact)
  839.                 (pScsiPhysDev, &scsiXaction);
  840.         if (status == ERROR)
  841.     return (status);
  842.         }
  843.     if (numBytes > 0)
  844. {
  845. scsiCmdFill (pScsiSeqDev, scsiCommand, SCSI_WRITE, FALSE, numBytes);
  846. bufPtr = (UINT8 *) buffer + writeBytes;
  847. xferLength = numBytes;
  848. timeout = SCSI_TIMEOUT_5SEC * 50 + (numBytes * 10);
  849. scsiXactionFill (&scsiXaction, scsiCommand, SCSI_WRITE,
  850.  SCSI_GROUP_0_CMD_LENGTH, timeout, xferLength,
  851.  bufPtr);
  852.         status = (*pScsiPhysDev->pScsiCtrl->scsiTransact)
  853.                 (pScsiPhysDev, &scsiXaction);
  854.         }
  855.     return (status);
  856.     }
  857. /*******************************************************************************
  858. *
  859. * scsiRewind - issue a REWIND command to a SCSI device
  860. *
  861. * This routine issues a REWIND command to a specified SCSI device.
  862. *
  863. * RETURNS: OK, or ERROR if the command fails.
  864. */
  865. STATUS scsiRewind
  866.     (
  867.     SCSI_SEQ_DEV *pScsiSeqDev /* ptr to SCSI Sequential device */
  868.     )
  869.     {
  870.     SCSI_COMMAND rewindCommand; /* SCSI command byte array     */
  871.     SCSI_TRANSACTION scsiXaction; /* info on a SCSI transaction  */
  872.     SCSI_PHYS_DEV * pScsiPhysDev;     /* ptr to SCSI physical device */
  873.     STATUS status; /* holds status of transaction */
  874.     SCSI_DEBUG_MSG ("scsiRewind:n", 0, 0, 0, 0, 0, 0);
  875.     pScsiPhysDev = pScsiSeqDev->pScsiPhysDev;
  876.     rewindCommand[0] = SCSI_OPCODE_REWIND;
  877.     rewindCommand[1] = (UINT8) ((pScsiPhysDev->scsiDevLUN & 0x7) << 5);
  878.     rewindCommand[2] = (UINT8) 0;
  879.     rewindCommand[3] = (UINT8) 0;
  880.     rewindCommand[4] = (UINT8) 0;
  881.     rewindCommand[5] = (UINT8) 0;
  882.     scsiXaction.cmdAddress    = rewindCommand;
  883.     scsiXaction.cmdLength     = SCSI_GROUP_0_CMD_LENGTH;
  884.     scsiXaction.dataAddress   = (UINT8 *) NULL;
  885.     scsiXaction.dataDirection = O_WRONLY;
  886.     scsiXaction.dataLength    = 0;
  887.     scsiXaction.addLengthByte = NULL;
  888.     scsiXaction.cmdTimeout    = SCSI_TIMEOUT_FULL;
  889.     scsiXaction.tagType       = SCSI_TAG_DEFAULT;
  890.     scsiXaction.priority      = SCSI_THREAD_TASK_PRIORITY;
  891.     status = (*pScsiPhysDev->pScsiCtrl->scsiTransact)
  892.       (pScsiPhysDev, &scsiXaction);
  893.     return (status);
  894.     }
  895. /*******************************************************************************
  896. *
  897. * scsiReserveUnit - issue a RESERVE UNIT command to a SCSI device
  898. *
  899. * This routine issues a RESERVE UNIT command to a specified SCSI device.
  900. *
  901. * RETURNS: OK, or ERROR if the command fails.
  902. */
  903. STATUS scsiReserveUnit
  904.     (
  905.     SCSI_SEQ_DEV *pScsiSeqDev /* ptr to SCSI sequential device */
  906.     )
  907.     {
  908.     SCSI_COMMAND reserveUnitCommand; /* SCSI command byte array     */
  909.     SCSI_TRANSACTION scsiXaction; /* info on a SCSI transaction  */
  910.     SCSI_PHYS_DEV *pScsiPhysDev;        /* ptr to SCSI physical device */
  911.     STATUS status; /* status of transaction       */
  912.     SCSI_DEBUG_MSG ("scsiReserveUnit:n", 0, 0, 0, 0, 0, 0);
  913.     pScsiPhysDev = pScsiSeqDev->pScsiPhysDev;
  914.     reserveUnitCommand[0] = SCSI_OPCODE_RESERVE;
  915.     reserveUnitCommand[1] = (UINT8) 0;
  916.     reserveUnitCommand[2] = (UINT8) 0;
  917.     reserveUnitCommand[3] = (UINT8) 0;
  918.     reserveUnitCommand[4] = (UINT8) 0;
  919.     reserveUnitCommand[5] = (UINT8) 0;
  920.     scsiXaction.cmdAddress    = reserveUnitCommand;
  921.     scsiXaction.cmdLength     = SCSI_GROUP_0_CMD_LENGTH;
  922.     scsiXaction.dataAddress   = (UINT8 *) NULL;
  923.     scsiXaction.dataDirection = O_WRONLY;
  924.     scsiXaction.dataLength    = 0;
  925.     scsiXaction.addLengthByte = NULL;
  926.     scsiXaction.cmdTimeout    = SCSI_TIMEOUT_5SEC;
  927.     scsiXaction.tagType       = SCSI_TAG_DEFAULT;
  928.     scsiXaction.priority      = SCSI_THREAD_TASK_PRIORITY;
  929.     status = (*pScsiPhysDev->pScsiCtrl->scsiTransact)
  930.       (pScsiPhysDev, &scsiXaction);
  931.     return (status);
  932.     }
  933. /*******************************************************************************
  934. *
  935. * scsiReleaseUnit - issue a RELEASE UNIT command to a SCSI device
  936. *
  937. * This routine issues a RELEASE UNIT command to a specified SCSI device.
  938. *
  939. * RETURNS: OK, or ERROR if the command fails.
  940. */
  941. STATUS scsiReleaseUnit
  942.     (
  943.     SCSI_SEQ_DEV *pScsiSeqDev /* ptr to SCSI sequential device */
  944.     )
  945.     {
  946.     SCSI_COMMAND releaseUnitCommand; /* SCSI command byte array     */
  947.     SCSI_TRANSACTION scsiXaction; /* info on a SCSI transaction  */
  948.     SCSI_PHYS_DEV *pScsiPhysDev;        /* ptr to SCSI physical device */
  949.     STATUS status; /* status of transaction       */
  950.     SCSI_DEBUG_MSG ("scsiReleaseUnit:n", 0, 0, 0, 0, 0, 0);
  951.     pScsiPhysDev = pScsiSeqDev->pScsiPhysDev;
  952.     releaseUnitCommand[0] = SCSI_OPCODE_RELEASE;
  953.     releaseUnitCommand[1] = (UINT8) 0;
  954.     releaseUnitCommand[2] = (UINT8) 0;
  955.     releaseUnitCommand[3] = (UINT8) 0;
  956.     releaseUnitCommand[4] = (UINT8) 0;
  957.     releaseUnitCommand[5] = (UINT8) 0;
  958.     scsiXaction.cmdAddress    = releaseUnitCommand;
  959.     scsiXaction.cmdLength     = SCSI_GROUP_0_CMD_LENGTH;
  960.     scsiXaction.dataAddress   = (UINT8 *) NULL;
  961.     scsiXaction.dataDirection = O_WRONLY;
  962.     scsiXaction.dataLength    = 0;
  963.     scsiXaction.addLengthByte = NULL;
  964.     scsiXaction.cmdTimeout    = SCSI_TIMEOUT_5SEC;
  965.     scsiXaction.tagType       = SCSI_TAG_DEFAULT;
  966.     scsiXaction.priority      = SCSI_THREAD_TASK_PRIORITY;
  967.     status = (*pScsiPhysDev->pScsiCtrl->scsiTransact)
  968.       (pScsiPhysDev, &scsiXaction);
  969.     return (status);
  970.     }
  971. /*******************************************************************************
  972. *
  973. * scsiLoadUnit - issue a LOAD/UNLOAD command to a SCSI device
  974. *
  975. * This routine issues a LOAD/UNLOAD command to a specified SCSI device.
  976. *
  977. * RETURNS: OK, or ERROR if the command fails.
  978. */
  979. STATUS scsiLoadUnit
  980.     (
  981.     SCSI_SEQ_DEV * pScsiSeqDev,         /* ptr to SCSI physical device */
  982.     BOOL           load, /* TRUE=load, FALSE=unload     */
  983.     BOOL    reten, /* TRUE=retention and unload   */
  984.     BOOL    eot /* TRUE=end of tape and unload */
  985.     )
  986.     {
  987.     SCSI_COMMAND loadCommand; /* SCSI command byte array     */
  988.     SCSI_TRANSACTION scsiXaction; /* info on a SCSI transaction  */
  989.     SCSI_PHYS_DEV *pScsiPhysDev; /* ptr to SCSI physical device */
  990.     STATUS status; /* status of transaction       */
  991.     SCSI_DEBUG_MSG ("scsiLoadUnit:n", 0, 0, 0, 0, 0, 0);
  992.     pScsiPhysDev = pScsiSeqDev->pScsiPhysDev;
  993.     loadCommand[0] = SCSI_OPCODE_LOAD_UNLOAD;
  994.     loadCommand[1] = (UINT8) 0;
  995.     loadCommand[2] = (UINT8) 0;
  996.     loadCommand[3] = (UINT8) 0;
  997.     /* 
  998.      * Check for load, retension and eot (TRUE/FALSE) conditions.
  999.      * Byte4 bit2 of CDB: eot
  1000.      * Byte4 bit1 of CDB: reten
  1001.      * Byte4 bit0 of CDB: load
  1002.      */
  1003.     if (load && eot)  /* invalid condition */
  1004. return (ERROR);
  1005.     if (load)
  1006.         loadCommand[4] = (UINT8) 1;
  1007.     else /* unload */
  1008. {
  1009.         loadCommand[4] = (UINT8) 0;
  1010.         if (eot)
  1011.     loadCommand[4] |= (0x1 << 2);
  1012.         }
  1013.     if (reten)
  1014.      loadCommand[4] |= (0x1 << 1);
  1015.     loadCommand[5] = (UINT8) 0;
  1016.     scsiXaction.cmdAddress    = loadCommand;
  1017.     scsiXaction.cmdLength     = SCSI_GROUP_0_CMD_LENGTH;
  1018.     scsiXaction.dataAddress   = (UINT8 *) NULL;
  1019.     scsiXaction.dataDirection = O_WRONLY;
  1020.     scsiXaction.dataLength    = 0;
  1021.     scsiXaction.addLengthByte = NULL;
  1022.     scsiXaction.cmdTimeout    = SCSI_TIMEOUT_5SEC * 10;
  1023.     scsiXaction.tagType       = SCSI_TAG_DEFAULT;
  1024.     scsiXaction.priority      = SCSI_THREAD_TASK_PRIORITY;
  1025.     status = (*pScsiPhysDev->pScsiCtrl->scsiTransact)
  1026.       (pScsiPhysDev, &scsiXaction);
  1027.     return (status);
  1028.     }
  1029. /*******************************************************************************
  1030. *
  1031. * scsiWrtFileMarks - write file marks to a SCSI sequential device
  1032. *
  1033. * This routine writes file marks to a specified physical device.
  1034. *
  1035. * RETURNS: OK, or ERROR if the file mark cannot be written.
  1036. */
  1037. STATUS scsiWrtFileMarks
  1038.     (
  1039.     SCSI_SEQ_DEV * pScsiSeqDev,   /* ptr to SCSI sequential device info */
  1040.     int            numMarks,      /* number of file marks to write      */
  1041.     BOOL           shortMark   /* TRUE to write short file mark      */
  1042.     )
  1043.     {
  1044.     SCSI_COMMAND     scsiCommand; /* SCSI command byte array          */
  1045.     SCSI_TRANSACTION scsiXaction; /* info on a SCSI transaction       */
  1046.     SCSI_PHYS_DEV *  pScsiPhysDev;      /* ptr to SCSI physical device info */
  1047.     STATUS           status; /* status of transactions           */
  1048.     SCSI_DEBUG_MSG ("scsiWrtFileMarks:n", 0, 0, 0, 0, 0, 0);
  1049.     pScsiPhysDev = pScsiSeqDev->pScsiPhysDev;
  1050.     scsiCommand[0] = SCSI_OPCODE_WRITE_FILEMARKS;
  1051.     scsiCommand[1] = (UINT8) ((pScsiPhysDev->scsiDevLUN & 0x7) << 5);
  1052.     scsiCommand[2] = (UINT8) ((numMarks >> 16) & 0xff);
  1053.     scsiCommand[3] = (UINT8) ((numMarks >>  8) & 0xff);
  1054.     scsiCommand[4] = (UINT8) (numMarks & 0xff);
  1055.     if (shortMark)
  1056. scsiCommand [5] = 0x80;
  1057.     else
  1058.         scsiCommand[5] = (UINT8) 0;
  1059.     scsiXaction.cmdAddress    = scsiCommand;
  1060.     scsiXaction.cmdLength     = SCSI_GROUP_0_CMD_LENGTH;
  1061.     scsiXaction.dataAddress   = NULL;
  1062.     scsiXaction.dataDirection = O_WRONLY;
  1063.     scsiXaction.dataLength    = NULL;
  1064.     scsiXaction.addLengthByte = NULL;
  1065.     if (numMarks < 500)
  1066.         scsiXaction.cmdTimeout = SCSI_TIMEOUT_5SEC * (numMarks + 10);
  1067.     else
  1068. scsiXaction.cmdTimeout = SCSI_TIMEOUT_FULL;
  1069.     scsiXaction.tagType       = SCSI_TAG_DEFAULT;
  1070.     scsiXaction.priority      = SCSI_THREAD_TASK_PRIORITY;
  1071.     status = (*pScsiPhysDev->pScsiCtrl->scsiTransact)
  1072.       (pScsiPhysDev, &scsiXaction);
  1073.     return (status);
  1074.     }
  1075. /*******************************************************************************
  1076. *
  1077. * scsiSpace - move the tape on a specified physical SCSI device
  1078. *
  1079. * This routine moves the tape on a specified SCSI physical device.
  1080. * There are two types of space code that are mandatory in SCSI; currently
  1081. * these are the only two supported:
  1082. *
  1083. * .TS
  1084. * tab(|);
  1085. * lf3 lf3 cf3
  1086. * l l c.
  1087. * Code | Description | Support
  1088. * _
  1089. * 000 | Blocks       | Yes
  1090. * 001 | File marks            | Yes
  1091. * 010 | Sequential file marks | No
  1092. * 011 | End-of-data           | No
  1093. * 100 | Set marks             | No
  1094. * 101 | Sequential set marks  | No
  1095. * .TE
  1096. *
  1097. * RETURNS: OK, or ERROR if an error is returned by the device.
  1098. *
  1099. * ERRNO: S_scsiLib_ILLEGAL_REQUEST
  1100. */
  1101. STATUS scsiSpace
  1102.     (
  1103.     SCSI_SEQ_DEV * pScsiSeqDev,  /* ptr to SCSI sequential device info */
  1104.     int count,                   /* count for space command            */
  1105.     int spaceCode  /* code for the type of space command */
  1106.     )
  1107.     {
  1108.     SCSI_PHYS_DEV *pScsiPhysDev; /* ptr to SCSI physical device info */
  1109.     SCSI_COMMAND scsiCommand; /* SCSI command byte array          */
  1110.     SCSI_TRANSACTION scsiXaction; /* info on a SCSI transaction       */
  1111.     STATUS status; /* status of transaction            */
  1112.     SCSI_DEBUG_MSG ("scsiSpace:n", 0, 0, 0, 0, 0, 0);
  1113.     pScsiPhysDev = pScsiSeqDev->pScsiPhysDev;
  1114.     if ((count == 0) || ((spaceCode != SPACE_CODE_DATABLK) && 
  1115.  (spaceCode != SPACE_CODE_FILEMARK)))
  1116.         {
  1117. errno = S_scsiLib_ILLEGAL_REQUEST;
  1118. return (ERROR);
  1119. }
  1120.     scsiCommand[0] = SCSI_OPCODE_SPACE;
  1121.     scsiCommand[1] = (UINT8) (((pScsiPhysDev->scsiDevLUN & 0x7) << 5) |
  1122.       (spaceCode));
  1123.     scsiCommand[2] = (UINT8) ((count >> 16) & 0xff);
  1124.     scsiCommand[3] = (UINT8) ((count >>  8) & 0xff);
  1125.     scsiCommand[4] = (UINT8) (count & 0xff);
  1126.     scsiCommand[5] = (UINT8) 0;
  1127.     scsiXaction.cmdAddress    = scsiCommand;
  1128.     scsiXaction.cmdLength     = SCSI_GROUP_0_CMD_LENGTH;
  1129.     scsiXaction.dataAddress   = NULL;
  1130.     scsiXaction.dataDirection = O_RDONLY;
  1131.     scsiXaction.dataLength    = NULL;
  1132.     scsiXaction.addLengthByte = NULL;
  1133.     if (count < 500)
  1134.         scsiXaction.cmdTimeout = SCSI_TIMEOUT_5SEC * count * 10;
  1135.     else
  1136. scsiXaction.cmdTimeout = SCSI_TIMEOUT_FULL;
  1137.     scsiXaction.tagType       = SCSI_TAG_DEFAULT;
  1138.     scsiXaction.priority      = SCSI_THREAD_TASK_PRIORITY;
  1139.     status = (*pScsiPhysDev->pScsiCtrl->scsiTransact)
  1140.       (pScsiPhysDev, &scsiXaction);
  1141.     return (status);
  1142.     }
  1143. /*******************************************************************************
  1144. *
  1145. * scsiSeqStatusCheck - detect a change in media
  1146. *
  1147. * This routine issues a TEST_UNIT_READY command to a SCSI device to detect a
  1148. * change in media. It is called by file systems before executing open() or
  1149. * creat().
  1150. *
  1151. * INTERNAL
  1152. * This function is a duplicate of that in scsiDirectLib, except for the fact
  1153. * that this function operates on a SEQ_DEV.
  1154. * RETURNS: OK or ERROR.
  1155. */
  1156. STATUS scsiSeqStatusCheck
  1157.     (
  1158.     SCSI_SEQ_DEV *pScsiSeqDev          /* ptr to a sequential dev */
  1159.     )
  1160.     {
  1161.     SCSI_PHYS_DEV *pScsiPhysDev;        /* ptr to SCSI physical device */
  1162.     SCSI_COMMAND testUnitRdyCommand;    /* SCSI command byte array     */
  1163.     SCSI_TRANSACTION scsiXaction;       /* info on a SCSI transaction  */
  1164.     char             modeBuf[0xff];     /* get mode sense data array   */
  1165.     int      modeBufLen;
  1166.     int       pageControl;
  1167.     int              pageCode;
  1168.     pScsiPhysDev =  pScsiSeqDev->pScsiPhysDev;
  1169.     if (scsiCmdBuild (testUnitRdyCommand, &scsiXaction.cmdLength,
  1170.         SCSI_OPCODE_TEST_UNIT_READY, pScsiPhysDev->scsiDevLUN, FALSE,
  1171.         0, 0, (UINT8) 0) == ERROR)
  1172.         {
  1173.         return (ERROR);
  1174.         }
  1175.     scsiXaction.cmdAddress    = testUnitRdyCommand;
  1176.     scsiXaction.dataAddress   = NULL;
  1177.     scsiXaction.dataDirection = NONE;
  1178.     scsiXaction.dataLength    = 0;
  1179.     scsiXaction.addLengthByte = NONE;
  1180.     scsiXaction.cmdTimeout    = SCSI_TIMEOUT_5SEC;
  1181.     scsiXaction.tagType       = SCSI_TAG_DEFAULT;
  1182.     scsiXaction.priority      = SCSI_THREAD_TASK_PRIORITY;
  1183.     if ((*pScsiPhysDev->pScsiCtrl->scsiTransact) (pScsiPhysDev, &scsiXaction)
  1184.              == ERROR)
  1185. {
  1186.         SCSI_DEBUG_MSG ("scsiSeqStatusCheck returning ERROR, last Sense = %xn",
  1187.                         pScsiPhysDev->lastSenseKey, 0, 0, 0, 0, 0);
  1188.         return (ERROR);
  1189. }
  1190.     pageControl = 0x0;  /* current values     */
  1191.     pageCode    = 0x0;  /* no page formatting */
  1192.     /* (Mode param hdr len) + (mode param block descriptor len) */
  1193.     modeBufLen  = 4 + 8;
  1194.     if (scsiModeSense (pScsiPhysDev, pageControl, pageCode, modeBuf,
  1195.        modeBufLen
  1196.        ) == ERROR)
  1197.         return (ERROR);
  1198.     /* Set the mode of the device */
  1199.     pScsiSeqDev->seqDev.sd_mode =
  1200. ( modeBuf [SCSI_MODE_DEV_SPECIFIC_PARAM] &
  1201.   (UINT8) SCSI_DEV_SPECIFIC_WP_MASK
  1202.         ) ? O_RDONLY : O_RDWR;
  1203.     return (OK);
  1204.    
  1205.     }
  1206. /*******************************************************************************
  1207. *
  1208. * scsiSeqIoctl - perform an I/O control function for sequential access devices
  1209. *
  1210. * This routine issues scsiSeqLib commands to perform sequential
  1211. * device-specific I/O control operations.
  1212. *
  1213. * RETURNS: OK or ERROR.
  1214. *
  1215. * ERRNO: S_scsiLib_INVALID_BLOCK_SIZE
  1216. */
  1217. int scsiSeqIoctl
  1218.     (
  1219.     SCSI_SEQ_DEV *  pScsiSeqDev,    /* ptr to SCSI sequential device */
  1220.     int     function,     /* ioctl function code */
  1221.     int     arg      /* argument to pass to called function */
  1222.     )
  1223.     {
  1224.     char modeBuf[MODE_BUF_LENGTH];
  1225.     int  modeBufLen;
  1226.     int  pageControl;
  1227.     int  pageCode;
  1228.     int  pageFormat;
  1229.     int  savePages;
  1230.     int  blkSize;
  1231.     SCSI_PHYS_DEV * pScsiPhysDev; /* ptr to SCSI physical device struct */
  1232.     if ((pScsiPhysDev = pScsiSeqDev->pScsiPhysDev) == NULL)
  1233. {
  1234. /* XXX errno */
  1235. SCSI_DEBUG_MSG ("scsiSeqIoctl: pScsiSeqDev ptr NULLn",0,0,0,0,0,0);
  1236. return (ERROR);
  1237. }
  1238.     switch (function)
  1239. {
  1240.      case FIODENSITYSET:
  1241.             /* Execute a MODE SENSE to get the right buffer values */
  1242.     pageControl = 0x0;  /* current values     */
  1243.     pageCode    = 0x0;  /* no page formatting */
  1244.             /* (Mode param hdr len) + (mode param block descriptor len) */
  1245.          modeBufLen  = 4 + 8;
  1246.     if (scsiModeSense (pScsiPhysDev, pageControl, pageCode, modeBuf,
  1247.        modeBufLen
  1248.       ) == ERROR)
  1249. return (ERROR);
  1250.             
  1251.     /* Execute a MODE SELECT to set the density value */
  1252.     modeBuf[0] = 0x0; /* mode data len not valid for mode select   */
  1253.     /* modeBuf[1] is reserved; medium type not valid for seq devices */
  1254.     modeBuf[2] = 0x0;   /* dev-specific param not defined for md sel */
  1255.     modeBuf[4] = arg;   /* set density code                          */
  1256.             pageFormat = 0x0;   /* no formatted pages                        */
  1257.     savePages  = 0x1;   /* save page values                          */
  1258.     if (scsiModeSelect (pScsiPhysDev, pageFormat, savePages, modeBuf,
  1259. modeBufLen) == ERROR)
  1260.         return (ERROR);
  1261.             /* Check that the density was set correctly by issuing MODE SENSE */
  1262.             
  1263.     if (scsiModeSense (pScsiPhysDev, pageControl, pageCode, modeBuf,
  1264.        modeBufLen
  1265.       ) == ERROR)
  1266. return (ERROR);
  1267.             if (modeBuf[4] != arg)
  1268. {
  1269. /* XXX set errno */
  1270. return (ERROR);
  1271. }
  1272.     pScsiSeqDev->seqDev.sd_density = arg;
  1273.     return (OK);
  1274.         case FIODENSITYGET:
  1275.             /* Execute a MODE SENSE to get the right buffer values */
  1276.             
  1277.             pageControl = 0x0;  /* current values     */
  1278.             pageCode    = 0x0;  /* no page formatting */
  1279.             /* (Mode param hdr len) + (mode param block descriptor len) */
  1280.             modeBufLen  = 4 + 8;
  1281.             if (scsiModeSense (pScsiPhysDev, pageControl, pageCode, modeBuf,
  1282.                                modeBufLen
  1283.                               ) == ERROR)
  1284.                 return (ERROR);
  1285.             * ((int *) arg) = modeBuf[4]; /* density */
  1286.     return (OK);
  1287.         case FIOBLKSIZESET:
  1288.             /* Execute a MODE SENSE to get the right buffer values */
  1289.             
  1290.             pageControl = 0x0;  /* current values     */
  1291.             pageCode    = 0x0;  /* no page formatting */
  1292.             /* (Mode param hdr len) + (mode param block descriptor len) */
  1293.             modeBufLen  = 4 + 8;
  1294.             if (scsiModeSense (pScsiPhysDev, pageControl, pageCode, modeBuf,
  1295.                                modeBufLen
  1296.                               ) == ERROR)
  1297.                 return (ERROR);
  1298.             /* Execute a MODE SELECT to set the blkSize value */
  1299.             modeBuf[0]  = 0x0;   /* mode data len not valid for mode select   */
  1300.             /* modeBuf[1] is reserved; medium type not valid for seq devices  */
  1301.     modeBuf[1] = 0x0;
  1302.             modeBuf[2] = 0x0;    /* dev-specific param not defined for md sel */
  1303.             /* Set the block size */
  1304.             modeBuf[9]  = (UINT8) ((arg >> 16) & 0xff);
  1305.             modeBuf[10] = (UINT8) ((arg >>  8) & 0xff);
  1306.             modeBuf[11] = (UINT8) ( arg & 0xff); 
  1307.             pageFormat = 0x1;   /* no formatted pages                        */
  1308.             savePages  = 0x0;   /* save page values                          */
  1309.             if (scsiModeSelect (pScsiPhysDev, pageFormat, savePages, modeBuf,
  1310.                                 modeBufLen) == ERROR)
  1311.                 return (ERROR);
  1312.             /* Check that the block size was set correctly */
  1313.             blkSize = scsiSeqIoctl (pScsiSeqDev, FIOBLKSIZEGET, 0);
  1314.             if (blkSize != arg)
  1315.                 {
  1316.                 errno = S_scsiLib_INVALID_BLOCK_SIZE;
  1317.                 return (ERROR);
  1318.                 }
  1319.             pScsiSeqDev->seqDev.sd_blkSize = blkSize;
  1320.             return (OK);
  1321.         case FIOBLKSIZEGET:
  1322.             /* Execute a MODE SENSE to get the right buffer values */
  1323.             
  1324.             pageControl = 0x0;  /* current values     */
  1325.             pageCode    = 0x0;  /* no page formatting */
  1326.             /* (Mode param hdr len) + (mode param block descriptor len) */
  1327.             modeBufLen  = 4 + 8;
  1328.             if (scsiModeSense (pScsiPhysDev, pageControl, pageCode, modeBuf,
  1329.                                modeBufLen
  1330.                               ) == ERROR)
  1331.                 return (ERROR);
  1332.             /* Construct the block size from the buffer */
  1333.             blkSize  = 0;
  1334.             blkSize  = (modeBuf[9]  << 16);
  1335.             blkSize |= (modeBuf[10] <<  8);
  1336.             blkSize |=  modeBuf[11];
  1337.             return (blkSize);
  1338.         default:
  1339.     SCSI_DEBUG_MSG ("scsiSeqIoctl: bad IOCTL functionn",0,0,0,0,0,0);
  1340.             return (ERROR);
  1341.         } /* switch */
  1342.     }