[sane-devel] RFC: proposal for an improved sanei_scsi library

abel deuring a.deuring@satzbau-gmbh.de
Sat, 07 Dec 2002 23:29:20 +0100


This is a multi-part message in MIME format.
--------------010608090107060104040506
Content-Type: text/plain; charset=us-ascii; format=flowed
Content-Transfer-Encoding: 7bit


Some time ago, I made some remarks on this list about things I don't 
like in the sanei_scsi interface: 
http://www.mostang.com/pipermail/sane-devel/2002-January/001463.html
Here is a proposal for a modified interface. The main points are:

- sanei_scsi_max_request_size is no longer available. Global variables 
often cause a mess ;) For Linux, the limit of SCSI data depends on the 
the adapter driver. Most drivers ISA adapters probably allow only <64 
kB, while PCI adapters don't have this limit. To avoid unexpected 
crashes, the current version of sanei_scsi.c limits the buffer size to a 
value supported by all loaded SCSI drivers.

- sanei2_scsi_open gets the new parameters *buffersize and *timeout, to 
set the maximum length for SCSI data and to set the timeout value for 
SCSI commands on a per-device basis.

- the sense handler callback is no longer available. I think that the 
sense handler is not really necessary, because the only thing done by 
sanei2_scsi_req_wait / sanei2_scsi_cmd after calling the sense handler 
is some internal cleanup.

Instead, the sense buffer and the device status byte are passed to the 
caller by sanei_scsi_req_wait / sanei_scsi_cmd.

- sanei2_scsi_cmd and sanei2_scsi_req_enter no longer accept CDB and 
write data in the same array. This was really messy; most backends 
contain memcpy calls in order to collect the data for the single array.

- sanei2_scsi_req_flush_all now only flushes the command for a single 
device file. This is perhaps not very important, since the frontends I 
know do not run more than one scan at a time, and it is not very likely 
that we'll ever have a frontend that tries to control 10 scanners 
simultaneously -- but a clean implementation would allow this ;) (And we 
are not that far away from such an implementation.)

An implementation of this interface based on the current version of 
sanei_scsi.c should not be too difficult, I think.

comments are welcome.

Abel

--------------010608090107060104040506
Content-Type: text/plain;
 name="sanei_scsi.h"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="sanei_scsi.h"

/** Find SCSI devices.
 *
 * Find each SCSI device that matches the pattern specified by the
 * arguments.  String arguments can be "omitted" by passing NULL,
 * integer arguments can be "omitted" by passing -1.
 *
 *   Example: vendor="HP" model=NULL, type=NULL, bus=3, id=-1, lun=-1 would
 *          attach all HP devices on SCSI bus 3.
 *
 * @param vendor
 * @param model
 * @param type
 * @param bus
 * @param channel
 * @param id
 * @param lun
 * @param attach callback invoked once for each device
 * @param dev real devicename (passed to attach callback)
 *
 */ 
extern void sanei2_scsi_find_devices (const char *vendor, const char *model,
				     const char *type,
				     int bus, int channel, int id, int lun,
				     SANE_Status (*attach) (const char *dev));


/** Open a SCSI device
 *
 * Opens a SCSI device by its device filename and returns a file descriptor.
 * The function tries to allocate a buffer of the size given by *buffersize.
 * If sanei2_scsi_open returns successfully, *buffersize contains the
 * available buffer size. This value may be both smaller or larger than the
 * value requested by the backend; it can even be zero. The backend must not
 * try to issue SCSI command with data blocks larger than given by the
 * value of *buffersize. The backend must decide, if it got enough buffer
 * memory to work.
 *
 * Note that the value of *buffersize may differ for different files and
 * even for consecutive calls for the same file.
 *
 * @param devicename name of the devicefile, e.g. "/dev/sg0"
 * @param fd file descriptor
 * @param is the timeout in seconds for SCSI commands
 * @param sense_arg pointer to data for the sense handler
 * @param buffersize size of the SCSI request buffer (in bytes)
 * 
 * @return 
 * - SANE_STATUS_GOOD - on success
 * - SANE_STATUS_ACCESS_DENIED - if the file couldn't be accessed due to
 *   permissions
 * - SANE_STATUS_NO_MEM - if malloc failed (not enough memory)
 * - SANE_STATUS_INVAL - if the filename was invalid or an unknown error occured
 *
 * @sa sanei2_scsi_open(), HAVE_SANEI_SCSI_OPEN_EXTENDED
 */
extern SANE_Status sanei2_scsi_open (
       const char * device_name, int * fd,
       int *timeout, int *buffersize);

