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

VxWorks

开发平台:

C/C++

  1. /* scsiLib.c - Small Computer System Interface (SCSI) library */
  2. /* Copyright 1989-1995 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /*
  5. modification history
  6. --------------------
  7. 01h,09jul97,dgp  doc: correct fonts per SPR 7853
  8. 01g,29oct96,dgp  doc: editing for newly published SCSI libraries
  9. 01f,01may96,jds  doc tweaks
  10. 01e,13nov95,jds  minor documentation tweaks
  11. 01d,08nov95,jds  main description modification
  12. 01c,20sep95,jdi  doc tweaks.
  13. 01b,11feb95,jdi  doc: fixed style for global variable pSysScsiCtrl.
  14. 01a,24aug94,jds  Written. Interface and documentation remain the same. However,
  15.          routines moved to different SCSI1 or SCSI2 libraries.
  16. */
  17. /*
  18. DESCRIPTION
  19. The purpose of this library is to switch SCSI function calls (the common 
  20. SCSI-1 and SCSI-2 calls listed above) to either scsi1Lib or scsi2Lib, 
  21. depending upon the SCSI configuration in the Board Support Package (BSP).
  22. The normal usage is to configure SCSI-2. However, SCSI-1 is configured
  23. when device incompatibilities exist. VxWorks can be configured with 
  24. either SCSI-1 or SCSI-2, but not both SCSI-1 and SCSI-2 simultaneously.
  25. For more information about SCSI-1 functionality, refer to scsi1Lib. 
  26. For more information about SCSI-2, refer to scsi2Lib.
  27. INCLUDE FILES
  28. scsiLib.h, scsi1Lib.h, scsi2Lib.h
  29. SEE ALSO: dosFsLib, rt11FsLib, rawFsLib, scsi1Lib, scsi2Lib,
  30. .pG "I/O System, Local File Systems"
  31. */
  32. #include "vxWorks.h"
  33. #include "ioLib.h"
  34. #include "ctype.h"
  35. #include "stdlib.h"
  36. #include "errnoLib.h"
  37. #include "taskLib.h"
  38. #include "logLib.h"
  39. #include "string.h"
  40. #include "stdio.h"
  41. #include "sysLib.h"
  42. #include "scsiLib.h"
  43. /* globals */
  44. BOOL scsiErrors; /* enable SCSI error messages */
  45. BOOL scsiDebug; /* enable task level debug messages */
  46. BOOL scsiIntsDebug; /* enable int level debug messages */
  47. SCSI_FUNC_TBL * pScsiIfTbl;             /* pointer to scsiLib interface table */
  48.     /* select timeout to use when creating a SCSI_PHYS_DEV */
  49. UINT32 scsiSelectTimeout    = SCSI_DEF_SELECT_TIMEOUT;
  50. int blkDevListMutexOptions  = SEM_Q_PRIORITY |
  51.       SEM_INVERSION_SAFE |
  52.       SEM_DELETE_SAFE;
  53. int scsiCtrlMutexOptions    = SEM_Q_PRIORITY |
  54.       SEM_INVERSION_SAFE |
  55.       SEM_DELETE_SAFE;
  56. int scsiCtrlSemOptions      = SEM_Q_FIFO;
  57. int scsiPhysDevMutexOptions = SEM_Q_PRIORITY |
  58.       SEM_INVERSION_SAFE |
  59.       SEM_DELETE_SAFE;
  60. int scsiPhysDevSemOptions   = SEM_Q_FIFO;
  61. SCSI_CTRL * pSysScsiCtrl; /* ptr to default SCSI_CTRL struct */
  62. /******************************************************************************
  63. *
  64. * scsiCtrlInit - initialize generic fields of a SCSI_CTRL structure
  65. *
  66. * This routine should be called by the SCSI controller libraries' xxCtrlCreate
  67. * routines, which are responsible for initializing any fields not herein
  68. * initialized.  It is NOT intended to be called directly by a user.
  69. *
  70. * NOTE
  71. * As a matter of good practice, the SCSI_CTRL structure should be
  72. * calloc()'ed by the xxCtrlCreate() routine, so that all fields are
  73. * initially zero.  If this is done, some of the work of this routine will be
  74. * redundant.
  75. *
  76. * RETURNS: OK, or ERROR if a semaphore initialization fails.
  77. *
  78. * NOMANUAL
  79. */
  80. STATUS scsiCtrlInit
  81.     (
  82.     SCSI_CTRL *pScsiCtrl        /* ptr to SCSI_CTRL struct to initialize */
  83.     )
  84.     {
  85.     if (pScsiIfTbl->scsiCtrlInit != NULL)
  86. return ((STATUS) (pScsiIfTbl->scsiCtrlInit) (pScsiCtrl));
  87.     else
  88. return (ERROR);
  89.     }
  90. /******************************************************************************
  91. *
  92. * scsiPhysDevDelete - delete a SCSI physical-device structure
  93. *
  94. * This routine deletes a specified SCSI physical-device structure.
  95. *
  96. * RETURNS: OK, or ERROR if `pScsiPhysDev' is NULL or SCSI_BLK_DEVs have
  97. * been created on the device.
  98. */
  99. STATUS scsiPhysDevDelete
  100.     (
  101.     SCSI_PHYS_DEV *pScsiPhysDev    /* ptr to SCSI physical device info */
  102.     )
  103.     {
  104.     if (pScsiIfTbl->scsiPhysDevDelete != NULL)
  105. return ((STATUS) (pScsiIfTbl->scsiPhysDevDelete) (pScsiPhysDev));
  106.     else
  107. return (ERROR);
  108.     }
  109. /*******************************************************************************
  110. *
  111. * scsiPhysDevCreate - create a SCSI physical device structure
  112. *
  113. * This routine enables access to a SCSI device and must be the first routine
  114. * invoked. It must be called once for each physical device on the SCSI bus.
  115. *
  116. * If <reqSenseLength> is NULL (0), one or more REQUEST_SENSE
  117. * commands are issued to the device to determine the number of bytes of
  118. * sense data it typically returns.  Note that if the device returns variable
  119. * amounts of sense data depending on its state, you must consult the device
  120. * manual to determine the maximum amount of sense data that can be
  121. * returned.
  122. *
  123. * If <devType> is NONE (-1), an INQUIRY command is issued to
  124. * determine the device type; as an added benefit, it acquires the device's
  125. * make and model number.  The scsiShow() routine displays this information.
  126. * Common values of <devType> can be found in scsiLib.h or in the SCSI
  127. * specification.
  128. *
  129. * If <numBlocks> or <blockSize> are specified as NULL (0), a READ_CAPACITY
  130. * command is issued to determine those values.  This occurs
  131. * only for device types that support READ_CAPACITY.
  132. *
  133. * RETURNS: A pointer to the created SCSI_PHYS_DEV structure, or NULL if the
  134. * routine is unable to create the physical-device structure.
  135. */
  136. SCSI_PHYS_DEV * scsiPhysDevCreate
  137.     (
  138.     SCSI_CTRL * pScsiCtrl, /* ptr to SCSI controller info */
  139.     int  devBusId,         /* device's SCSI bus ID */
  140.     int  devLUN,           /* device's logical unit number */
  141.     int  reqSenseLength,   /* length of REQUEST SENSE data dev returns */
  142.     int  devType,          /* type of SCSI device */
  143.     BOOL removable,        /* whether medium is removable */
  144.     int  numBlocks,        /* number of blocks on device */
  145.     int  blockSize         /* size of a block in bytes */
  146.     )
  147.     {
  148.     if (pScsiIfTbl->scsiPhysDevCreate != NULL)
  149. return ((SCSI_PHYS_DEV *) (pScsiIfTbl->scsiPhysDevCreate) 
  150.         (pScsiCtrl, devBusId, devLUN, reqSenseLength, devType, 
  151.       removable, numBlocks, blockSize));
  152.     else
  153. return (NULL);
  154.     }
  155. /*******************************************************************************
  156. *
  157. * scsiPhysDevIdGet - return a pointer to a SCSI_PHYS_DEV structure
  158. *
  159. * This routine returns a pointer to the SCSI_PHYS_DEV structure of the SCSI
  160. * physical device located at a specified bus ID (<devBusId>) and logical
  161. * unit number (<devLUN>) and attached to a specified SCSI controller
  162. * (<pScsiCtrl>).
  163. *
  164. * RETURNS: A pointer to the specified SCSI_PHYS_DEV structure, or NULL if the
  165. * structure does not exist.
  166. */
  167. SCSI_PHYS_DEV * scsiPhysDevIdGet
  168.     (
  169.     SCSI_CTRL * pScsiCtrl,       /* ptr to SCSI controller info  */
  170.     int         devBusId,        /* device's SCSI bus ID         */
  171.     int         devLUN           /* device's logical unit number */
  172.     )
  173.     {
  174.     if (pScsiIfTbl->scsiPhysDevIdGet != NULL)
  175. return ((SCSI_PHYS_DEV *) (pScsiIfTbl->scsiPhysDevIdGet) 
  176. (pScsiCtrl, devBusId, devLUN));
  177.     else
  178. return (NULL);
  179.     }
  180. /*******************************************************************************
  181. *
  182. * scsiAutoConfig - configure all devices connected to a SCSI controller
  183. *
  184. * This routine cycles through all valid SCSI bus IDs and logical unit
  185. * numbers (LUNs), attempting a scsiPhysDevCreate() with default parameters
  186. * on each.  All devices which support the INQUIRY command are
  187. * configured.  The scsiShow() routine can be used to find the system table
  188. * of SCSI physical devices attached to a specified SCSI controller.  In
  189. * addition, scsiPhysDevIdGet() can be used programmatically to get a
  190. * pointer to the SCSI_PHYS_DEV structure associated with the device at a
  191. * specified SCSI bus ID and LUN.
  192. *
  193. * RETURNS: OK, or ERROR if <pScsiCtrl> and the global variable `pSysScsiCtrl'
  194. * are both NULL.
  195. */
  196. STATUS scsiAutoConfig
  197.     (
  198.     SCSI_CTRL *pScsiCtrl       /* ptr to SCSI controller info */
  199.     )
  200.     {
  201.     if (pScsiIfTbl->scsiAutoConfig != NULL)
  202. return ((STATUS) (pScsiIfTbl->scsiAutoConfig) (pScsiCtrl));
  203.     else
  204. return (ERROR);
  205.     }
  206. /*******************************************************************************
  207. *
  208. * scsiShow - list the physical devices attached to a SCSI controller
  209. *
  210. * This routine displays the SCSI bus ID, logical unit number (LUN), vendor ID,
  211. * product ID, firmware revision (rev.), device type, number of blocks,
  212. * block size in bytes, and a pointer to the associated SCSI_PHYS_DEV
  213. * structure for each physical SCSI device known to be attached to a specified
  214. * SCSI controller.
  215. *
  216. * NOTE:
  217. * If <pScsiCtrl> is NULL, the value of the global variable `pSysScsiCtrl'
  218. * is used, unless it is also NULL.
  219. *
  220. * RETURNS: OK, or ERROR if both <pScsiCtrl> and `pSysScsiCtrl' are NULL.
  221. */
  222. STATUS scsiShow
  223.     (
  224.     SCSI_CTRL *pScsiCtrl           /* ptr to SCSI controller info */
  225.     )
  226.     {
  227.     if (pScsiIfTbl->scsiShow != NULL)
  228. return ((STATUS) (pScsiIfTbl->scsiShow) (pScsiCtrl));
  229.     else
  230. return (ERROR);
  231.     }
  232. /*******************************************************************************
  233. *
  234. * scsiBlkDevCreate - define a logical partition on a SCSI block device
  235. *
  236. * This routine creates and initializes a BLK_DEV structure, which
  237. * describes a logical partition on a SCSI physical-block device.  A logical
  238. * partition is an array of contiguously addressed blocks; it can be completely
  239. * described by the number of blocks and the address of the first block in
  240. * the partition.  In normal configurations partitions do not overlap, although
  241. * such a condition is not an error.
  242. *
  243. * NOTE:
  244. * If <numBlocks> is 0, the rest of device is used.
  245. *
  246. * RETURNS: A pointer to the created BLK_DEV, or NULL if parameters exceed
  247. * physical device boundaries, if the physical device is not a block device, or
  248. * if memory is insufficient for the structures.
  249. */
  250. BLK_DEV * scsiBlkDevCreate
  251.     (
  252.     SCSI_PHYS_DEV * pScsiPhysDev,/* ptr to SCSI physical device info */
  253.     int             numBlocks,   /* number of blocks in block device */
  254.     int             blockOffset  /* address of first block in volume */
  255.     )
  256.     {
  257.     if (pScsiIfTbl->scsiBlkDevCreate != NULL)
  258. return ((BLK_DEV *) (pScsiIfTbl->scsiBlkDevCreate) (pScsiPhysDev, 
  259.                                               numBlocks, blockOffset));
  260.     else
  261. return (NULL);
  262.     }
  263. /*******************************************************************************
  264. *
  265. * scsiBlkDevInit - initialize fields in a SCSI logical partition
  266. *
  267. * This routine specifies the disk-geometry parameters required by certain
  268. * file systems (for example, dosFs).  It is called after a SCSI_BLK_DEV
  269. * structure is created with scsiBlkDevCreate(), but before calling a file system
  270. * initialization routine.  It is generally required only for removable-media
  271. * devices.
  272. *
  273. * RETURNS: N/A
  274. */
  275. void scsiBlkDevInit
  276.     (
  277.     SCSI_BLK_DEV * pScsiBlkDev, /* ptr to SCSI block dev. struct */
  278.     int            blksPerTrack,/* blocks per track */
  279.     int            nHeads       /* number of heads */
  280.     )
  281.     {
  282.     if (pScsiIfTbl->scsiBlkDevInit != NULL)
  283. (pScsiIfTbl->scsiBlkDevInit) (pScsiBlkDev, blksPerTrack, nHeads);
  284.     }
  285. /*******************************************************************************
  286. *
  287. * scsiBlkDevShow - show the BLK_DEV structures on a specified physical device
  288. *
  289. * This routine displays all of the BLK_DEV structures created on a specified
  290. * physical device.  This routine is called by scsiShow() but may also be
  291. * invoked directly, usually from the shell.
  292. *
  293. * RETURNS: N/A
  294. *
  295. * SEE ALSO: scsiShow()
  296. */
  297. void scsiBlkDevShow
  298.     (
  299.     SCSI_PHYS_DEV * pScsiPhysDev  /* ptr to SCSI physical device info */
  300.     )
  301.     {
  302.     if (pScsiIfTbl->scsiBlkDevShow != NULL)
  303.         (pScsiIfTbl->scsiBlkDevShow) (pScsiPhysDev);
  304.     }
  305. /*******************************************************************************
  306. *
  307. * scsiBusReset - pulse the reset signal on the SCSI bus
  308. *
  309. * This routine calls a controller-specific routine to reset a specified
  310. * controller's SCSI bus.  If no controller is specified (<pScsiCtrl> is 0),
  311. * the value in the global variable `pSysScsiCtrl' is used.
  312. *
  313. * RETURNS: OK, or ERROR if there is no controller or controller-specific
  314. * routine.
  315. */
  316. STATUS scsiBusReset
  317.     (
  318.     SCSI_CTRL * pScsiCtrl /* ptr to SCSI controller info */
  319.     )
  320.     {
  321.     if (pScsiIfTbl->scsiBusReset != NULL)
  322. return ((STATUS) (pScsiIfTbl->scsiBusReset) (pScsiCtrl));
  323.     else
  324. return (ERROR);
  325.     }
  326. /*******************************************************************************
  327. *
  328. * scsiPhaseNameGet - get the name of a specified SCSI phase
  329. *
  330. * This routine returns a pointer to a string which is the name of the SCSI
  331. * phase input as an integer.  It's primarily used to improve readability of
  332. * debugging messages.
  333. *
  334. * RETURNS: A pointer to a string naming the SCSI phase input
  335. *
  336. * NOMANUAL
  337. */
  338. char * scsiPhaseNameGet
  339.     (
  340.     int scsiPhase               /* phase whose name to look up */
  341.     )
  342.     {
  343.     if (pScsiIfTbl->scsiPhaseNameGet != NULL)
  344. return ((char *) (pScsiIfTbl->scsiPhaseNameGet) (scsiPhase));
  345.     else
  346. return (NULL);
  347.     }
  348. /*******************************************************************************
  349. *
  350. * scsiCmdBuild - fills in the fields of a SCSI command descriptor block
  351. *
  352. * Typically, this routine is not called directly by the user, but by other
  353. * routines in scsiLib.  It fills in fields of a SCSI-command descriptor block
  354. * based on the input parameters.  The field layouts vary based on the command
  355. * group, which is determined from the `opCode'.
  356. *
  357. * RETURNS: ERROR if vendor-unique command group or out-of-bounds parameter,
  358. * otherwise OK.
  359. *
  360. * NOMANUAL
  361. */
  362. STATUS scsiCmdBuild
  363.     (
  364.     SCSI_COMMAND scsiCmd,       /* command to be built */
  365.     int *        pCmdLength,    /* ptr to command length variable */
  366.     UINT8        opCode,        /* SCSI opCode for command */
  367.     int          LUN,           /* logical unit number for command */
  368.     BOOL         relAdrs,       /* whether to set relative address bit */
  369.     int          logBlockAdrs,  /* logical block address */
  370.     int          xferLength,    /* number of blocks or bytes to xfer */
  371.     UINT8        controlByte    /* control byte for command */
  372.     )
  373.     {
  374.     if (pScsiIfTbl->scsiCmdBuild != NULL)
  375. return ((STATUS) (pScsiIfTbl->scsiCmdBuild) (scsiCmd, pCmdLength, 
  376. opCode, LUN, relAdrs, logBlockAdrs, xferLength, controlByte));
  377.     else
  378. return (ERROR);
  379.     }
  380. /*******************************************************************************
  381. *
  382. * scsiTransact - obtain exclusive use of SCSI controller for a transaction
  383. *
  384. * This routine calls scsiPhaseSequence() to execute the command specified.
  385. * If there are physical path management errors, then this routine returns
  386. * ERROR.  If not, then the status returned from the command is checked.  If
  387. * it is "Check Condition", then a "Request Sense" CCS command is executed
  388. * and the sense key is examined.  An indication of the success of the
  389. * command is returned (OK or ERROR).
  390. *
  391. * RETURNS: OK, or ERROR if a path management error occurs
  392. * or the status or sense information indicates an error.
  393. *
  394. * NOMANUAL
  395. */
  396. STATUS scsiTransact
  397.     (
  398.     SCSI_PHYS_DEV *     pScsiPhysDev,        /* ptr to the target device    */
  399.     SCSI_TRANSACTION  * pScsiXaction      /* ptr to the transaction info */
  400.     )
  401.     {
  402.     if (pScsiIfTbl->scsiTransact != NULL)
  403. return ((STATUS) (pScsiIfTbl->scsiTransact) (pScsiPhysDev, 
  404. pScsiXaction));
  405.     else
  406. return (ERROR);
  407.     }
  408. /*******************************************************************************
  409. *
  410. * scsiIoctl - perform a device-specific I/O control function
  411. *
  412. * This routine performs a specified `ioctl' function using a specified SCSI 
  413. * block device.
  414. *
  415. * RETURNS: The status of the request, or ERROR if the request is unsupported.
  416. */
  417. STATUS scsiIoctl
  418.     (
  419.     SCSI_PHYS_DEV * pScsiPhysDev,/* ptr to SCSI block device info */
  420.     int             function,    /* function code */
  421.     int             arg          /* argument to pass called function */
  422.     )
  423.     {
  424.     if (pScsiIfTbl->scsiIoctl != NULL)
  425. return ((STATUS) (pScsiIfTbl->scsiIoctl) (pScsiPhysDev, function, arg));
  426.     else
  427. return (ERROR);
  428.     }
  429. /*******************************************************************************
  430. *
  431. * scsiFormatUnit - issue a FORMAT_UNIT command to a SCSI device
  432. *
  433. * This routine issues a FORMAT_UNIT command to a specified SCSI device.
  434. *
  435. * RETURNS: OK, or ERROR if the command fails.
  436. */
  437. STATUS scsiFormatUnit
  438.     (
  439.     SCSI_PHYS_DEV * pScsiPhysDev,  /* ptr to SCSI physical device */
  440.     BOOL            cmpDefectList, /* whether defect list is complete */
  441.     int             defListFormat, /* defect list format */
  442.     int             vendorUnique,  /* vendor unique byte */
  443.     int             interleave,    /* interleave factor */
  444.     char *          buffer,        /* ptr to input data buffer */
  445.     int             bufLength      /* length of buffer in bytes */
  446.     )
  447.     {
  448.     if (pScsiIfTbl->scsiFormatUnit != NULL)
  449. return ((STATUS) (pScsiIfTbl->scsiFormatUnit) (pScsiPhysDev, 
  450. cmpDefectList, defListFormat, vendorUnique, interleave, 
  451. buffer, bufLength));
  452.     else
  453. return (ERROR);
  454.     }
  455. /*******************************************************************************
  456. *
  457. * scsiModeSelect - issue a MODE_SELECT command to a SCSI device
  458. *
  459. * This routine issues a MODE_SELECT command to a specified SCSI device.
  460. *
  461. * RETURNS: OK, or ERROR if the command fails.
  462. */
  463. STATUS scsiModeSelect
  464.     (
  465.     SCSI_PHYS_DEV * pScsiPhysDev, /* ptr to SCSI physical device            */
  466.     int             pageFormat,   /* value of the page format bit (0-1)     */
  467.     int             saveParams,   /* value of the save parameters bit (0-1) */
  468.     char *          buffer,       /* ptr to output data buffer              */
  469.     int             bufLength     /* length of buffer in bytes              */
  470.     )
  471.     {
  472.     if (pScsiIfTbl->scsiModeSelect != NULL)
  473. return ((STATUS) (pScsiIfTbl->scsiModeSelect) (pScsiPhysDev, pageFormat,
  474.                                saveParams, buffer, bufLength));
  475.     else
  476. return (ERROR);
  477.     }
  478. /*******************************************************************************
  479. *
  480. * scsiModeSense - issue a MODE_SENSE command to a SCSI device
  481. *
  482. * This routine issues a MODE_SENSE command to a specified SCSI device.
  483. *
  484. * RETURNS: OK, or ERROR if the command fails.
  485. */
  486. STATUS scsiModeSense
  487.     (
  488.     SCSI_PHYS_DEV * pScsiPhysDev, /* ptr to SCSI physical device */
  489.     int             pageControl,  /* value of the page control field (0-3) */
  490.     int             pageCode,     /* value of the page code field (0-0x3f) */
  491.     char *          buffer,       /* ptr to input data buffer */
  492.     int             bufLength     /* length of buffer in bytes */
  493.     )
  494.     {
  495.     if (pScsiIfTbl->scsiModeSense != NULL)
  496. return ((STATUS) (pScsiIfTbl->scsiModeSense) (pScsiPhysDev, pageControl,
  497.                                pageCode, buffer, bufLength));
  498.     else
  499. return (ERROR);
  500.     }
  501. /*******************************************************************************
  502. *
  503. * scsiReadCapacity - issue a READ_CAPACITY command to a SCSI device
  504. *
  505. * This routine issues a READ_CAPACITY command to a specified SCSI device.
  506. *
  507. * RETURNS: OK, or ERROR if the command fails.
  508. */
  509. STATUS scsiReadCapacity
  510.     (
  511.     SCSI_PHYS_DEV * pScsiPhysDev, /* ptr to SCSI physical device */
  512.     int *           pLastLBA,   /* where to return last logical block address */
  513.     int *           pBlkLength    /* where to return block length */
  514.     )
  515.     {
  516.     if (pScsiIfTbl->scsiReadCapacity != NULL)
  517. return ((STATUS) (pScsiIfTbl->scsiReadCapacity) (pScsiPhysDev, pLastLBA,
  518.                                                    pBlkLength));
  519.     else
  520. return (ERROR);
  521.     }
  522. /*******************************************************************************
  523. *
  524. * scsiRdSecs - read sector(s) from a SCSI block device
  525. *
  526. * This routine reads the specified physical sector(s) from a specified
  527. * physical device.
  528. *
  529. * RETURNS: OK, or ERROR if the sector(s) cannot be read.
  530. */
  531. STATUS scsiRdSecs
  532.     (
  533.     SCSI_BLK_DEV * pScsiBlkDev,  /* ptr to SCSI block device info */
  534.     int             sector,       /* sector number to be read */
  535.     int             numSecs,      /* total sectors to be read */
  536.     char *          buffer        /* ptr to input data buffer */
  537.     )
  538.     {
  539.     if (pScsiIfTbl->scsiRdSecs != NULL)
  540. return ((STATUS) (pScsiIfTbl->scsiRdSecs) (pScsiBlkDev, sector, numSecs,
  541.                                                       buffer));
  542.     else
  543. return (ERROR);
  544.     }
  545. /*******************************************************************************
  546. *
  547. * scsiWrtSecs - write sector(s) to a SCSI block device
  548. *
  549. * This routine writes the specified physical sector(s) to a specified physical
  550. * device.
  551. *
  552. * RETURNS: OK, or ERROR if the sector(s) cannot be written.
  553. */
  554. STATUS scsiWrtSecs
  555.     (
  556.     SCSI_BLK_DEV * pScsiBlkDev,  /* ptr to SCSI block device info */
  557.     int             sector,       /* sector number to be written */
  558.     int             numSecs,      /* total sectors to be written */
  559.     char *          buffer        /* ptr to input data buffer */
  560.     )
  561.     {
  562.     if (pScsiIfTbl->scsiWrtSecs != NULL)
  563. return ((STATUS) (pScsiIfTbl->scsiWrtSecs) (pScsiBlkDev, sector, 
  564. numSecs, buffer));
  565.     else
  566. return (ERROR);
  567.     }
  568. /*******************************************************************************
  569. *
  570. * scsiTestUnitRdy - issue a TEST_UNIT_READY command to a SCSI device
  571. *
  572. * This routine issues a TEST_UNIT_READY command to a specified SCSI device.
  573. *
  574. * RETURNS: OK, or ERROR if the command fails.
  575. */
  576. STATUS scsiTestUnitRdy
  577.     (
  578.     SCSI_PHYS_DEV * pScsiPhysDev         /* ptr to SCSI physical device */
  579.     )
  580.     {
  581.     if (pScsiIfTbl->scsiTestUnitRdy != NULL)
  582. return ((STATUS) (pScsiIfTbl->scsiTestUnitRdy) (pScsiPhysDev));
  583.     else
  584. return (ERROR);
  585.     }
  586. /*******************************************************************************
  587. *
  588. * scsiInquiry - issue an INQUIRY command to a SCSI device
  589. *
  590. * This routine issues an INQUIRY command to a specified SCSI device.
  591. *
  592. * RETURNS: OK, or ERROR if the command fails.
  593. */
  594. STATUS scsiInquiry
  595.     (
  596.     SCSI_PHYS_DEV * pScsiPhysDev, /* ptr to SCSI physical device */
  597.     char *          buffer,       /* ptr to input data buffer */
  598.     int             bufLength     /* length of buffer in bytes */
  599.     )
  600.     {
  601.     if (pScsiIfTbl->scsiInquiry != NULL)
  602. return ((STATUS) (pScsiIfTbl->scsiInquiry) (pScsiPhysDev, buffer, 
  603. bufLength));
  604.     else
  605. return (ERROR);
  606.     }
  607. /*******************************************************************************
  608. *
  609. * scsiReqSense - issue a REQUEST_SENSE command to a SCSI device and read results
  610. *
  611. * This routine issues a REQUEST_SENSE command to a specified SCSI device and
  612. * reads the results.
  613. *
  614. * RETURNS: OK, or ERROR if the command fails.
  615. */
  616. STATUS scsiReqSense
  617.     (
  618.     SCSI_PHYS_DEV * pScsiPhysDev, /* ptr to SCSI physical device */
  619.     char *          buffer,       /* ptr to input data buffer */
  620.     int             bufLength     /* length of buffer in bytes */
  621.     )
  622.     {
  623.     if (pScsiIfTbl->scsiReqSense != NULL)
  624. return ((STATUS) (pScsiIfTbl->scsiReqSense) (pScsiPhysDev, buffer, 
  625.    bufLength));
  626.     else
  627. return (ERROR);
  628.     }