SCO OpenServer
scsi_usercmd(D3osdi)
scsi_usercmd, scsi_usercmd_build, scsi_usercmd_fill --
process user-level requests issued with the SCSIUSERCMD and SCSIUSERCMD2 ioctls
Synopsis
   #include <sys/nbufdev.h>
   #include <sys/scsicmd.h>
   scsi_usercmd_build (req_p, cfg_p, scsicmd, devbuf)
   	REQ_IO		*req_p;
   	DEVCFG		*cfg_p;
   	struct scsicmd	*scsicmd;	/* supplied SCSI command */
   	struct ndevbuf	*db;		/* supplied devbuf       */
   
   scsi_usercmd_fill (req_p, cfg_p, scsicmd, devbuf)
   	REQ_IO		*req_p;
   	DEVCFG		*cfg_p;
   	struct scsicmd	*scsicmd;	/* supplied SCSI command */
   	struct ndevbuf	*db;		/* supplied devbuf       */
Description
The
scsi_usercmd( )
functions are used in SCSI peripheral drivers
to process user-level requests issued with the
SCSIUSERCMD and SCSIUSERCMD2 ioctls.
Note that no sense data information can be returned
with these functions.
This makes this interface unsuitable
for writing a "user-level" driver
for a new SCSI device.
The interface should be used only
for occasional device-specific commands
for which no sense data is needed.
Arguments
 req_p
- 
Pointer to a
scsi_io_req(D4osdi)
structure.
 cfg_p
- 
Pointer to a
scsi_dev_cfg(D4osdi)
structure.
 cfg_p
- 
Pointer to a scsicmd structure.
 db
- 
Pointer to an ndevbuf structure.
Return values
scsi_usercmd_build( )
and
scsi_usercmd_fill( )
return 0 on success.
On failure, they return -1
and sets u.u_errno to one of the following:
 EPERM
- 
Calling process is not superuser
(setuid root is required).
 EINVAL
- 
Invalid opcode or data length.
 EFAULT
- 
Invalid data pointer
or failure to transfer user data to CDB.
 ENOMEM
- 
Could not allocate enough contiguous memory
for the CDB.
Usage
This functionality is coded in
the SCSI peripheral driver's
ioctl(D2osdi)
routine.
The typical calling sequence is:
- 
Call
copyin(D3oddi)
to copy the SCSI command in from user space.
 
- 
Call
scsi_usercmd_build( )
to create a REQ_IO structure
and allocate the required memory for the
scsi_cdb(D4osdi)
structure that is passed in with the
ioctl( )
call.
 
- 
Call the
_entry(D2osdi)
entry point routine and pass the newly-created
REQ_IO structure to stage the command in the driver.
 
- 
Issue the
sleep(D3oddi)
function to wait for the command to be processed.
 
- 
Issue the
scsi_usercmd_fill( )
function to copy the requested data
from kernel buffers to user space.
 
- 
Call
copyout(D3oddi)
to copy the updated scsi_cdb structure
back out to user space.
The
scsi_usercmd( )
is only a stub that is provided
for backward compatibility.
It should not be called.
Context and synchronization
User
context
Hardware applicability
All
Version applicability
 scsi_usercmd
- 
osdi:
2, 3, 4, 5
 scsi_usercmd_build and scsi_usercmd_fill
- 
osdi:
3, 4, 5
Differences between versions
The
scsi_usercmd( )
function was supported on earlier releases
of SCO systems.
A stub is provided for backward compatibility,
but drivers that run on SCO OpenServer
should be written to use the
scsi_usercmd_build( )
and
scsi_usercmd_fill( )
functions instead.
scsi_usercmd( )
is a stub and always sets
u.u_errno to an appropriate value.
References
scsi_io_req(D4osdi),
scsi(HW) ,
``OSDI SCSI driver interface version for SCO OpenServer 5'' in HDK Technical Reference
Examples
The following example from a SCSI peripheral driver
for a hard disk illustrates how to use these functions
to code the SCSIUSERCMD case of the driver's
ioctl(D2osdi)
routine.
   	case SCSIUSERCMD:		/* do a disk-related scsi cmd */
   		s = lockb5(&mydk_p->cilock);	
   		while (!(req_p = mydk_getreqblk(unit)))	
   	    		sleep(&mydk_needreq[unit], PRIBIO);	
   		unlockb(&mydk_p->cilock, s);	
   		req_p->io_intr = mydkintr;
   		req_p->jq = unit;
   		if (mydk_p->info.do_tagged)
   			req_p->hacmd = SCSI_TAG_SIMPLE;
   		else
   			req_p->hacmd = 0;
   		
   		if ( copyin( addr, &scsicmd, sizeof(scsicmd) ) == -1 ) {
   			u.u_error = EFAULT;
   			mydk_freereq(req_p);
   			break;
   		}
   		if ( scsi_usercmd_build( req_p, cfg_p, &scsicmd, &scsi_db ) ){
   			mydk_freereq(req_p);
   			u.u_error = EFAULT;
   			break;
   		}
   		/*
   		 * now submit the command
   		 */
   		if ((*cfg_p->adapter_entry)(req_p) != 0) {
   			mydk_freereq(req_p);			
   			u.u_error = ENXIO;
   			break;
   		}
   		s = lockb5(&mydk_p->cilock);		
   		while( req_p->internal ) {
   			sleep( req_p, PRIBIO );
   		}
   		unlockb( &mydk_p->cilock, s );
   		
   		if ( req_p->host_sts || req_p->target_sts ) {
   			u.u_error = EIO;	
   		}
   		/*
   		 * copy any resulting data back to the user
   		 */
   		if ( scsi_usercmd_fill( req_p, cfg_p, &scsicmd, &scsi_db ) ) {
   			mydk_freereq(req_p);
   			u.u_error = EFAULT;
   			break;
   		}
   		if ( copyout( &scsicmd, addr, sizeof(scsicmd) ) == -1 ) {
   			u.u_error = EFAULT;
   			mydk_freereq(req_p);
   			break;
   		}
   		mydk_freereq(req_p);
   		break;
19 June 2005
© 2005 The SCO Group, Inc.  All rights reserved.
OpenServer 5 HDK - June 2005