[Return to Library] [Contents] [Previous Chapter] [Next Section] [Next Chapter] [Index] [Help]


12    SCSI/CAM Special I/O Interface

This chapter describes the SCSI/CAM special I/O interface. The S/CA software includes an interface developed to process special SCSI I/O control commands that the existing Digital SCSI subsystem uses and to aid in porting new or existing SCSI device drivers from other vendors to the S/CA.

Application programs issue I/O control commands by using the ioctl system call to send special SCSI I/O commands to a peripheral device. The term ``special'' refers to commands that are not usually issued to the device through the standard driver entry points. SCSI device drivers usually require the special I/O control commands in addition to the standard read and write system calls. With the SCSI/CAM special I/O interface, SCSI/CAM peripheral driver writers do not need detailed knowledge of either the system-specific or the CAM-specific structures and routines used to issue a SCSI command to the CAM I/O subsystem.


[Return to Library] [Contents] [Previous Chapter] [Next Section] [Next Chapter] [Index] [Help]


12.1    Application Program Access

Application programs access the SCSI/CAM special I/O interface by making requests to peripheral drivers that use the ioctl system call. This system call is processed by system kernel support routines that invoke the device driver's I/O control command entry point in the character device switch table, which is defined in the /usr/sys/io/common/conf.c file. The device driver's I/O control routine accesses the special I/O interface by using either the supplied SCSI/CAM peripheral common routine, ccmn_DoSpecialCmd, or a driver-specific routine. Figure 12-1 shows the flow of application program requests through the operating system to the SCSI/CAM special I/O interface and the CAM I/O subsystem.

Figure 12-1: Application Program Flow Through the SCSI/CAM Special I/O Interface


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


12.2    Device Driver Access

SCSI/CAM peripheral device drivers access the SCSI/CAM special I/O interface by using either the supplied SCSI/CAM peripheral common routine, ccmn_SysSpecialCmd, or a driver-specific routine. Figure 12-2 shows the flow of system requests from device drivers through the SCSI/CAM special I/O interface and the CAM I/O subsystem.

Figure 12-2: Device Driver Flow Through the SCSI/CAM Special I/O Interface


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


12.3    SCSI/CAM Special Command Tables

The SCSI/CAM special I/O interface includes default command tables that provide backwards compatibility with existing SCSI I/O control commands. The following predefined SCSI/CAM special command tables are included:

The interface also allows commands to be added to the existing command tables and new command tables to be added. The SCSI/CAM special I/O interface includes routines that manipulate the tables so programmers can write device drivers to easily add and remove command tables.

The command table header structure, SPECIAL_HEADER, provides a bit mask of device types that can be used with a command table. The Special Command Header structure is defined as follows:

/*
 * Special Command Header structure:
 */

typedef struct special_header { struct special_header *sph_flink; /* Forward link to next table */ struct special_header *sph_blink; /* Backward link to prev table */ struct special_cmd *sph_cmd_table; /* Pointer to command table */ U32 sph_device_type; /* The device types supported */ U32 sph_table_flags; /* Flags to control cmd lookup */ caddr_t sph_table_name; /* Name of this command table */ } SPECIAL_HEADER;


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


12.3.1    The sph_flink and sph_blink Members

The sph_flink and sph_blink members are table-linkage members that allow command tables to be dynamically added or removed from the list of tables searched by the SCSI/CAM special I/O interface when processing commands.


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


12.3.2    The sph_cmd_table Member

The sph_cmd_table member specifies a pointer to the Special Command Entry structure.


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


12.3.3    The sph_device_type Member

The sph_device_type member specifies the device types supported by this SCSI/CAM special command table.


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


12.3.4    The sph_table_flags Member

The sph_table_flags member specifies flags to control command lookup. The SPH_SUB_COMMAND bit indicates that the command table contains subcommands.


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


12.3.5    The sph_table_name Member

The sph_table_name member specifies the name of this SCSI/CAM special command table.


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


12.4    SCSI/CAM Special Command Table Entries

Each SCSI/CAM special command table contains multiple entries. Each entry provides enough information to process the command associated with that entry. The command tables can be dynamically added, but the entries within the command tables are not dynamic. Each command table's entries are statically defined so that individual entries cannot be appended to the table. The Special Command Entry structure structure is defined as follows:

/*
 * Special Command Entry structure:
 */
typedef struct special_cmd {
        u_int   spc_ioctl_cmd;        /* The I/O control command code */
        u_int   spc_sub_command;      /* The I/O control sub-command */
        u_char  spc_cmd_flags;        /* The special command flags */
        u_char  spc_cmd_code;         /* The special command code */
        u_short                 : 16; /* Unused ... align next field */
        U32     spc_device_type;      /* The device types supported */
        U32     spc_cmd_parameter;    /* Command parameter (if any) */
        U32     spc_cam_flags;        /* The CAM flags field for CCB */
        U32     spc_file_flags;       /* File control flags (fcntl) */
        int     spc_data_length;      /* Kernel data buffer length */
        int     spc_timeout;          /* Timeout for this command */
        int     (*spc_docmd)();       /* Function to do the command */
        int     (*spc_mkcdb)();       /* Function to make SCSI CDB */
        int     (*spc_setup)();       /* Setup parameters routine */
        caddr_t spc_cdbp;             /* Pointer to prototype CDB */
        caddr_t spc_cmdp;             /* Pointer to the command name */
} SPECIAL_CMD;


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


12.4.1    The spc_ioctl_cmd and spc_sub_command Members

The spc_ioctl_cmd and spc_sub_command members contain the SCSI I/O control command code and subcommand used to locate the appropriate table entry. The subcommand is checked only if flags are set that indicate a subcommand exists.


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


12.4.2    The spc_cmd_flags Member

