This chapter describes the generic data structures and routines provided by Digital for SCSI/CAM peripheral device driver writers. Device driver writers can use the generic data structures and routines as templates for SCSI/CAM peripheral device drivers to interface with the CAM subsystem to perform standard I/O operations. See Chapter 12 for a description of the SCSI/CAM special I/O interface, which processes special I/O control commands that are not issued to the device through the standard driver entry points.
The generic routines use the common SCSI/CAM peripheral device driver routines described in Chapter 3. Using the common and generic routines helps ensure that SCSI/CAM peripheral device drivers are consistent with the SCSI/CAM Architecture. See Chapter 11 if you plan to define your own SCSI/CAM peripheral device drivers. See Appendix C for the source to the generic driver.
The generic device driver routines use the common routines and data structures supplied by Digital. The following routines must be called with the Peripheral Device structure locked:
The writer of a generic SCSI/CAM peripheral device driver has two options for implementing ioctl commands within the driver:
If new ioctl commands are implemented, conflicts with future releases of the operating system may result.
See Chapter 12 for information about the SCSI/CAM special I/O interface to handle SCSI special I/O commands.
The writer of the device driver is responsible for all error handling within the driver and for notifying the user process of the error.
The kernel entry points for any device driver are defined for both character and block devices in the structures cdevsw and bdevsw defined in the /usr/sys/include/sys/conf.h file. The kernel entry points are implemented in the cdevsw and bdevsw switch tables in the /usr/sys/io/common/conf.c file. If the device driver does not implement a specific kernel entry point, then the corresponding entries in the cdevsw and bdevsw switch tables must be null.
This section describes the generic data structures programmers adapt when they write their own SCSI/CAM peripheral device drivers. The following data structures are described:
A SCSI/CAM peripheral device structure, CGEN_SPECIFIC, is defined for the device controlled by the driver. The CGEN_SPECIFIC structure is defined as follows:
typedef generic_specific struct { u_long gen_flags; /* flags - EOM, write locked */ u_long gen_state_flags;/* STATE - UNIT_ATTEN, RESET etc. */ u_long gen_resid; /* Last operation residual count */ }CGEN_SPECIFIC;
The gen_flags member is used to indicate certain conditions of the SCSI unit. The possible flags are:
Flag Name | Description |
CGEN_EOM | The unit is positioned at the end of media. |
CGEN_OFFLINE | The device is returning DEVICE NOT READY in response to a command. The media is either not loaded or is being loaded. |
CGEN_WRT_PROT | The unit is either write protected or is opened read only. |
CGEN_SOFTERR | A soft error has been reported by the SCSI unit. |
CGEN_HARDERR | A hard error has been reported by the SCSI unit. It can be reported either through an ioctl command or by marking the buf structure as EIO. |
The gen_state_flags member is used to indicate certain states of the driver and of the SCSI unit. The possible flags are:
Flag Name | Description |
CGEN_NOT_READY_STATE | The unit was opened with the FNDELAY flag and the unit had a failure during the open, but it was seen. |
CGEN_UNIT_ATTEN_STATE | A check condition occurred and the sense key was UNIT ATTENTION. This usually indicates that a media change has occurred, but it could indicate a power-up or reset. Either way, current settings are lost. |
CGEN_RESET_STATE | Indicates notification of a reset condition on the device or bus. |
CGEN_RESET_PENDING_STATE | A reset is pending. |
CGEN_OPENED_STATE | The unit is opened. |
The gen_resid member contains the residual byte count from the last operation.
The SCSI/CAM peripheral device structure CGEN_ACTION is passed to the generic driver's action routines to be filled in according to the success or failure of the command. The CGEN_ACTION structure is defined as follows:
typedef struct generic_action { CCB_SCSIIO *act_ccb; /* The CCB that is returned to caller */ long act_ret_error; /* Error code if any */ u_long act_fatal; /* Is this considered fatal? */ u_long act_ccb_status; /* The CCB status code */ u_long act_scsi_status; /* The SCSI error code */ u_long act_chkcond_error; /* The check condition error */ }CGEN_ACTION;
The act_ccb member is a pointer to the SCSI I/O CCB returned to the calling routine.
The act_ret_error contains the error code, if any, returned from the operation.
The act_fatal member indicates whether an error returned was fatal. The possible flags are:
Flag Name | Description |
ACT_FAILED | The action has failed. |
ACT_RESOURCE | There is a memory availability problem. |
ACT_PARAMETER | An invalid parameter was passed. |
ACT_RETRY_EXCEDED | The maximum retry count for the operation has been exceeded. |
The act_ccb_status member indicates the CAM generic category code for the CCB that was returned from the ccmn_ccb_status routine.
The act_scsi_status member indicates the SCSI status code if the CCB completed with an error status. The SCSI status codes are defined in the /usr/sys/include/io/cam/scsi_status.h file.
The act_chkcond_error member contains the check condition code returned from the cgen_ccb_chkcond routine, if the cam_scsi_status member of the SCSI I/O CCB is equal to SCSI_STAT_CHECK_CONDITION. The check condition codes are defined in the generic.h file shown in Appendix C.
The generic routines described in this section handle open, close, read, write, and other I/O requests from user processes. Table 4-1 lists the name of each routine and gives a short description of its function. The sections that follow contain a more detailed description of each routine. Appendix B lists the routines alphabetically and includes descriptions and syntax information in Digital UNIX reference-page format.
Routine | Summary Description |
cgen_open | Called by the kernel when a user process requests an open of the device. |
cgen_close | Closes the device. |
cgen_read | Handles synchronous read requests for user processes through the raw interface. |
cgen_write | Handles synchronous write requests for user processes through the raw interface. |
cgen_strategy | Handles all I/O requests for user processes through the block inerface and the raw interface via a call to physio. |
cgen_ioctl | Handles user process requests for specific actions other than read, write, open, or close for generic devices. |
The kernel calls the cgen_open routine when a user process requests an open of the device. The cgen_open routine calls the ccmn_open_unit routine, which manages the SMP_LOCKS, and if passed the exclusive use flag for SCSI devices, makes sure that no other process has opened the device. If the ccmn_open_unit routine returns success, the necessary data structures are allocated.
The cgen_open routine calls the ccmn_sasy_ccb_bld routine to register for asynchronous event notification for the device. The cgen_open routine then enters a for loop based on the power-up time specified in the Device Descriptor structure for the device. Within the loop, calls are made to the cgen_ready routine, which calls the ccmn_tur routine to issue a TEST UNIT READY command to the device.
The cgen_open routine calls the ccmn_rel_ccb routine to release the CCB. The cgen_open routine checks certain state flags for the device to decide whether to send the initial SCSI mode select pages to the device. Depending on the setting of the state flags CGEN_UNIT_ATTEN_STATE and CGEN_RESET_STATE, the cgen_open routine calls the cgen_open_sel routine for each mode select page to be sent to the device. The cgen_open_sel routine fills out the Generic Action structure, based on the completion status of the CCB for each mode select page it sends.
The cgen_close routine closes the device. The routine checks any device flags that are defined to see if action is required, such as rewind on close or release the unit. The cgen_close routine closes the device by calling the ccmn_close_unit routine.
The cgen_read routine handles synchronous read requests for user processes. It passes the user process requests to the cgen_strategy routine. The cgen_read routine calls the ccmn_get_bp routine to allocate a buf structure for the user process read request. When the I/O is complete, the cgen_read routine calls the ccmn_rel_bp routine to deallocate the buf structure.
The cgen_write routine handles synchronous write requests for user processes. The routine passes the user process requests to the cgen_strategy routine. The cgen_write routine calls the ccmn_get_bp routine to allocate a buf structure for the user process write request. When the I/O is complete, the cgen_write routine calls the ccmn_rel_bp routine to deallocate the buf structure.
The cgen_strategy routine handles all I/O requests for user processes. It performs specific checks, depending on whether the request is synchronous or asynchronous and on the SCSI device type. The cgen_strategy routine calls the ccmn_io_ccb_bld routine to obtain an initialized SCSI I/O CCB and to build either a read or a write command based on the information contained in the buf structure. The cgen_strategy routine then calls the ccmn_send_ccb to place the CCB on the active queue and to send it to the XPT layer.
The cgen_ioctl routine handles user process requests for specific actions other than read, write, open, or close for SCSI tape devices. The routine currently issues a DEVIOCGET ioctl command for the device. DEVIOCGET fills out the devget structure passed in, and then calls the cgen_mode_sns routine, which issues a SCSI_MODE_SENSE to the device to determine the device's state. The routine then calls the ccmn_rel_ccb routine to release the CCB. When the call to cgen_mode_sns is completed, the cgen_ioctl routine fills out the rest of the devget structure, based on information contained in the mode sense data.
The generic routines described in this section are examples that show one method of handling errors, events, and conditions. SCSI/CAM peripheral device driver writers must implement routines for handling errors, events, and conditions that are compatible with the design and the functionality of the specific device. Table 4-2 lists the name of each routine and gives a short description of its function. Appendix C lists the routines alphabetically and includes descriptions and syntax information in Digital UNIX reference-page format.
Routine | Summary Description |
cgen_ccb_chkcond | Decodes the autosense data for a device driver. |
cgen_done | The entry point for all nonread and nonwrite I/O callbacks. |
cgen_iodone | The entry point for all read and write I/O callbacks. |
cgen_async | Handles notification of asynchronous events. |
cgen_minphys | Compares the b_bcount member of the buf structure with the maximum transfer limit for the device. |
cgen_slave | Called at system boot to initialize the lower levels. |
cgen_attach | Called for each bus, target, and LUN after the cgen_slave routine returns SUCCESS. |
The cgen_ccb_chkcond routine decodes the autosense data for a device driver and returns the appropriate status to the calling routine. The routine is called when a SCSI I/O CCB is returned with a CAM status of CAM_REQ_CMP_ERR (request completed with error) and a SCSI status of SCSI_STAT_CHECK_CONDITION. The routine also sets the appropriate flags in the Generic-Specific structure.
The cgen_done routine is the entry point for all nonread and nonwrite I/O callbacks. The generic device driver uses two callback entry points, one for all nonuser I/O requests and one for all user I/O requests. The SCSI/CAM peripheral device driver writer can declare multiple callback routines for each type of command and can fill the CCB with the address of the appropriate callback routine.
This is a generic routine for all nonread and nonwrite SCSI I/O CCBs. The SCSI I/O CCB should not contain a pointer to a buf structure in the cam_req_map member of the structure. If it does, then a wake-up call is issued on the address of the CCB and the error is reported. If the SCSI I/O CCB does not contain a pointer to a buf structure in the cam_req_map member, then a wake-up call is issued on the address of the CCB and the CCB is removed from the active queues. No CCB completion status is checked because that is the responsibility of the routine that created the CCB and is waiting for completion status. When this routine is entered, context is on the interrupt stack and the driver cannot sleep while waiting for an event.
The cgen_iodone routine is the entry point for all read and write I/O callbacks. This is a generic routine for all read and write SCSI I/O CCBs. The SCSI I/O CCB should contain a pointer to a buf structure in the cam_req_map member of the structure. If it does not, then a wake-up call is issued on the address of the CCB and the error is reported. If the SCSI I/O CCB does contain a pointer to a buf structure in the cam_req_map member, as it should, then the completion status is decoded. Depending on the CCB's completion status, the correct fields within the buf structure are filled out.
The device's active queues may need to be aborted because of errors or because the device is a sequential access device and the transaction is an asynchronous request.
The CCB is removed from the active queues by a call to the ccmn_rem_ccb routine and is released back to the free CCB pool by a call to the ccmn_rel_ccb routine. When the cgen_iodone routine is entered, context is on the interrupt stack and the driver cannot sleep while waiting for an event.
The cgen_async routine handles notification of asynchronous events. The routine is called when an asynchronous event notification(AEN), bus device reset (BDR), or bus reset (BR) occurs. The routine sets the CGEN_RESET_STATE flag and clears the CGEN_RESET_PEND_STATE flag for BDRs and bus resets. The routine sets the CGEN_UNIT_ATTEN_STATE flag for AENs.
The cgen_minphys routine compares the b_bcount member of the buf structure with the maximum transfer limit for the device. The routine compares the b_bcount field in the buf structure with the maximum transfer limit for the device in the Device Descriptor structure. The count is adjusted if it is greater than the limit.
The cgen_slave routine is called at system boot to initialize the lower levels. The routine also checks the bounds for the unit number to ensure it is within the allowed range and sets the device-configured bit for the device at the specified bus, target, and LUN.
The cgen_attach routine is called for each bus, target, and LUN after the cgen_slave routine returns SUCCESS. The routine calls the ccmn_open_unit routine, passing the bus, target, and LUN information.
The cgen_attach routine calls the ccmn_close_unit routine to close the device. If a device of the specified type is found, the device identification string is printed.
The generic routines described in this section are SCSI/CAM command support routines. Table 4-3 lists the name of each routine and gives a short description of its function. The sections that follow contain a more detailed description of each routine. Appendix C lists the routines alphabetically and includes descriptions and syntax information in Digital UNIX reference-page format.
Routine | Summary Description |
cgen_ready | Issues a TEST UNIT READY command to the unit defined. |
cgen_open_sel | Issues a SCSI_MODE_SELECT command to the SCSI device. |
cgen_mode_sns | Issues a SCSI_MODE_SENSE command to the unit defined. |
The cgen_ready routine issues a TEST UNIT READY command to the unit defined. The routine calls the ccmn_tur routine to issue the TEST UNIT READY command and sleeps while waiting for command status.
The cgen_open_sel routine issues a SCSI_MODE_SELECT command to the SCSI device. The mode select data sent to the device is based on the data contained in the Mode Select Table structure for the device, if one is defined. The CGEN_ACTION structure is filled in for the calling routine, based on the completion status of the CCB.
The cgen_open_sel routine calls the ccmn_mode_select routine to create a SCSI I/O CCB and to send it to the XPT for processing.
The cgen_mode_sns routine issues a SCSI_MODE_SENSE command to the unit defined. The CGEN_ACTION structure is filled in for the calling routine, based on the completion status of the CCB.