/** Enqueue SCSI command
 *
 * One or more scsi commands can be enqueued by calling sanei2_scsi_req_enter().
 *
 * NOTE: Some systems may not support multiple outstanding commands.  On such
 * systems, sanei2_scsi_req_enter() may block.  In other words, it is not proper
 * to assume that enter() is a non-blocking routine.
 *
 * @param fd file descriptor
 * @param cmd pointer to SCSI command
 * @param cmd_size size of the command
 * @param buffer pointer to the buffer with data to be sent to / received from
          the scanner
 * @param buffer_size size of the data buffer
 * @param direction direction of the data transfer. Allowed values:
 *	  - SANE_SCSI_DXFER_NONE  no data transfer
 *        - SANE_SCSI_DXFER_TO_DEVICE data is sent to the device
 *	  - SANE_SCSI__DXFER_FROM_DEVICE data is received from the device
 * @param idp pointer to a void* that uniquely identifies the entered request
 * @return
 * - SANE_STATUS_GOOD - on success
 * - SANE_STATUS_IO_ERROR - if an error was received from the SCSI driver
 * - SANE_STATUS_NO_MEM - if malloc failed (not enough memory)
 * - SANE_STATUS_INVAL - if a locking or an unknown error occured
 * - SANE_STATUS_DEVICE_BUSY  - the SCSI command could not be issued; try
 *                       again later
 * @sa sanei2_scsi_req_enter()
 */
extern SANE_Status sanei2_scsi_req_enter (int fd,
					 const void * cmd, size_t cmd_size,
					 const void * buffer, size_t buffer_size,
					 int direction, void **idp);

/** Wait for SCSI command
 *
 * Wait for the completion of the SCSI command with id ID.  
 *
 * @param id id used in sanei2_scsi_req_enter()
 * @param sb pointer to a SANE_Byte array, where the SCSI sense data may be
 *           stored. The caller must allocate the necessary memory.
 *	     The parameter may be NULL.
 * @param sblen the length of the sense buffer allocated by the caller.
 *           On return, *sblen contains the number of bytes copied to the
 *	     sense buffer
 * @param scsi_status the status returned by the device. 
 *           xxx what about the situation, that the command has not been
 *           issued, or other situations, where no status information
 *           is available? Can this situation be detected for all supported
 *           OSes? If that is possible, we should add another parameter which
 *	     signals "SCSI status available"
 *             
 *
 * @return
 * - SANE_STATUS_GOOD - on success
 * - SANE_STATUS_DEVICE_BUSY - if the device is busy (try again later)
 * - SANE_STATUS_IO_ERROR - if an error was received from the SCSI driver
*/
extern SANE_Status sanei2_scsi_req_wait (void *id, SANE_Byte *sb, size_t *sblen,
                                        SANE_Byte *scsi_status);

/** Send SCSI command
 *
 * This is a convenience function that is equivalent to a pair of
 * sanei2_scsi_req_enter()/sanei2_scsi_req_wait() calls.
 *
 * @param fd file descriptor
 * @param cmd pointer to SCSI command
 * @param cmd_size size of the command
 * @param buffer pointer to the buffer with data to be sent to / received from
          the scanner
 * @param buffer_size size of the data buffer
 * @param direction direction of the data transfer. Allowed value:
 *	  - SANE_SCSI_DXFER_NONE  no data transfer
 *        - SANE_SCSI_DXFER_TO_DEVICE data is sent to the device
 *	  - SANE_SCSI__DXFER_FROM_DEVICE data is received from the device
 * @param sb pointer to a SANE_Byte array, where the SCSI sense data may be
 *           stored. The caller must allocate the necessary memory.
 *	     The parameter may be NULL.
 * @param sblen the length of the sense buffer allocated by the caller.
 *           On return, *sblen contains the number of bytes copied to the
 *	     sense buffer
 * @param scsi_status the status returned by the device. 
 *
 * @return
 * - SANE_STATUS_GOOD - on success
 * - SANE_STATUS_IO_ERROR - if an error was received from the SCSI driver
 * - SANE_STATUS_NO_MEM - if malloc failed (not enough memory)
 * - SANE_STATUS_INVAL - if a locking or an unknown error occured
 * - SANE_STATUS_DEVICE_BUSY  - the SCSI command could not be issued; try
 *                       again later
 * @sa sanei2_scsi_cmd2(), sanei2_scsi_req_enter(), sanei2_scsi_req_wait()
 */
extern SANE_Status sanei2_scsi_cmd2 (int fd,
				   const void * cmd, size_t cmd_size,
				   const void * buffer, size_t buffer_size,
				   int direction, SANE_Byte *sb, size_t *sblen,
				   SANE_Byte *scsi_status);

/** Flush queue for handle
 *
 * Flush all SCSI commands pending for one handle
 *
 * @param fd file descriptor
 *
 */
extern void sanei2_scsi_req_flush_all (int fd);

/** Close a SCSI device
 *
 * @param fd file descriptor
 *
 */
extern void sanei2_scsi_close (int fd);

--------------010608090107060104040506--