The spc_cmd_flags member contains flags to control the action of the SCSI/CAM special I/O interface routines. The flag definitions are described in the following table:
Flag Name Description
SPC_SUSER Restricted to superuser.
SPC_COPYIN User buffer to copy from.
SPC_COPYOUT User buffer to copy to.
SPC_NOINTR Do not allow sleep interrupts.
SPC_DATA_IN Data direction is from device.
SPC_DATA_OUT Data direction is to device.
SPC_DATA_NONE No data movement for command.
SPC_SUB_COMMAND Entry contains subcommand.
SPC_INOUT Copy in and out.
SPC_DATA_INOUT Copy data in and out.


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


12.4.3    The spc_command_code Member

The spc_command_code member contains the special SCSI opcode used to execute this command. This member is used during the creation of the CDB.


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


12.4.4    The spc_device_type Member

The spc_device_type member defines the specific device types with which this command is used. For example, direct-access and read-only direct-access devices share many of the same commands. Therefore, rather than duplicating command table entries, both device types can use the same command table. The values that are valid for this member are those defined in the Inquiry data device type member of the inquiry_info structure, which is defined in the /usr/sys/include/io/cam/scsi_all.h file.


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


12.4.5    The spc_cmd_parameter Member

The spc_cmd_parameter member is used to define any special parameters that the command uses. For example, the SCSI START CDB command, which is defined in the /usr/sys/include/io/cam/scsi_direct.h file, is used for stopping, starting, and ejecting a CDROM caddy. The parameter member can be defined as the subcommand code so a common routine can be used to create the CDB.


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


12.4.6    The spc_cam_flags Member

The spc_cam_flags member contains the CAM flags necessary for processing the command. The CAM flags are defined in the file /usr/sys/include/io/cam/cam.h.


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


12.4.7    The spc_file_flags Member

The spc_file_flags member contains the file access bits required for accessing the command. For example, the command can be restricted to device files opened for read and write access. The file flags are defined in the file /usr/sys/include/sys/file.h.


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


12.4.8    The spc_data_length Member

The spc_data_length member describes the length of the buffer to hold additional kernel data that is required to process the command. Usually this member is set to 0 (zero) because the data buffer lengths are normally decoded from the I/O command code or taken from a member in the I/O parameter buffer.


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


12.4.9    The spc_timeout Member

The spc_timeout member defines the default timeout for this command. This value is used for the SCSI I/O CCB timeout member, unless it is overridden by the timeout member in the Special I/O Argument structure.


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


12.4.10    The spc_docmd Member

The spc_docmd member specifies the routine to invoke to execute the command. A routine is required by I/O commands that need special servicing. For example, if the I/O command does not return all the data read by the SCSI command, then a routine is needed to handle this special servicing.


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


12.4.11    The spc_mkcdb Member

The spc_mkcdb member specifies the routine that is invoked to create the CDB for the command. A routine is not necessary for simple commands, such as TEST UNIT READY. However, any command that requires additional members to be set up in the CDB prior to issuing the SCSI command must define this routine.


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


12.4.12    The spc_setup Member

The spc_setup member is required by any command that has special setup requirements. For example, commands that pass a user buffer and length as part of the I/O parameters buffer structure must have a setup routine to copy these members to the Special I/O Argument structure. This applies to all previously defined commands, but does not apply to commands implemented using the new SCSI_SPECIAL I/O control command code.


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


12.4.13    The spc_cdbp Member

The spc_cdbp member specifies a pointer to the prototype CDB. This member is used by commands that can be implemented using a prototype CDB. A prototype CDB is a SCSI command that can be implemented using a statically defined SCSI CDB. Fields within the CDB do not change. Usually, simple SCSI commands, such as SCSI_START_UNIT, can be implemented with a prototype CDB so that the make CDB routine is not required.


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


12.4.14    The spc_cmdp Member

The spc_cmdp member points to a string that describes the name of the command. This string is used during error reporting and during debugging.


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


12.4.15    Sample SCSI/CAM Special Command Table

The example that follows shows a sample SCSI/CAM special command table with one entry defined:

#include "<cdrom.h"
#include "<mtio.h"
#include "<rzdisk.h"

#include <cam.h> #include <cam_special.h> #include <dec_cam.h> #include <scsi_all.h> #include <scsi_direct.h> #include <scsi_rodirect.h> #include <scsi_sequential.h> #include <scsi_special.h>

extern int scmn_MakeFormatUnit(), scmn_SetupFormatUnit();

/* * Command Header for Direct-Access Command Table: */ struct special_header cam_DirectCmdsHdr = { (struct special_header *) 0, /* sph_flink */ (struct special_header *) 0, /* sph_blink */ cam_DirectCmds, /* sph_cmd_table */ (BITMASK(ALL_DTYPE_DIRECT) | BITMASK(ALL_DTYPE_RODIRECT)), /* sph_device_type */ 0, /* sph_table_flags */ "Direct Access Commands" /* sph_table_name */ };

/********************************************************************** * * * Special Direct Access Command Table * * * **********************************************************************/ struct special_cmd cam_DirectCmds[] = { { SCSI_FORMAT_UNIT, /* spc_ioctl_cmd */ 0, /* spc_sub_command */ (SPC_COPYIN | SPC_DATA_OUT), /* spc_cmd_flags */ DIR_FORMAT_OP, /* spc_cmd_code */ BITMASK(ALL_DTYPE_DIRECT), /* spc_device_type */ 0, /* spc_cmd_parameter */ CAM_DIR_OUT, /* spc_cam_flags */ FWRITE, /* spc_file_flags */ -1, /* spc_data_length */ (120 * ONE_MINUTE), /* spc_timeout */ (int (*)()) 0, /* spc_docmd */ scmn_MakeFormatUnit, /* spc_mkcdb */ scmn_SetupFormatUnit, /* spc_setup */ (caddr_t) 0, /* spc_cdbp */ "format unit" /* spc_cmdp */ }, . . . { END_OF_CMD_TABLE } /* End of cam_DirectCmds[] Table. */ };

