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

VxWorks

开发平台:

C/C++

  1. /* scsiDirectLib.c - SCSI library for direct access devices (SCSI-2) */
  2. /* Copyright 1989-1996 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /*
  5. modification history
  6. --------------------
  7. 01g,10mar99,dat  SPR 25196, return error if numsecs == 0
  8. 01f,28aug97,dds  SPR 3425: "scsiFormatUnit" command, times out for disks which 
  9.                  take a long time to format.
  10. 01e,29oct96,dgp  doc: editing for newly published SCSI libraries
  11. 01d,23jul96,dds  SPR 6718: added support for transfers above 16 MB.
  12. 01c,06may96,jds  more doc tweaks
  13. 01b,20sep95,jdi  doc tweak.
  14. 01a,24jul95,jds  written by extracting from scsi2Lib.
  15. */
  16. /*
  17. DESCRIPTION
  18. This library contains commands common to all direct-access SCSI devices.
  19. These routines are separated from scsi2Lib in order to create an additional
  20. layer for better support of all SCSI direct-access devices.
  21. Commands in this library include:
  22. .TS
  23. tab(|);
  24. lf3 lf3
  25. l l.
  26. Command                 | Op Code
  27. _
  28. FORMAT UNIT             | (0x04)
  29. READ (6)                | (0x08)
  30. READ (10)               | (0x28)
  31. READ CAPACITY           | (0x25)
  32. RELEASE                 | (0x17)
  33. RESERVE                 | (0x16)
  34. MODE SELECT (6)         | (0x15)
  35. MODE SELECT (10)        | (0x55)
  36. MODE SENSE (6)          | (0x1a)
  37. MODE SENSE (10)         | (0x5a)
  38. START STOP UNIT         | (0x1b)
  39. WRITE (6)               | (0x0a)
  40. WRITE (10)              | (0x2a)
  41. .TE
  42. INCLUDE FILES
  43. scsiLib.h, scsi2Lib.h
  44. SEE ALSO: dosFsLib, rt11FsLib, rawFsLib, scsi2Lib,
  45. .pG "I/O System, Local File Systems"
  46. */
  47. #define  INCLUDE_SCSI2
  48. #define  SCSI_BLOCK_ADDRESS_SIZE  0x1fffff  /* 21 Bit logical block address */
  49. #include "vxWorks.h"
  50. #include "ioLib.h"
  51. #include "intLib.h"
  52. #include "ctype.h"
  53. #include "cacheLib.h"
  54. #include "stdlib.h"
  55. #include "errnoLib.h"
  56. #include "taskLib.h"
  57. #include "lstLib.h"
  58. #include "logLib.h"
  59. #include "msgQLib.h"
  60. #include "string.h"
  61. #include "stdio.h"
  62. #include "sysLib.h"
  63. #include "scsiLib.h"
  64. #include "wdLib.h"
  65. /* imported globals */
  66. IMPORT BOOL scsiErrors; /* enable SCSI error messages */
  67. IMPORT BOOL scsiDebug; /* enable task level debug messages */
  68. IMPORT BOOL scsiIntsDebug; /* enable int level debug messages */
  69. /* global functions */
  70. void scsiDirectLibTblInit ();
  71. /*
  72.  * Backward compatability functions localised
  73.  */
  74. LOCAL STATUS          scsi2ReadCapacity (SCSI_PHYS_DEV *, int *, int *);
  75. LOCAL STATUS          scsi2RdSecs (SCSI_BLK_DEV *, int, int, char *);
  76. LOCAL STATUS          scsiSectorRead (SCSI_BLK_DEV *, int, int, char *);
  77. LOCAL STATUS          scsi2WrtSecs (SCSI_BLK_DEV *, int, int, char *);
  78. LOCAL STATUS          scsiSectorWrite (SCSI_BLK_DEV *, int, int, char *);
  79. LOCAL STATUS          scsi2FormatUnit (SCSI_PHYS_DEV *, BOOL, int, int, int,
  80.                                                                 char *,int);
  81. LOCAL STATUS          scsi2ModeSelect (SCSI_PHYS_DEV *, int, int, char *, int);
  82. LOCAL STATUS          scsi2ModeSense (SCSI_PHYS_DEV *, int, int, char *, int);
  83. /* Block Device functions */
  84. LOCAL BLK_DEV *       scsi2BlkDevCreate (SCSI_PHYS_DEV *, int, int);
  85. LOCAL void            scsi2BlkDevInit (SCSI_BLK_DEV *, int, int);
  86. LOCAL void            scsi2BlkDevShow (SCSI_PHYS_DEV *);
  87. LOCAL STATUS        scsiStatusCheck (BLK_DEV *pBlkDev);
  88. LOCAL STATUS          scsiBlkDevIoctl (SCSI_BLK_DEV *pScsiBlkDev, 
  89. int function, int arg);
  90. /*******************************************************************************
  91. *
  92. * scsiDirectLibTblInit - initialize direct access functions in table 
  93. *
  94. * Initialisation of array of function pointers for SCSI1 and SCSI2 switching
  95. *
  96. * NOMANUAL
  97. */
  98. void scsiDirectLibTblInit ()
  99.     {
  100.     pScsiIfTbl->scsiBlkDevCreate  = (FUNCPTR) scsi2BlkDevCreate;
  101.     pScsiIfTbl->scsiBlkDevInit    = (FUNCPTR) scsi2BlkDevInit;
  102.     pScsiIfTbl->scsiBlkDevShow    = (FUNCPTR) scsi2BlkDevShow;
  103.     pScsiIfTbl->scsiFormatUnit    = (FUNCPTR) scsi2FormatUnit;
  104.     pScsiIfTbl->scsiModeSelect    = (FUNCPTR) scsi2ModeSelect;
  105.     pScsiIfTbl->scsiModeSense     = (FUNCPTR) scsi2ModeSense;
  106.     pScsiIfTbl->scsiReadCapacity  = (FUNCPTR) scsi2ReadCapacity;
  107.     pScsiIfTbl->scsiRdSecs        = (FUNCPTR) scsi2RdSecs;
  108.     pScsiIfTbl->scsiWrtSecs       = (FUNCPTR) scsi2WrtSecs;
  109.     }
  110. /*******************************************************************************
  111. *
  112. * scsi2BlkDevCreate - define a logical partition on a SCSI block device
  113. *
  114. * This routine creates and initializes a BLK_DEV structure, which
  115. * describes a logical partition on a SCSI physical block device.  A logical
  116. * partition is an array of contiguously addressed blocks; it can be completely
  117. * described by the number of blocks and the address of the first block in
  118. * the partition.  In normal configurations, partitions do not overlap, although
  119. * such a condition is not an error.
  120. *
  121. * NOTE:
  122. * If `numBlocks' is 0, the rest of device is used.
  123. *
  124. * RETURNS: A pointer to the created BLK_DEV, or NULL if parameters exceed
  125. * physical device boundaries, the physical device is not a block device, or
  126. * memory is insufficient for the structures.
  127. */
  128. LOCAL BLK_DEV *scsi2BlkDevCreate
  129.     (
  130.     SCSI_PHYS_DEV *pScsiPhysDev, /* ptr to SCSI physical device info */
  131.     int numBlocks,               /* number of blocks in block device */
  132.     int blockOffset              /* address of first block in volume */
  133.     )
  134.     {
  135.     SCSI_BLK_DEV      *pScsiBlkDev; /* ptr to SCSI block dev struct */
  136.     SCSI_BLK_DEV_NODE *pScsiBlkDevNode; /* ptr to SCSI block dev node struct */
  137.     /* check parameters for validity */
  138.     if ((pScsiPhysDev == NULL) ||
  139.         (numBlocks < 0) || (blockOffset < 0) ||
  140. ((blockOffset + numBlocks) > pScsiPhysDev->numBlocks))
  141. {
  142. errnoSet (S_scsiLib_ILLEGAL_PARAMETER);
  143. SCSI_DEBUG_MSG ("scsiBlkDevCreate: Invalid input parameter(s).n",
  144. 0, 0, 0, 0, 0, 0);
  145. return ((BLK_DEV *) NULL);
  146. }
  147.     /* return NULL if sequential access (or other non-block) device */
  148.     if (!((pScsiPhysDev->scsiDevType == SCSI_DEV_DIR_ACCESS) ||
  149.        (pScsiPhysDev->scsiDevType == SCSI_DEV_WORM) ||
  150.        (pScsiPhysDev->scsiDevType == SCSI_DEV_RO_DIR_ACCESS)))
  151. {
  152. errnoSet (S_scsiLib_ILLEGAL_OPERATION);
  153. SCSI_DEBUG_MSG ("scsiBlkDevCreate:", 0, 0, 0, 0, 0, 0);
  154. SCSI_DEBUG_MSG ("Physical device is not a block device.n",
  155. 0, 0, 0, 0, 0, 0);
  156. return ((BLK_DEV *) NULL);
  157. }
  158.     /* disallow multiple partitions on removable media */
  159.     if (pScsiPhysDev->removable && (lstCount (&pScsiPhysDev->blkDevList) != 0))
  160. {
  161. printErr ("scsiBlkDevCreate: ");
  162. printErr ("Can't create multiple partitions on removable media.n");
  163. return ((BLK_DEV *) NULL);
  164. }
  165.     /* create a SCSI block device node structure */
  166.     pScsiBlkDevNode =
  167. (SCSI_BLK_DEV_NODE *) calloc (1, sizeof (SCSI_BLK_DEV_NODE));
  168.     if (pScsiBlkDevNode == NULL)
  169.         return ((BLK_DEV *) NULL);
  170.     pScsiBlkDev = &pScsiBlkDevNode->scsiBlkDev;
  171.     /* fill in the member data */
  172.     pScsiBlkDev->blkDev.bd_blkRd  = (FUNCPTR) scsiRdSecs;
  173.     pScsiBlkDev->blkDev.bd_blkWrt = (FUNCPTR) scsiWrtSecs;
  174.     pScsiBlkDev->blkDev.bd_ioctl  = (FUNCPTR) scsiBlkDevIoctl;
  175.     pScsiBlkDev->blkDev.bd_reset  = (FUNCPTR) NULL;
  176.     if (pScsiPhysDev->removable)
  177. pScsiBlkDev->blkDev.bd_statusChk = (FUNCPTR) scsiStatusCheck;
  178.     else
  179. pScsiBlkDev->blkDev.bd_statusChk = (FUNCPTR) NULL;
  180.     pScsiBlkDev->blkDev.bd_removable = pScsiPhysDev->removable;
  181.     pScsiBlkDev->blkDev.bd_nBlocks = (ULONG)
  182. (numBlocks == 0 ? pScsiPhysDev->numBlocks - blockOffset : numBlocks);
  183.     pScsiBlkDev->blkDev.bd_bytesPerBlk = (ULONG) pScsiPhysDev->blockSize;
  184.     pScsiBlkDev->blkDev.bd_retry = 1;
  185.     pScsiBlkDev->blkDev.bd_mode = O_RDWR;
  186.     pScsiBlkDev->blkDev.bd_readyChanged = TRUE;
  187.     pScsiBlkDev->pScsiPhysDev = pScsiPhysDev;
  188.     pScsiBlkDev->blockOffset = blockOffset;
  189.     pScsiBlkDev->numBlocks   = (int) pScsiBlkDev->blkDev.bd_nBlocks;
  190.     /* add block device to list created on the physical device */
  191.     semTake (pScsiPhysDev->mutexSem, WAIT_FOREVER);
  192.     lstAdd (&pScsiPhysDev->blkDevList, &pScsiBlkDevNode->blkDevNode);
  193.     semGive (pScsiPhysDev->mutexSem);
  194.     return (&pScsiBlkDev->blkDev);
  195.     }
  196. /*******************************************************************************
  197. *
  198. * scsi2BlkDevInit - initialize fields in a SCSI logical partition
  199. *
  200. * This routine specifies the disk geometry parameters required by certain
  201. * file systems (e.g., dosFs).  It should be called after a SCSI_BLK_DEV
  202. * structure is created via scsiBlkDevCreate(), but before a file system
  203. * initialization routine.  It is generally required only for removable media
  204. * devices.
  205. *
  206. * RETURNS: N/A
  207. */
  208. LOCAL void scsi2BlkDevInit
  209.     (
  210.     SCSI_BLK_DEV *pScsiBlkDev,  /* ptr to SCSI block dev. struct */
  211.     int blksPerTrack,           /* blocks per track */
  212.     int nHeads                  /* number of heads */
  213.     )
  214.     {
  215.     pScsiBlkDev->blkDev.bd_blksPerTrack = (ULONG) blksPerTrack;
  216.     pScsiBlkDev->blkDev.bd_nHeads = (ULONG) nHeads;
  217.     }
  218. /*******************************************************************************
  219. *
  220. * scsi2BlkDevShow - show the BLK_DEV structures on a specified physical device
  221. *
  222. * This routine displays all of the BLK_DEV structures created on a specified
  223. * physical device.  This routine is called by scsiShow(), but may also be
  224. * invoked directly, usually from the shell.
  225. *
  226. * RETURNS: N/A
  227. */
  228. LOCAL void scsi2BlkDevShow
  229.     (
  230.     SCSI_PHYS_DEV *pScsiPhysDev  /* ptr to SCSI physical device info */
  231.     )
  232.     {
  233.     SCSI_BLK_DEV_NODE *pScsiBlkDevNode;
  234.     int ix = 0;
  235.     printf ("Block Device #       physical address     size (blocks)n");
  236.     printf ("--------------       ----------------     -------------n");
  237.     if (lstCount (&pScsiPhysDev->blkDevList) == 0)
  238. return;
  239.     semTake (pScsiPhysDev->mutexSem, WAIT_FOREVER);
  240.     for (pScsiBlkDevNode = (SCSI_BLK_DEV_NODE *)
  241.        lstFirst (&pScsiPhysDev->blkDevList);
  242.          pScsiBlkDevNode != NULL;
  243.          pScsiBlkDevNode = (SCSI_BLK_DEV_NODE *)
  244.        lstNext (&pScsiBlkDevNode->blkDevNode))
  245.         {
  246. printf ("%8d              %8d                %8dn", ix++,
  247. pScsiBlkDevNode->scsiBlkDev.blockOffset,
  248. pScsiBlkDevNode->scsiBlkDev.numBlocks);
  249. }
  250.     semGive (pScsiPhysDev->mutexSem);
  251.     }
  252. /*******************************************************************************
  253. *
  254. * scsi2FormatUnit - issue a FORMAT_UNIT command to a SCSI device
  255. *
  256. * This routine issues a FORMAT_UNIT command to a specified SCSI device.
  257. *
  258. * RETURNS: OK, or ERROR if the command fails.
  259. */
  260. LOCAL STATUS scsi2FormatUnit
  261.     (
  262.     SCSI_PHYS_DEV *pScsiPhysDev,/* ptr to SCSI physical device */
  263.     BOOL cmpDefectList,         /* whether defect list is complete */
  264.     int defListFormat,          /* defect list format */
  265.     int vendorUnique,           /* vendor unique byte */
  266.     int interleave,             /* interleave factor */
  267.     char *buffer,               /* ptr to input data buffer */
  268.     int bufLength               /* length of buffer in bytes */
  269.     )
  270.     {
  271.     SCSI_COMMAND formatUnitCommand; /* SCSI command byte array */
  272.     SCSI_TRANSACTION scsiXaction; /* info on a SCSI transaction */
  273.     SCSI_DEBUG_MSG ("scsiFormatUnit:n", 0, 0, 0, 0, 0, 0);
  274.     formatUnitCommand[0] = SCSI_OPCODE_FORMAT_UNIT;
  275.     formatUnitCommand[1] = (UINT8) ((pScsiPhysDev->scsiDevLUN & 0x7) << 5);
  276.     if (buffer != (char *) NULL)
  277. {
  278. formatUnitCommand[1] |= SCSI_FORMAT_DATA_BIT;
  279. if (cmpDefectList)
  280.     formatUnitCommand[1] |= SCSI_COMPLETE_LIST_BIT;
  281. formatUnitCommand[1] |= (defListFormat & 0x07);
  282. }
  283.     formatUnitCommand[2]  = (UINT8) vendorUnique;
  284.     formatUnitCommand[3]  = (UINT8) ((interleave >> 8) & 0xff);
  285.     formatUnitCommand[4]  = (UINT8) ((interleave     ) & 0xff);
  286.     formatUnitCommand[5]  = (UINT8) 0;
  287.     scsiXaction.cmdAddress    = formatUnitCommand;
  288.     scsiXaction.cmdLength     = SCSI_GROUP_0_CMD_LENGTH;
  289.     scsiXaction.dataAddress   = (UINT8 *) buffer;
  290.     scsiXaction.dataDirection = O_WRONLY;
  291.     scsiXaction.dataLength    = bufLength;
  292.     scsiXaction.addLengthByte = NONE;
  293.     scsiXaction.cmdTimeout    = WAIT_FOREVER;
  294.     scsiXaction.tagType       = SCSI_TAG_DEFAULT;
  295.     scsiXaction.priority      = SCSI_THREAD_TASK_PRIORITY;
  296.     return ((*pScsiPhysDev->pScsiCtrl->scsiTransact)
  297.     (pScsiPhysDev, &scsiXaction));
  298.     }
  299. /*******************************************************************************
  300. *
  301. * scsi2ModeSelect - issue a MODE_SELECT command to a SCSI device
  302. *
  303. * This routine issues a MODE_SELECT command to a specified SCSI device.
  304. *
  305. * RETURNS: OK, or ERROR if the command fails.
  306. */
  307. LOCAL STATUS scsi2ModeSelect
  308.     (
  309.     SCSI_PHYS_DEV *pScsiPhysDev,/* ptr to SCSI physical device */
  310.     int pageFormat,             /* value of the page format bit (0-1) */
  311.     int saveParams,             /* value of the save parameters bit (0-1) */
  312.     char *buffer,               /* ptr to output data buffer */
  313.     int bufLength               /* length of buffer in bytes */
  314.     )
  315.     {
  316.     SCSI_COMMAND modeSelectCommand; /* SCSI command byte array */
  317.     SCSI_TRANSACTION scsiXaction; /* info on a SCSI transaction */
  318.     int tempLBAField; /* "logical block address" field */
  319.     SCSI_DEBUG_MSG ("scsiModeSelect:n", 0, 0, 0, 0, 0, 0);
  320.     tempLBAField = (pageFormat ? (1 << 20) : 0) | (saveParams ? (1 << 16) : 0);
  321.     if (scsiCmdBuild (modeSelectCommand, &scsiXaction.cmdLength,
  322. SCSI_OPCODE_MODE_SELECT, pScsiPhysDev->scsiDevLUN, FALSE,
  323. tempLBAField, min (0xff, bufLength), (UINT8) 0)
  324. == ERROR)
  325.      return (ERROR);
  326.     scsiXaction.cmdAddress    = modeSelectCommand;
  327.     scsiXaction.dataAddress   = (UINT8 *) buffer;
  328.     scsiXaction.dataDirection = O_WRONLY;
  329.     scsiXaction.dataLength    = min (0xff, bufLength);
  330.     scsiXaction.addLengthByte = NONE;
  331.     scsiXaction.cmdTimeout    = SCSI_TIMEOUT_5SEC;
  332.     scsiXaction.tagType       = SCSI_TAG_DEFAULT;
  333.     scsiXaction.priority      = SCSI_THREAD_TASK_PRIORITY;
  334.     return ((*pScsiPhysDev->pScsiCtrl->scsiTransact)
  335.     (pScsiPhysDev, &scsiXaction));
  336.     }
  337. /*******************************************************************************
  338. *
  339. * scsi2ModeSense - issue a MODE_SENSE command to a SCSI device
  340. *
  341. * This routine issues a MODE_SENSE command to a specified SCSI device.
  342. *
  343. * RETURNS: OK, or ERROR if the command fails.
  344. */
  345. LOCAL STATUS scsi2ModeSense
  346.     (
  347.     SCSI_PHYS_DEV *pScsiPhysDev,/* ptr to SCSI physical device */
  348.     int pageControl,            /* value of the page control field (0-3) */
  349.     int pageCode,               /* value of the page code field (0-0x3f) */
  350.     char *buffer,               /* ptr to input data buffer */
  351.     int bufLength               /* length of buffer in bytes */
  352.     )
  353.     {
  354.     SCSI_COMMAND modeSenseCommand; /* SCSI command byte array */
  355.     SCSI_TRANSACTION scsiXaction; /* info on a SCSI transaction */
  356.     SCSI_DEBUG_MSG ("scsiModeSense:n", 0, 0, 0, 0, 0, 0);
  357.     if (scsiCmdBuild (modeSenseCommand, &scsiXaction.cmdLength,
  358. SCSI_OPCODE_MODE_SENSE, pScsiPhysDev->scsiDevLUN, FALSE,
  359. 0, min (0xff, bufLength), (UINT8) 0)
  360. == ERROR)
  361.      return (ERROR);
  362.     modeSenseCommand [2] = (UINT8) ((pageControl << 6) | pageCode);
  363.     scsiXaction.cmdAddress    = modeSenseCommand;
  364.     scsiXaction.dataAddress   = (UINT8 *) buffer;
  365.     scsiXaction.dataDirection = O_RDONLY;
  366.     scsiXaction.dataLength    = min (0xff, bufLength);
  367.     scsiXaction.addLengthByte = MODE_SENSE_ADD_LENGTH_BYTE;
  368.     scsiXaction.cmdTimeout    = SCSI_TIMEOUT_5SEC;
  369.     scsiXaction.tagType       = SCSI_TAG_DEFAULT;
  370.     scsiXaction.priority      = SCSI_THREAD_TASK_PRIORITY;
  371.     return ((*pScsiPhysDev->pScsiCtrl->scsiTransact)
  372.     (pScsiPhysDev, &scsiXaction));
  373.     }
  374. /*******************************************************************************
  375. *
  376. * scsi2ReadCapacity - issue a READ_CAPACITY command to a SCSI device
  377. *
  378. * This routine issues a READ_CAPACITY command to a specified SCSI device.
  379. *
  380. * RETURNS: OK, or ERROR if the command fails.
  381. */
  382. LOCAL STATUS scsi2ReadCapacity
  383.     (
  384.     SCSI_PHYS_DEV *pScsiPhysDev,/* ptr to SCSI physical device */
  385.     int *pLastLBA,              /* where to return last logical block adrs */
  386.     int *pBlkLength             /* where to return block length */
  387.     )
  388.     {
  389.     SCSI_COMMAND readCapCommand; /* SCSI command byte array */
  390.     RD_CAP_DATA readCapData; /* data structure for results */
  391.     SCSI_TRANSACTION scsiXaction; /* info on a SCSI transaction */
  392.     SCSI_DEBUG_MSG ("scsiReadCapacity:n", 0, 0, 0, 0, 0, 0);
  393.     if (scsiCmdBuild (readCapCommand, &scsiXaction.cmdLength,
  394. SCSI_OPCODE_READ_CAPACITY, pScsiPhysDev->scsiDevLUN, FALSE,
  395. 0, 0, (UINT8) 0)
  396. == ERROR)
  397.      return (ERROR);
  398.     scsiXaction.cmdAddress    = readCapCommand;
  399.     scsiXaction.dataAddress   = (UINT8 *) &readCapData;
  400.     scsiXaction.dataDirection = O_RDONLY;
  401.     scsiXaction.dataLength    = sizeof (readCapData);
  402.     scsiXaction.addLengthByte = NONE;
  403.     scsiXaction.cmdTimeout    = SCSI_TIMEOUT_5SEC;
  404.     scsiXaction.tagType       = SCSI_TAG_DEFAULT;
  405.     scsiXaction.priority      = SCSI_THREAD_TASK_PRIORITY;
  406.     if ((*pScsiPhysDev->pScsiCtrl->scsiTransact) (pScsiPhysDev, &scsiXaction)
  407. == ERROR)
  408. return (ERROR);
  409.     else
  410. {
  411. *pLastLBA   = readCapData.lastLogBlkAdrs;
  412. *pBlkLength = readCapData.blkLength;
  413. SCSI_SWAB (pLastLBA, sizeof (*pLastLBA));
  414. SCSI_SWAB (pBlkLength, sizeof (*pBlkLength));
  415. return (OK);
  416. }
  417.     }
  418. /******************************************************************************
  419. *
  420. * scsi2RdSecs - write sector(s) to a SCSI block device
  421. *
  422. * This routine checks if the data to be transferred is greater than the
  423. * maximum transfer length permitted by the device. If the data to be 
  424. * transferred is greater than the maximum transfer length it breaks the
  425. * data into permissible sizes and loops until the transfer is done.
  426. *
  427. * RETURNS: OK, or ERROR if the sector cannot be written, or if numSecs
  428. * is zero.
  429. */
  430. LOCAL STATUS scsi2RdSecs
  431.     (
  432.     SCSI_BLK_DEV *pScsiBlkDev,  /* ptr to SCSI block device info */
  433.     int sector,                 /* sector number to be read */
  434.     int numSecs,                /* total sectors to be read */
  435.     char *buffer                /* ptr to input data buffer */
  436.     )
  437.     {
  438.     SCSI_PHYS_DEV *pScsiPhysDev = pScsiBlkDev->pScsiPhysDev;
  439.     int dataToXfer;             /* Total Transfer size */
  440.     int sectorNum;               /* sector number to be read */
  441.     int numbSecs;               /* total sectors to be read */
  442.     char *xferBuf;              /* ptr to input data buffer    */
  443.     STATUS xferStatus = OK;
  444.     dataToXfer = numSecs * pScsiPhysDev->blockSize;
  445.     xferBuf = buffer;
  446.     sectorNum = sector;
  447.     if (numSecs == 0)
  448. return ERROR;
  449.     if (dataToXfer <= (pScsiPhysDev->pScsiCtrl->maxBytesPerXfer))
  450. xferStatus = scsiSectorRead (pScsiBlkDev,sector,numSecs,buffer);
  451.     else
  452. {
  453. while (dataToXfer > 0)
  454.     {
  455.     /* determine the number of sectors to read */
  456.     
  457.     if (dataToXfer > (pScsiPhysDev->pScsiCtrl->maxBytesPerXfer))
  458. numbSecs = (pScsiPhysDev->pScsiCtrl->maxBytesPerXfer) / 
  459.           pScsiPhysDev->blockSize;
  460.     else
  461. numbSecs = dataToXfer / pScsiPhysDev->blockSize;
  462.     /* read the sectors */
  463.     xferStatus = scsiSectorRead (pScsiBlkDev,sectorNum,numbSecs,
  464.  xferBuf);
  465.     if (xferStatus == OK)
  466. {
  467. /* 
  468.  * increment the sector no, buffer pointers & update the
  469.  * bytes left to be transferred
  470.  */
  471. sectorNum += numbSecs;
  472. xferBuf += (numbSecs * pScsiPhysDev->blockSize);
  473. dataToXfer -= (numbSecs * pScsiPhysDev->blockSize);
  474. }
  475.     else
  476. return (xferStatus);
  477.     }
  478. }
  479.     return (xferStatus);
  480.     }
  481. /*******************************************************************************
  482. *
  483. * scsiSectorRead - read sector(s) from a SCSI block device
  484. *
  485. * This routine reads the specified physical sector(s) from a specified
  486. * physical device.
  487. *
  488. * RETURNS: OK, or ERROR if the sector cannot be read.
  489. */
  490. LOCAL STATUS scsiSectorRead
  491.     (
  492.     SCSI_BLK_DEV *pScsiBlkDev,  /* ptr to SCSI block device info */
  493.     int sector,                 /* sector number to be read */
  494.     int numSecs,                /* total sectors to be read */
  495.     char *buffer                /* ptr to input data buffer */
  496.     )
  497.     {
  498.     SCSI_COMMAND readCommand; /* SCSI command byte array */
  499.     SCSI_TRANSACTION scsiXaction; /* info on a SCSI transaction */
  500.     SCSI_PHYS_DEV *pScsiPhysDev = pScsiBlkDev->pScsiPhysDev;
  501.     int startSec = sector + pScsiBlkDev->blockOffset;
  502.     
  503.     SCSI_DEBUG_MSG ("scsiRdSecs:n", 0, 0, 0, 0, 0, 0);
  504.     
  505.     if (startSec <= SCSI_BLOCK_ADDRESS_SIZE && numSecs <= 256)
  506.         {
  507.         /* build a 21 bit logical block address 'READ' command */
  508. if (scsiCmdBuild (readCommand, &scsiXaction.cmdLength,
  509.   SCSI_OPCODE_READ, pScsiPhysDev->scsiDevLUN, FALSE,
  510.   startSec, (numSecs == 256 ? 0 : numSecs), (UINT8) 0)
  511.     == ERROR)
  512.     return (ERROR);
  513.         }
  514.     else
  515.         {
  516.         /* build a 32 bit logical block address 'READ_EXTENDED' command */
  517. if (scsiCmdBuild (readCommand, &scsiXaction.cmdLength, 
  518.   SCSI_OPCODE_READ_EXT, pScsiPhysDev->scsiDevLUN, 
  519.   FALSE, startSec, numSecs, (UINT8) 0) == ERROR)
  520.     return (ERROR);
  521.         }
  522.     
  523.     scsiXaction.cmdAddress    = readCommand;
  524.     scsiXaction.dataAddress   = (UINT8 *) buffer;
  525.     scsiXaction.dataDirection = O_RDONLY;
  526.     scsiXaction.dataLength    = numSecs * pScsiPhysDev->blockSize;
  527.     scsiXaction.addLengthByte = NONE;
  528.     scsiXaction.tagType       = SCSI_TAG_DEFAULT;
  529.     scsiXaction.priority      = SCSI_THREAD_TASK_PRIORITY;
  530.     
  531.     if (numSecs < 2000)
  532. scsiXaction.cmdTimeout = SCSI_TIMEOUT_5SEC +
  533.  (SCSI_TIMEOUT_1SEC * numSecs);
  534.     else
  535. scsiXaction.cmdTimeout = SCSI_TIMEOUT_FULL;
  536.     return ((*pScsiPhysDev->pScsiCtrl->scsiTransact)
  537.     (pScsiPhysDev, &scsiXaction));
  538.     }
  539. /*******************************************************************************
  540. *
  541. * scsi2WrtSecs - write sector(s) to a SCSI block device
  542. *
  543. * This routine checks if the data to be transferred is greater than the
  544. * maximum transfer length permitted by the device. If the data to be 
  545. * transferred is greater than the maximum transfer length it breaks the
  546. * data into permissible sizes and loops until the transfer is done.
  547. *
  548. * RETURNS: OK, or ERROR if the sector cannot be written, or if the numSecs
  549. * is zero.
  550. */
  551. LOCAL STATUS scsi2WrtSecs
  552.     (
  553.     SCSI_BLK_DEV *pScsiBlkDev,  /* ptr to SCSI block device info */
  554.     int sector,                 /* sector number to be read */
  555.     int numSecs,                /* total sectors to be read */
  556.     char *buffer                /* ptr to input data buffer */
  557.     )
  558.     {
  559.     SCSI_PHYS_DEV *pScsiPhysDev = pScsiBlkDev->pScsiPhysDev;
  560.     int dataToXfer;             /* Total Transfer size */
  561.     int sectorNum;               /* sector number to be written */
  562.     int numbSecs;               /* total sectors to be written */
  563.     char *xferBuf;              /* ptr to input data buffer    */
  564.     STATUS xferStatus = OK;
  565.     dataToXfer = numSecs * pScsiPhysDev->blockSize;
  566.     xferBuf = buffer;
  567.     sectorNum = sector;
  568.     if (numSecs == 0)
  569. return ERROR;
  570.     if (dataToXfer <= (pScsiPhysDev->pScsiCtrl->maxBytesPerXfer))
  571. xferStatus = scsiSectorWrite (pScsiBlkDev,sector,numSecs,buffer);
  572.     else
  573. {
  574. while (dataToXfer > 0)
  575.     {
  576.     /* determine the number of sectors to written */
  577.     
  578.     if (dataToXfer > (pScsiPhysDev->pScsiCtrl->maxBytesPerXfer))
  579. numbSecs = (pScsiPhysDev->pScsiCtrl->maxBytesPerXfer) / 
  580.     pScsiPhysDev->blockSize;
  581.     else
  582. numbSecs = dataToXfer / pScsiPhysDev->blockSize;
  583.     
  584.     /* write the sectors */
  585.     
  586.     xferStatus = scsiSectorWrite (pScsiBlkDev,sectorNum,numbSecs,
  587.   xferBuf);
  588.     
  589.     if (xferStatus == OK)
  590. {
  591. /* 
  592.  * increment the sector no, buffer pointers & update the
  593.  * bytes left to be transferred
  594.  */
  595. sectorNum += numbSecs;
  596. xferBuf += (numbSecs * pScsiPhysDev->blockSize);
  597. dataToXfer -= (numbSecs * pScsiPhysDev->blockSize);
  598. }
  599.     else
  600. return (xferStatus);
  601.     }
  602. }
  603.     return (xferStatus);
  604.     }
  605. /*******************************************************************************
  606. *
  607. * scsiSectorWrite - write sector(s) to a SCSI block device
  608. *
  609. * This routine writes the specified physical sector(s) to a specified physical
  610. * device.
  611. *
  612. * RETURNS: OK, or ERROR if the sector cannot be written.
  613. */
  614. LOCAL STATUS scsiSectorWrite
  615.     (
  616.     SCSI_BLK_DEV *pScsiBlkDev,  /* ptr to SCSI block device info */
  617.     int sector,                 /* sector number to be read */
  618.     int numSecs,                /* total sectors to be read */
  619.     char *buffer                /* ptr to input data buffer */
  620.     )
  621.     {
  622.     SCSI_COMMAND writeCommand; /* SCSI command byte array */
  623.     SCSI_TRANSACTION scsiXaction; /* info on a SCSI transaction */
  624.     SCSI_PHYS_DEV *pScsiPhysDev = pScsiBlkDev->pScsiPhysDev;
  625.     int startSec = sector + pScsiBlkDev->blockOffset;
  626.     SCSI_DEBUG_MSG ("scsiWrtSecs:n", 0, 0, 0, 0, 0, 0);
  627.     if (startSec <= SCSI_BLOCK_ADDRESS_SIZE && numSecs <= 256)
  628.         {
  629.         /* build a 21 bit logical block address 'WRITE' command */
  630. if (scsiCmdBuild (writeCommand, &scsiXaction.cmdLength,
  631.   SCSI_OPCODE_WRITE, pScsiPhysDev->scsiDevLUN, FALSE,
  632.   startSec, (numSecs == 256 ? 0 : numSecs), (UINT8) 0)
  633.     == ERROR)
  634.     {
  635.     return (ERROR);
  636.     }
  637.         }
  638.     else
  639.         {
  640.         /* build a 32 bit logical block address 'WRITE_EXTENDED' command */
  641. if (scsiCmdBuild (writeCommand, &scsiXaction.cmdLength,
  642.   SCSI_OPCODE_WRITE_EXT, pScsiPhysDev->scsiDevLUN,
  643.   FALSE, startSec, numSecs, (UINT8) 0) == ERROR)
  644.     return (ERROR);
  645.         }
  646.     
  647.     scsiXaction.cmdAddress    = writeCommand;
  648.     scsiXaction.dataAddress   = (UINT8 *) buffer;
  649.     scsiXaction.dataDirection = O_WRONLY;
  650.     scsiXaction.dataLength    = numSecs * pScsiPhysDev->blockSize;
  651.     scsiXaction.addLengthByte = NONE;
  652.     scsiXaction.tagType       = SCSI_TAG_DEFAULT;
  653.     scsiXaction.priority      = SCSI_THREAD_TASK_PRIORITY;
  654.     
  655.     if (numSecs < 2000)
  656. scsiXaction.cmdTimeout = SCSI_TIMEOUT_5SEC +
  657.  (SCSI_TIMEOUT_1SEC * numSecs);
  658.     else
  659. scsiXaction.cmdTimeout = SCSI_TIMEOUT_FULL;
  660.     
  661.     return ((*pScsiPhysDev->pScsiCtrl->scsiTransact)
  662.     (pScsiPhysDev, &scsiXaction));
  663.     }
  664. /*******************************************************************************
  665. *
  666. * scsiStatusCheck - called by filesystems before doing open()'s or creat()'s
  667. *
  668. * This routine issues a TEST_UNIT_READY command to a SCSI device to detect a
  669. * medium change.
  670. *
  671. * RETURNS: OK or ERROR.
  672. */
  673. LOCAL STATUS scsiStatusCheck
  674.     (
  675.     BLK_DEV *pBlkDev                    /* ptr to a block dev */
  676.     )
  677.     {
  678.     SCSI_PHYS_DEV *pScsiPhysDev;        /* ptr to SCSI physical device */
  679.     SCSI_COMMAND testUnitRdyCommand;    /* SCSI command byte array */
  680.     SCSI_TRANSACTION scsiXaction;       /* info on a SCSI transaction */
  681.     pScsiPhysDev = ((SCSI_BLK_DEV *) pBlkDev)->pScsiPhysDev;
  682.     if (scsiCmdBuild (testUnitRdyCommand, &scsiXaction.cmdLength,
  683.         SCSI_OPCODE_TEST_UNIT_READY, pScsiPhysDev->scsiDevLUN, FALSE,
  684.         0, 0, (UINT8) 0) == ERROR)
  685.         {
  686.         return (ERROR);
  687.         }
  688.     scsiXaction.cmdAddress    = testUnitRdyCommand;
  689.     scsiXaction.dataAddress   = NULL;
  690.     scsiXaction.dataDirection = NONE;
  691.     scsiXaction.dataLength    = 0;
  692.     scsiXaction.addLengthByte = NONE;
  693.     scsiXaction.cmdTimeout    = SCSI_TIMEOUT_5SEC;
  694.     scsiXaction.tagType       = SCSI_TAG_DEFAULT;
  695.     scsiXaction.priority      = SCSI_THREAD_TASK_PRIORITY;
  696.     (*pScsiPhysDev->pScsiCtrl->scsiTransact) (pScsiPhysDev, &scsiXaction);
  697.     if ((pScsiPhysDev->lastSenseKey != SCSI_SENSE_KEY_NO_SENSE) &&
  698.         (pScsiPhysDev->lastSenseKey != SCSI_SENSE_KEY_UNIT_ATTENTION))
  699.         {
  700.         SCSI_DEBUG_MSG ("scsiStatusCheck returning ERROR, last Sense = %xn",
  701.                         pScsiPhysDev->lastSenseKey, 0, 0, 0, 0, 0);
  702.         return (ERROR);
  703.         }
  704.     else
  705.         return (OK);
  706.     }
  707. /*******************************************************************************
  708. *
  709. * scsiBlkDevIoctl - call scsiIoctl() with pointer to SCSI physical device
  710. *                   associated with the specified SCSI block device
  711. *
  712. * RETURNS: Status of scsiIoctl call.
  713. */
  714. LOCAL STATUS scsiBlkDevIoctl
  715.     (
  716.     SCSI_BLK_DEV *pScsiBlkDev,  /* ptr to SCSI block device info */
  717.     int function,               /* function code */
  718.     int arg                     /* argument to pass called function */
  719.     )
  720.     {
  721.     return (scsiIoctl (pScsiBlkDev->pScsiPhysDev, function, arg));
  722.     }
  723. /*******************************************************************************
  724. *
  725. * scsiStartStopUnit - issue a START_STOP_UNIT command to a SCSI device
  726. *
  727. * This routine issues a START_STOP_UNIT command to a specified SCSI device.
  728. *
  729. * RETURNS: OK, or ERROR if the command fails.
  730. */
  731. STATUS scsiStartStopUnit
  732.     (
  733.     SCSI_PHYS_DEV *pScsiPhysDev,  /* ptr to SCSI physical device */
  734.     BOOL start                    /* TRUE == start, FALSE == stop */
  735.     )
  736.     {
  737.     SCSI_COMMAND startStopCommand;      /* SCSI command byte array */
  738.     SCSI_TRANSACTION scsiXaction;       /* info on a SCSI transaction */
  739.     SCSI_DEBUG_MSG ("scsiStartStopUnit:n", 0, 0, 0, 0, 0, 0);
  740.     if (scsiCmdBuild (startStopCommand, &scsiXaction.cmdLength,
  741.         SCSI_OPCODE_START_STOP_UNIT, pScsiPhysDev->scsiDevLUN, FALSE,
  742.         0, 1, (UINT8) 0)
  743.         == ERROR)
  744.         {
  745.         return (ERROR);
  746.         }
  747.     scsiXaction.cmdAddress    = startStopCommand;
  748.     scsiXaction.dataDirection = O_RDONLY;
  749.     scsiXaction.dataLength    = 0;
  750.     scsiXaction.addLengthByte = NONE;
  751.     scsiXaction.cmdTimeout    = SCSI_TIMEOUT_5SEC;
  752.     scsiXaction.tagType       = SCSI_TAG_DEFAULT;
  753.     scsiXaction.priority      = SCSI_THREAD_TASK_PRIORITY;
  754.     return ((*pScsiPhysDev->pScsiCtrl->scsiTransact)
  755.             (pScsiPhysDev, &scsiXaction));
  756.     }
  757. /*******************************************************************************
  758. *
  759. * scsiReserve - issue a RESERVE command to a SCSI device
  760. *
  761. * This routine issues a RESERVE command to a specified SCSI device.
  762. *
  763. * RETURNS: OK, or ERROR if the command fails.
  764. */
  765. STATUS scsiReserve
  766.     (
  767.     SCSI_PHYS_DEV *pScsiPhysDev         /* ptr to SCSI physical device */
  768.     )
  769.     {
  770.     SCSI_COMMAND reserveCommand;        /* SCSI command byte array */
  771.     SCSI_TRANSACTION scsiXaction;       /* info on a SCSI transaction */
  772.     SCSI_DEBUG_MSG ("scsiReserve:n", 0, 0, 0, 0, 0, 0);
  773.     if (scsiCmdBuild (reserveCommand, &scsiXaction.cmdLength,
  774.         SCSI_OPCODE_RESERVE, pScsiPhysDev->scsiDevLUN, FALSE,
  775.         0, 0, (UINT8) 0)
  776.         == ERROR)
  777.         {
  778.         return (ERROR);
  779.         }
  780.     scsiXaction.cmdAddress    = reserveCommand;
  781.     scsiXaction.dataDirection = O_RDONLY;
  782.     scsiXaction.dataLength    = 0;
  783.     scsiXaction.addLengthByte = NONE;
  784.     scsiXaction.cmdTimeout    = SCSI_TIMEOUT_5SEC;
  785.     scsiXaction.tagType       = SCSI_TAG_DEFAULT;
  786.     scsiXaction.priority      = SCSI_THREAD_TASK_PRIORITY;
  787.     return ((*pScsiPhysDev->pScsiCtrl->scsiTransact)
  788.             (pScsiPhysDev, &scsiXaction));
  789.     }
  790. /*******************************************************************************
  791. *
  792. * scsiRelease - issue a RELEASE command to a SCSI device
  793. *
  794. * This routine issues a RELEASE command to a specified SCSI device.
  795. *
  796. * RETURNS: OK, or ERROR if the command fails.
  797. */
  798. STATUS scsiRelease
  799.     (
  800.     SCSI_PHYS_DEV *pScsiPhysDev         /* ptr to SCSI physical device */
  801.     )
  802.     {
  803.     SCSI_COMMAND releaseCommand;        /* SCSI command byte array */
  804.     SCSI_TRANSACTION scsiXaction;       /* info on a SCSI transaction */
  805.     SCSI_DEBUG_MSG ("scsiRelease:n", 0, 0, 0, 0, 0, 0);
  806.     if (scsiCmdBuild (releaseCommand, &scsiXaction.cmdLength,
  807.         SCSI_OPCODE_RELEASE, pScsiPhysDev->scsiDevLUN, FALSE,
  808.         0, 0, (UINT8) 0)
  809.         == ERROR)
  810.         {
  811.         return (ERROR);
  812.         }
  813.     scsiXaction.cmdAddress    = releaseCommand;
  814.     scsiXaction.dataDirection = O_RDONLY;
  815.     scsiXaction.dataLength    = 0;
  816.     scsiXaction.addLengthByte = NONE;
  817.     scsiXaction.cmdTimeout    = SCSI_TIMEOUT_5SEC;
  818.     scsiXaction.tagType       = SCSI_TAG_DEFAULT;
  819.     scsiXaction.priority      = SCSI_THREAD_TASK_PRIORITY;
  820.     return ((*pScsiPhysDev->pScsiCtrl->scsiTransact)
  821.             (pScsiPhysDev, &scsiXaction));
  822.     }