/* * Define Special Commands Header & Table for Initialization Routine. */ struct special_header *cam_SpecialCmds = &cam_SpecialCmdsHdr;

struct special_header *cam_SpecialHdrs[] = { &cam_GenericCmdsHdr, &cam_DirectCmdsHdr, &cam_AudioCmdsHdr, &cam_SequentialCmdsHdr, &cam_MtCmdsHdr, 0 };


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


12.5    SCSI/CAM Special I/O Argument Structure

A Special I/O Argument structure is passed to the SCSI/CAM special I/O interface to control processing of the I/O control command being executed. The structure members provide information to process a special command for different SCSI subsystems. The calling routine can override default settings and routines invoked by the SCSI/CAM special I/O interface. Table 12-1 shows the members that are mandatory for the calling routine to set up, the members that are optional, and the members that are used or filled in by the SCSI/CAM special I/O interface.

Table 12-1: SCSI/CAM Special I/O Argument Structure

Member Name Type Description
U32 sa_flags; M Flags to control command
dev_t sa_dev; M Device major/minor number
u_char sa_unit; U Device logical unit number
u_char sa_bus; M SCSI host adapter bus number
u_char sa_target; M SCSI device target number
u_char sa_lun; M SCSI logical unit number
u_int sa_ioctl_cmd; M The I/O control command
u_int sa_ioctl_scmd; C The subcommand, if any
caddr_t sa_ioctl_data; C The command data pointer
caddr_t sa_device_name; M Pointer to the device name
int sa_device_type; M The peripheral device type
int sa_iop_length; I Parameters' buffer length
caddr_t sa_iop_buffer; I Parameters' buffer address
int sa_file_flags; M The file control flags
u_char sa_sense_length; O Sense data buffer length
u_char sa_sense_resid; I Sense data residual count
caddr_t sa_sense_buffer; O Sense data buffer address
u_char sa_user_length; I User data buffer length
caddr_t sa_user_buffer; I User data buffer address
struct buf *sa_bp; O Kernel-only I/O request buffer
CCB_SCSIIO *sa_ccb; O CAM control block buffer
struct special_cmd *sa_spc; I Special command table entry
struct special_header *sa_sph; O Special command table header
U32 sa_cmd_parameter; I Command parameter, if any
int (*sa_error)(); O The error report routine
int (*sa_start)(); O The driver start routine
int sa_data_length; I Kernel data buffer length
caddr_t sa_data_buffer; I Kernel data buffer address
caddr_t sa_cdb_pointer; I Pointer to the CDB buffer
u_char sa_cdb_length; I Length of the CDB buffer
u_char sa_cmd_flags; I The special command flags
u_char sa_retry_count; I The current retry count
u_char sa_retry_limit; O Times to retry this command
int sa_timeout; O Timeout for this command
int sa_xfer_resid; I Transfer residual count
caddr_t sa_specific; O Driver-specific information

Legend: M = Mandatory. Must be set up by the caller.
  C = Command dependent. Depends on special command.
  O = Optional. Optionally overrides defaults.
  I = Interface. Used or filled in by SCSI/CAM special I/O interface.
  U = Unused. Not used by SCSI/CAM special I/O interface.

Several of the members marked as mandatory in Table 12-1 are set up initially by the routine that allocates the Special I/O Argument structure. The following members are initialized by the allocation routine: sa_bus, sa_target, sa_lun, sa_unit (same as target), sa_retry_limit (set to 30), and sa_start (set to the xpt_action routine).

Fields that are identified as optional in Table 12-1 can be defined by the caller to override some of the defaults that the SCSI/CAM special I/O interface uses. The following table describes these defaults:
Member Name Default
sa_sense_length Set to DEC_AUTO_SENSE_SIZE, which is defined in /usr/sys/include/io/cam/dec_cam.h.
sa_sense_buffer Sense buffer in SCSI/CAM Peripheral Device Driver Working Set structure.
sa_bp Allocated as needed for data movement commands.
sa_ccb Allocated by the CAM xpt_ccb_alloc routine.
sa_error() Special interface error report routine.
sa_start() Uses the CAM xpt_action routine.
sa_timeout Uses the timeout value from the SCSI/CAM special command table entry.
sa_specific Is not set up or used by SCSI/CAM special I/O interface.


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


12.5.1    The sa_flags Member

The sa_flags member is used to control the actions of the SCSI/CAM special I/O interface. The calling routine can set the low-order 5 bits of this member. All other bits in this member are reserved. The following table shows the control flags that the calling routine can set:
Flag Name Description
SA_NO_ERROR_RECOVERY Do not perform error recovery.
SA_NO_ERROR_LOGGING Do not log error messages.
SA_NO_SLEEP_INTR Do not allow sleep interrupts.
SA_NO_SIMQ_THAW Leave SIM queue frozen on errors.
SA_NO_WAIT_FOR_IO Do not wait for I/O to complete.


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


12.5.2    The sa_dev Member

The sa_dev member contains the device major/minor number pair passed into the device driver routines. It is used to fill in the bp_dev member of the system I/O request member.


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


12.5.3    The sa_unit, sa_bus, sa_target, and sa_lun Members

The sa_unit, sa_bus, sa_target, and sa_lun members are used to address the SCSI device to which the command is being sent. The sa_unit member is not used, but has been included for device drivers that implement logical device mapping.


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


12.5.4    The sa_ioctl_cmd Member

The sa_ioctl_cmd member contains the I/O control command to be processed. This command usually maps directly to a SCSI I/O command, but that is not necessary. For example, the Digital-specific SCSI_GET_SENSE command returns the sense data from the last failing command. A REQUEST SENSE command is not issued to the device, because autosense is assumed to have been enabled on the failing command, and the sense data is part of the common Peripheral Device structure.


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


12.5.5    The sa_ioctl_scmd Member

The sa_ioctl_scmd member specifies the subcommand (if any). This member must be filled in for special commands implemented with a subcommand code. For example, magnetic tape I/O control commands have both an I/O control command code and a subroutine command code.


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


12.5.6    The sa_ioctl_data Member

The sa_ioctl_data member specifies that an I/O parameters buffer is required if the I/O control command transfers data to and from the kernel. If the request comes from an application program, this buffer is normally passed into the driver ioctl routine.


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


12.5.7    The sa_device_name Member

The sa_device_name member contains a pointer to the device name string that is used when reporting device errors.


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


12.5.8    The sa_device_type Member

The sa_device_type member contains the device type member from the Inquiry data. This member controls the SCSI/CAM special command tables and the entries within each command table that are searched for the SCSI/CAM special I/O command being issued.


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


12.5.9    The sa_iop_length and sa_iop_buffer Members

The sa_iop_length member specifies the parameter's buffer length. The sa_iop_buffer member specifies the parameter's buffer address. The SCSI/CAM special I/O interface uses these members internally when processing a command. If I/O would normally be performed directly to the I/O parameters buffer because no other buffer was set up, then a kernel buffer is allocated and set up in these members.


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


12.5.10    The sa_file_flags Member

The sa_file_flags member contains the file flags passed into the device driver routines. The flags describe access control bits associated with the device. The file access flags are defined in the /usr/sys/include/io/cam/fcntl.h file.


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


12.5.11    The sa_sense_length and sa_sense_buffer Members

The sa_sense_length member specifies the sense data buffer length. The sa_sense_buffer member specifies the sense data buffer address. These members set up the sense buffer and expected sense data length that autosense uses when device errors occur. If these members are not set up by the calling routine, then the SCSI/CAM special I/O interface uses the sense buffer allocated in the SCSI/CAM Peripheral Device Driver Working Set structure that is pointed to by the SCSI I/O CCB.


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


12.5.12    The sa_user_length and sa_user_buffer Members

The sa_user_length member specifies the user's data buffer length. The sa_user_buffer member specifies the user's data buffer address. These members are set up by command setup routines to describe the user buffer and user data length required by a command. Requests from application programs that pass a user buffer and length in the I/O parameter buffers require a setup routine to copy this information into those members . The SCSI/CAM special I/O interface checks access and locking on this address range and sets up the address and length in the SCSI I/O CCB for the command.


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


12.5.13    The sa_bp Member

The sa_bp member contains a pointer to a system I/O request buffer for commands that perform data movement directly to user address space. A system buffer is not required if a kernel data buffer is used for I/O. If the calling routine does not pass a previously allocated request buffer in this member, and the SCSI/CAM special I/O interface determines that the I/O requires one based on the I/O buffer address, then a request buffer is allocated and deallocated automatically by the SCSI/CAM special I/O interface.


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


12.5.14    The sa_ccb Member

The sa_ccb member contains a pointer to the SCSI I/O CCB for a command. If the calling routine does not specify a SCSI I/O CCB in this member, then the SCSI/CAM special I/O interface automatically allocates and deallocates a SCSI I/O CCB for the command.


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


12.5.15    The special_cmd Member

The special_cmd member specifies a special command table entry. The SCSI/CAM special I/O interface uses this member internally to save the SPECIAL_CMD after a command is located.


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


12.5.16    The special_header Member

The special_header member specifies a special command table header. The calling routine can use this member to specify the SCSI/CAM special command table to search for the special command. This lets device drivers restrict the SCSI/CAM special command tables that are searched. If this member is not used, then all the SCSI/CAM special command tables in the list are searched for an entry that matches the special command being processed.


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


12.5.17    The sa_cmd_parameter Member

The sa_cmd_parameter member is used to store the command parameter, if any, from the command entry associated with this special command. Special support routines use this member when setting up members for a particular CDB.


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


12.5.18    The sa_error Member

The sa_error member contains the routine to be invoked when an error condition is detected. If not specified, a SCSI/CAM special I/O interface support routine handles the error condition. Otherwise, the routine is called as follows:

status = (*sap->sa_error)(ccb, sense);

This member can be specified for drivers requiring specialized error handling and for specific error logging. The SCSI/CAM special I/O interface's error logging uses the mprintf facility to report errors. Both sense key and CAM status members are logged.


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


12.5.19    The sa_start Member

The sa_start member contains the routine that starts processing the SCSI I/O CCB. If not specified, the CAM xpt_action routine is used. The routine is invoked as follows:

(void) ((sap->sa_start)(ccb);


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


12.5.20    The sa_data_length and sa_data_buffer Members

The sa_data_length member specifies the kernel data buffer length. The sa_data_buffer member specifies the kernel data buffer address. The SCSI/CAM special I/O interface uses these members internally to store the address and length of an additional kernel buffer required for a command. These members are usually initialized by the resulting value of the Special Command Entry structure member, spc_data_length, but SCSI/CAM special I/O command developers can use them if needed.


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


12.5.21    The sa_cdb_pointer Member

The sa_cdb_pointer member specifies a pointer to the CDB buffer. The SCSI/CAM special I/O interface uses this member internally to save a pointer to the CDB for this special command. This member may point to a prototype CDB; to a driver-allocated CDB buffer, if the CAM_CDB_POINTER flag is set in CCB header; or to the CDB buffer allocated within the SCSI I/O CCB. This member is set up with the CDB buffer address before the Special Command Header structure make CDB routine is invoked as follows:

status = (*spc->spc_mkcdb)(sap, cdbp);


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


12.5.22    The sa_cdb_length Member

The sa_cdb_length member specifies the size (in bytes) of the CDB required by a SCSI command. If the Special Command Header structure make CDB routine does not set up this member, then the SCSI Group Code is decoded to determine the length.


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


12.5.23    The sa_cmd_flags Member

The sa_cmd_flags member specifies the special command flags. This member is initialized from the Special Command Header structure spc_cmd_flags member so SCSI/CAM special I/O command support routines have easy and quick access to the flags.


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


12.5.24    The sa_retry_count Member

The sa_retry_count member contains the number of retrys that were required to successfully complete the request. It is filled in by the SCSI/CAM special I/O interface after processing the command.


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


12.5.25    The sa_retry_limit Member

The sa_retry_limit member contains the maximum number of times a command is retried. The only retries automatically handled by the SCSI/CAM special I/O interface are a sense key of Unit Attention or a SCSI bus status of Bus Busy or Reservation Conflict. All other error conditions must be handled by the calling routine.


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


12.5.26    The sa_timeout Member

The sa_timeout member contains the timeout value, in seconds, to use with the command being processed. The calling routine can specify this member. If it is not specified, the timeout value is taken from the Special Command Entry structure. This member is used to initialize the cam_timeout member of the SCSI I/O CCB before issuing the command.


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


12.5.27    The sa_xfer_resid Member

The sa_xfer_resid member contains the residual byte count of data movement commands. This member is copied from the cam_resid member of the SCSI I/O CCB before returning to the caller.


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


12.5.28    The sa_specific Member

The sa_specific member specifies driver-specfic information. This member is not set up or used by the SCSI/CAM special I/O interface. It provides a mechanism for device driver code to pass driver-dependent information to SCSI/CAM special I/O command support routines. The SCSI/CAM peripheral driver common routine ccmn_DoSpecialCmd passes the pointer to the Peripheral Device structure in this member.


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


12.5.29    Sample Function to Create a CDB

The following sample function shows how to use the SCSI/CAM special I/O interface to create a CDB for a SCSI FORMAT_UNIT command:

/*********************************************************************
 *                                                                   *
 * scmn_MakeFormatUnit() - Make Format Unit Command Descriptor Block.*
 *                                                                   *
 * Inputs:      sap = Special command argument block pointer.        *
 *              cdbp = Pointer to command descriptor block.          *
 *                                                                   *
 * Return Value:                                                     *
 *              Returns 0 for SUCCESS, or error code on failures.    *
 *                                                                   *
 *********************************************************************/
int
scmn_MakeFormatUnit (sap, cdbp)
register struct special_args *sap; [1]
register struct dir_format_cdb6 *cdbp; [2]
{
        register struct special_cmd *spc = sap->sa_spc; [3]
        register struct format_params *fp; [4]

 
fp = (struct format_params *) sap->sa_iop_buffer; cdbp->opcode = (u_char) spc->spc_cmd_code; if (fp->fp_defects == VENDOR_DEFECTS) { [5] cdbp->fmt_data = 1; cdbp->cmp_list = 1; } else if (fp->fp_defects == KNOWN_DEFECTS) { cdbp->fmt_data = 1; cdbp->cmp_list = 0; } else if (fp->fp_defects == NO_DEFECTS) { cdbp->fmt_data = 0; cdbp->cmp_list = 0; } cdbp->defect_list_fmt = fp->fp_format; [6] cdbp->vendor_specific = fp->fp_pattern; cdbp->interleave1 = 0; cdbp->interleave0 = fp->fp_interleave; return (SUCCESS); }

  1. Declares a register structure pointer to a Special I/O Argument structure that controls processing of the I/O command. The Special I/O Argument structure is defined in the /usr/sys/include/io/cam/cam_special.h file. [Return to example]

  2. Declares a register structure pointer to a structure that contains the format for a 6-byte CDB. The structure is defined in the /usr/sys/include/io/cam/scsi_direct.h file. [Return to example]

  3. Declares a register structure pointer to a Special I/O Control Commands structure that saves the SPECIAL_CMD after it is located in the sa_spc member of the Special I/O Argument structure. The Special I/O Control Commands structure is defined in the /usr/sys/include/io/cam/cam_special.h file. [Return to example]

  4. Declares a register structure pointer to a structure that contains the format parameters for a SCSI FORMAT UNIT command. The structure is defined in the /usr/sys/include/io/cam/rzdisk.h file. [Return to example]

  5. Tests the contents of the fp_defects member of the format parameters structure to determine the contents of the fmt_data and cmp_list members of the dir_format_cdb6 structure. [Return to example]

  6. Assigns the contents of the dir_format_cdb6 members to the equivalent members of the format_params structure. [Return to example]


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


12.5.30    Sample Function to Set Up Parameters

The following sample function shows how to use the SCSI/CAM special I/O interface to set up parameters for a SCSI FORMAT_UNIT command:

/*********************************************************************
 *                                                                   *
 * scmn_SetupFormatUnit() - Set up Format Unit Parameters.           *
 *                                                                   *
 * Inputs:      sap = Special command argument block pointer.        *
 *              data = The address of input/output arguments.        *
 *                                                                   *
 * Return Value:                                                     *
 *              Returns 0 for SUCCESS, or error code on failures.    *
 *                                                                   *
 *********************************************************************/
int
scmn_SetupFormatUnit (sap, data)
register struct special_args *sap; [1]
caddr_t data;
{
        struct form2_defect_list_header defect_header; [2]
        register struct form2_defect_list_header *ddh = &defect_header;
        register struct format_params *fp;  [3]

 
fp = (struct format_params *) data; sap->sa_user_buffer = (caddr_t) fp->fp_addr; [4]
 
/* * For diskettes, there are no defect lists. */ if ( ((sap->sa_user_length = fp->fp_length) == 0) && (fp->fp_defects == NO_DEFECTS) ) { sap->sa_cmd_flags &= ~(SPC_INOUT | SPC_DATA_INOUT); return (SUCCESS); }
 
#ifdef KERNEL /* * Ensure the defect list address is valid (user address). */ if ( ((sap->sa_flags & SA_SYSTEM_REQUEST) == 0) && !CAM_IS_KUSEG(fp->fp_addr) ) { return (EINVAL); }
 
/* * The format parameters structure is not set up with the length * of the defect lists as it should be. Therefore, we must copy * in the defect list header then calculate the defect list length. */ if (copyin ((caddr_t)fp->fp_addr, (caddr_t)ddh, sizeof(*ddh)) != 0) { return (EFAULT); #else (void) bcopy ((caddr_t)fp-> fp_addr, (caddr_t)ddh, sizeof(* ddh)) #endif } sap->sa_user_length = (int) ( (ddh->defect_len1 << 8) + ddh->defect_len0 + sizeof(*ddh) );
 
return (SUCCESS); }

  1. Declares a register structure pointer to a Special I/O Argument structure that controls processing of the I/O command. The Special I/O Argument structure is defined in the /usr/sys/include/io/cam/cam_special.h file. [Return to example]

  2. Declares a structure pointer to a structure that contains the format defect list header for a SCSI FORMAT UNIT command. The structure is defined in the /usr/sys/include/io/cam/rzdisk.h file. [Return to example]

  3. Declares a register structure pointer to a structure that contains the format parameters for a SCSI FORMAT UNIT command. The structure is defined in the /usr/sys/include/io/cam/rzdisk.h file. [Return to example]

  4. Assigns the user buffer data address to the defect list address. [Return to example]


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


12.6    SCSI/CAM Special I/O Control Command

A SCSI/CAM special I/O control command has been defined to provide a single standard method of implementing new SCSI/CAM special I/O commands. A subcommand member is used to determine the specific SCSI command being issued.

The SCSI/CAM special I/O control command structure can be used both in porting applications that use existing SCSI I/O control commands and when implementing new SCSI commands. Applications can be modified to use this structure to gain control over subsystem processing. For example, the SCSI/CAM special I/O command flags can be set to control error recovery and error reporting, sense data can be returned automatically by specifying a sense buffer address and length, and the command timeout and retry limit can be specified.

A member in the Special I/O Control Commands structure must be initialized to zero if a default value is desired. A nonzero member is used to override the default value.

The SCSI I/O control command and its associated structure and definitions are included in the file /usr/sys/include/io/cam/scsi_special.h. The scsi_special structure is defined as follows:

/*
 * Structure for Processing Special I/O Control Commands.
 */
struct scsi_special {
        U32     sp_flags;             /* The special command flags */
        dev_t   sp_dev;               /* Device major/minor number */
        u_char  sp_unit;              /* Device logical unit number */
        u_char  sp_bus;               /* SCSI host adapter bus number */
        u_char  sp_target;            /* SCSI device target number */
        u_char  sp_lun;               /* SCSI logical unit number */
        u_int   sp_sub_command;       /* The subcommand */
        U32     sp_cmd_parameter;     /* Command parameter (if any) */
        int     sp_iop_length;        /* Parameters buffer length */
        caddr_t sp_iop_buffer;        /* Parameters buffer address */
        u_char  sp_sense_length;      /* Sense data buffer length */
        u_char  sp_sense_resid;       /* Sense data residual count */
        caddr_t sp_sense_buffer;      /* Sense data buffer address */
        int     sp_user_length;       /* User data buffer length */
        caddr_t sp_user_buffer;       /* User data buffer address */
        int     sp_timeout;           /* Timeout for this command */
        u_char  sp_retry_count;       /* Retrys performed on command */
        u_char  sp_retry_limit;       /* Times to retry this command */
        int     sp_xfer_resid;        /* Transfer residual count */
};

This structure is used with the following SCSI special I/O control command:

#define SCSI_SPECIAL     _IOWR('p', 100, struct scsi_special)


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


12.6.1    The sp_flags Member

The sp_flags member controls the actions of the SCSI/CAM special I/O interface. The calling routine can set the low-order 3 bits. The other bits are reserved for use by SCSI/CAM peripheral drivers and the SCSI/CAM special I/O interface routines.
The bits that the calling routine can set are described as follows:
Flag Name Description
SA_NO_ERROR_RECOVERY Do not perform error recovery.
SA_NO_ERROR_LOGGING Do not log error messages.
SA_NO_SLEEP_INTR Do not allow sleep interrupts.


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


12.6.2    The sp_dev, sp_unit, sp_bus, sp_target, and sp_lun Members

The sp_dev member specifies the device major/minor number pair. The sp_unit member specifies the device logical unit number. The sp_bus member specifies the SCSI host adapter bus number. The sp_target member specifies the SCSI device target number. The sp_lun member specifies the SCSI logical unit number.

These members pass the device major/minor number pair and the device bus, target, LUN, and unit information to the SCSI/CAM special I/O interface when the I/O control command is not being issued to a SCSI/CAM peripheral device driver. These members provide the necessary hooks to allow software pseudodevice drivers, such as the User Agent driver, to send requests to the SCSI/CAM special I/O interface.


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


12.6.3    The sp_sub_command Member

The sp_sub_command member contains the SCSI/CAM special I/O subcommand code of the SCSI command to execute. This member can also be defined as an I/O control command to support backwards compatibility with preexisting SCSI I/O control commands. The SCSI/CAM special I/O interface detects an I/O control command, as opposed to a subcommand code, and coerces the arguments into the appropriate format for processing by the support routines associated with that I/O control command. The predefined subcommand codes are listed in the file /usr/sys/include/io/cam/scsi_special.h.


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


12.6.4    The sp_cmd_parameter Member

The sp_cmd_parameter member contains the command parameter, if any, for the SCSI special I/O command being issued. This parameter is specific to the special command processing routines and is not used directly by the SCSI/CAM special I/O interface routines.


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


12.6.5    The sp_iop_length and sp_iop_buffer Members

The sp_iop_length member contains the I/O parameters buffer length and the sp_iop_buffer member contains the I/O parameters buffer address. These members contain the I/O parameters buffer address and length for those commands that require additional parameters. Special command processing routines use these members to obtain and set up additional information prior to issuing the SCSI command. For example, the SCSI FORMAT_UNIT I/O control command passes a format_params structure that describes the format, length, pattern, and interleave information for the defect list. The scmn_MakeFormatUnit support routine uses this information when creating the CDB for this command.


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


12.6.6    The sp_sense_length, sp_sense_resid, and sp_sense_buffer Members

The sp_sense_length member contains the sense data buffer length. The sp_sense_resid member contains the sense data residual count. The sp_sense_buffer member contains the sense data buffer address.

These members contain the buffer address, length, and residual byte count for the sense data that is returned when device errors occur. If these members are specified, then the last sense data is saved in the Peripheral Device structure from which it can be obtained by the Digital-specific SCSI_GET_SENSE I/O control command.


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


12.6.7    The sp_user_length and sp_user_buffer Members

The sp_user_length member contains the user data buffer length and the sp_user_buffer contains the user data buffer address.

These members contain the user data buffer length and address for those commands that require them. The SCSI/CAM special I/O interface performs verification, locking, and unlocking of the user pages when processing the command.


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


12.6.8    The sp_timeout Member

The sp_timeout member specifies the timeout for this command. This member can be specified to override the default timeout (in seconds), which is usually taken from the Special Command Entry structure.


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


12.6.9    The sp_retry_count Member

The sp_retry_count member contains the number of retrys that were required to successfully complete the request. It is filled in by the SCSI/CAM special I/O interface after processing the command.


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


12.6.10    The sp_retry_limit Member

The sp_retry_limit member contains the maximum number of times a command is retried. The only retries automatically handled by the SCSI/CAM special I/O interface are a sense key of Unit Attention, or a SCSI bus status of Bus Busy or Reservation Conflict. All other error conditions must be handled by the calling routine.


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


12.6.11    The sp_xfer_resid Member

The sp_xfer_resid member is filled in with the transfer residual byte count when a command has completed. The SCSI/CAM special I/O interface copies the cam_resid member of the SCSI I/O CCB to this member before completing the request.


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


12.6.12    Sample Function to Create an I/O Control Command

The following sample function shows how to use the SCSI/CAM special I/O interface to create an I/O control command:

/***********************************************************************
 *                                                                     *
 * DoIoctl()    Do An I/O Control Command.                             *
 *                                                                     *
 * Description:                                                        *
 *      This routine issues the specified I/O control command to the   *
 *      file descriptor associated with the CD-ROM device driver.      *
 *                                                                     *
 * Inputs:      cmd = The I/O control command.                         *
 *              argp = The command argument to pass.                   *
 *              msgp = The message to display on errors.               *
 *                                                                     *
 * Return Value:                                                       *
 *              Returns 0 / -1 = SUCCESS / FAILURE.                    *
 *                                                                     *
 ***********************************************************************/
int
DoIoctl (cmd, argp, msgp)
int cmd;
caddr_t argp;
caddr_t msgp;
{
        int status;
#if defined(CAM)
        struct scsi_special special_cmd; [1]
        register struct scsi_special *sp = &special_cmd;
        register struct extended_sense *es; [2]

 
es = (struct extended_sense *)SenseBufPtr; bzero ((char *) sp, sizeof(*sp)); bzero ((char *) es, sizeof(*es)); sp->sp_sub_command = cmd; [3] sp->sp_sense_length = sizeof(*es); sp->sp_sense_buffer = (caddr_t) es; sp->sp_iop_length = ((cmd & ~(_IOC_INOUT|_IOC_VOID)) >> 16); sp->sp_iop_buffer = argp; if ((status = ioctl (CdrFd, SCSI_SPECIAL, sp)) < 0) { [4] perror (msgp); if (es->snskey) { cdbg_DumpSenseData (es); } } #else /* !defined(CAM) */ if ((status = ioctl (CdrFd, cmd, argp)) < 0) { perror (msgp); } #endif /* defined(CAM) */ return (status); }

  1. Declares a structure to process a special I/O control command. The scsi_special structure is defined in the /usr/sys/include/io/cam/scsi_special.h file. [Return to example]

  2. Declares a structure that defines the extended sense format for a REQUEST SENSE command. The extended_sense structure is defined in the /usr/sys/include/io/cam/rzdisk.h file. [Return to example]

  3. Assigns the program parameters to the special_cmd members. [Return to example]

  4. Is a standard I/O control call issued from application code. The SCSI_SPECIAL argument is defined in the /usr/sys/include/io/cam/scsi_special.h file. [Return to example]


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


12.7    Other Sample Code

This section contains other driver code samples that use the SCSI/CAM special I/O interface.


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


12.7.1    Sample Code to Open a Device

The following sample code shows how to use the SCSI/CAM special I/O interface to open a CDROM device from a device driver:

/*********************************************************************
 *                                                                   *
 * cdrom_open() - Driver Entry Point to Open CD-ROM Device.          *
 *                                                                   *
 * Inputs:      dev = The device major/minor number pair.            *
 *              flags = The file open flags (read/write/nodelay).    *
 *                                                                   *
 * Outputs:     Returns 0 for Success or error code on Failure.      *
 *                                                                   *
 *********************************************************************/
cdrom_open (dev, flags)
dev_t dev;
int flags;
{
        register PDRV_DEVICE *pd; [1]
        DIR_READ_CAP_DATA read_capacity; [2]
        DIR_READ_CAP_DATA *capacity = &read_capacity;
                .
                .
                .
        pd = GET_PDRV_PTR(dev); [3]
        status = cdrom_read_capacity (pd, capacity, flags);
                .
                .
                .
        return (status);
}
/**********************************************************************
 *                                                                    *
 * cdrom_read_capacity() - Obtain Disk Capacity Information.          *
 *                                                                    *
 * Inputs:      pd = Pointer to peripheral driver structure.          *
 *              capacity = Pointer to read capacity data buffer.      *
 *              flags = The file open flags.                          *
 *                                                                    *
 * Outputs:     Returns 0 for Success or error code on Failure.       *
 *                                                                    *
 **********************************************************************/
int
cdrom_read_capacity (pd, capacity, flags)
PDRV_DEVICE *pd;
DIR_READ_CAP_DATA *capacity;
int flags;
{
     int status;

 
PRINTD(DEV_BUS_ID(pd->pd_dev), DEV_TARGET(pd->pd_dev), DEV_LUN(pd->pd_dev), CAMD_CDROM, [4] ("[%d/%d/%d] cdrom_read_capacity: ENTRY - pd = 0x%x, \ capacity = 0x%x, flags = 0x%x\n", DEV_BUS_ID(pd->pd_dev), DEV_TARGET(pd->pd_dev), DEV_LUN(pd->pd_dev), pd, capacity, flags));
 
bzero ((char *)capacity, sizeof(*capacity));
 
status = ccmn_SysSpecialCmd (pd->pd_dev, SCSI_READ_CAPACITY, [5] (caddr_t) capacity, flags, (CCB_SCSIIO *) 0, SA_NO_ERROR_LOGGING);
 
PRINTD(DEV_BUS_ID(pd->pd_dev), DEV_TARGET(pd->pd_dev), DEV_LUN(pd->pd_dev), CAMD_CDROM, ("[%d/%d/%d] cdrom_read_capacity: EXIT - status = %d (%s)\n", DEV_BUS_ID(pd->pd_dev), DEV_TARGET(pd->pd_dev), DEV_LUN(pd->pd_dev), status, cdbg_SystemStatus(status))); [6]
 
return (status); }

  1. Assigns a register to a Peripheral Device structure pointer for the device to be opened. The Peripheral Device structure is defined in the /usr/sys/include/io/cam/pdrv.h file. [Return to example]

  2. Declares a structure to contain the capacity data returned for the device. The DIR_READ_CAP_DATA structure is defined in the /usr/sys/include/io/cam/scsi_direct.h file. [Return to example]

  3. Calls the GET_PDRV_PTR macro to return a pointer to the Peripheral Device structure for the device. The GET_PDRV_PTR macro is defined in the /usr/sys/include/io/cam/pdrv.h file. [Return to example]

  4. Uses the bus, target, and LUN information to be printed if the CAMD_CDROM flag is set. The CAMD_CDROM flag is defined in the /usr/sys/include/io/cam/cam_debug.h file. [Return to example]

  5. Calls the SCSI/CAM peripheral common routine ccmn_SysSpecialCmd to issue the SCSI I/O command, passing the major/minor device number pair for the device and the SCSI_READ_CAPACITY ioctl command, which is defined in the /usr/sys/include/io/cam/rzdisk.h file. It sets the SA_NO_ERROR_LOGGING flag, which is defined in the /usr/sys/include/io/cam/cam_special.h file for device drivers, and in the /usr/sys/include/io/cam/scsi_special.h file for application programs. [Return to example]

  6. Calls the cdbg_SystemStatus routine, passing the status as an argument. [Return to example]


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Chapter] [Index] [Help]


12.7.2    Sample Code to Create a Driver Entry Point

The following sample code shows how to use the SCSI/CAM special I/O interface to create a driver entry point for I/O control commands:

/*********************************************************************
 *                                                                   *
 * cdrom_ioctl() - Driver Entry Point for I/O Control Commands.      *
 *                                                                   *
 * Inputs:      dev = The device major/minor number pair.            *
 *              cmd = The I/O control command code.                  *
 *              data = The I/O parameters data buffer.               *
 *              flags = The file open flags (read/write/nodelay).    *
 *                                                                   *
 * Outputs:     Returns 0 for Success or error code on Failure.      *
 *                                                                   *
 *********************************************************************/
int
cdrom_ioctl (dev, cmd, data, flags)
dev_t dev;
register int cmd;
caddr_t data;
int flags;
{
        register PDRV_DEVICE *pd; [1]
        register DISK_SPECIFIC *cdisk;
        register DEV_DESC *dd;
        int status;

 
pd = GET_PDRV_PTR(dev); [2] dd = pd->pd_dev_desc; cdisk = (DISK_SPECIFIC *)pd->pd_specific;
 
switch (cmd) { . . /* Process Expected I/O Control Commands */ . . default: /* * Process Special I/O Control Commands. */ status = ccmn_DoSpecialCmd (dev, cmd, data, flags, [3] (CCB_SCSIIO *) 0, 0); break; } return (status); }

  1. Reserves registers for pointers to a Peripheral Device structure and a Device Descriptor structure, both of which are defined in the /usr/sys/include/io/cam/pdrv.h file, and to a DISK_SPECIFIC structure, which is defined in the /usr/sys/include/io/cam/cam_disk.h file. [Return to example]

  2. Calls the GET_PDRV_PTR macro to return a pointer to the Peripheral Device structure for the device. The GET_PDRV_PTR macro is defined in the /usr/sys/include/io/cam/pdrv.h [Return to example]

  3. Calls the SCSI/CAM peripheral common routine ccmn_DoSpecialCmd to issue the special I/O command. [Return to example]