The following topics cover design considerations of device and adapter device drivers:
FCP and iSCSI device drivers are responsible for the following actions:
Device drivers must support eight defined extended options in their open routine (that is, an openx subroutine). Additional extended options to the open are also allowed, but they must not conflict with predefined open options. The defined extended options are bit flags in the ext open parameter. These options can be specified singly or in combination with each other. The required ext options are defined in the /usr/include/sys/scsi.h header file and can have one of the following values:
The SC_FORCED_OPEN option causes the device driver to call the adapter device driver's transport Device Reset ioctl (SCIOLRESET) operation on the first open. This forces the device to release another initiator's reservation. After the SCIOLRESET command is completed, other commands are sent as in a normal open. If any of the commands fail due to a reservation conflict, the open registers the failure as an EBUSY status. This is also the result if a reservation conflict occurs during a normal open. The device driver should require the caller to have appropriate authority to request the SC_FORCED_OPEN option because this request can force a device to drop a reservation. If the caller attempts to initiate this system call without the proper authority, the device driver should return a value of -1, with the errno global variable set to a value of EPERM.
The SC_RETAIN_RESERVATION option causes the device driver not to issue the release command during the close of the device. This guarantees a calling program control of the device (using reservation) through open and close cycles. For shared devices (for example, disk or CD-ROM), the device driver must OR together this option for all opens to a given device. If any caller requests this option, the close routine does not issue the release even if other opens to the device do not set SC_RETAIN_RESERVATION. The device driver should require the caller to have appropriate authority to request the SC_RETAIN_RESERVATION option because this request can allow a program to monopolize a device (for example, if this is a nonshared device). If the caller attempts to initiate this system call without the proper authority, the device driver should return a value of -1, with the errno global variable set to a value of EPERM.
The SC_DIAGNOSTIC option causes the device driver to enter Diagnostic mode for the given device. This option directs the device driver to perform only minimal operations to open a logical path to the device. No commands should be sent to the device in the open or close routine when the device is in Diagnostic mode. One or more ioctl operations should be provided by the device driver to allow the caller to issue commands to the attached device for diagnostic purposes.
The SC_DIAGNOSTIC option gives the caller an exclusive open to the selected device. This option requires appropriate authority to run. If the caller attempts to execute this system call without the proper authority, the device driver should return a value of -1, with the errno global variable set to a value of EPERM. The SC_DIAGNOSTIC option may be executed only if the device is not already opened for normal operation. If this ioctl operation is attempted when the device is already opened, or if an openx call with the SC_DIAGNOSTIC option is already in progress, a return value of -1 should be passed, with the errno global variable set to a value of EACCES. Once successfully opened with the SC_DIAGNOSTIC flag, the device driver is placed in Diagnostic mode for the selected device.
The SC_NO_RESERVE option causes the device driver not to issue the reserve command during the opening of the device and not to issue the release command during the close of the device. This allows multiple hosts to share the device. The device driver should require the caller to have appropriate authority to request the SC_NO_RESERVE option, because this request allows other hosts to modify data on the device. If a caller does this kind of request then the caller must ensure data integrity between multiple hosts. If the caller attempts to execute this system call without the proper authority, the device driver should return a value of -1, with the errno global variable set to a value of EPERM.
The SC_SINGLE option causes the device driver to issue a normal open, but does not allow another caller to issue another open until the first caller has closed the device. This request gives the caller an exclusive open to the selected device. If this openx is attempted when the device is already open, a return value of -1 is passed, with the errno global variable set to a value of EBUSY.
Once successfully opened, the device is placed in Exclusive Access mode. If another caller tries to do any type of open, a return value of -1 is passed, with the errno global variable set to a value of EACCES.
The remaining options for the ext parameter are reserved for future requirements.
The following table shows how the various combinations of ext options should be handled in the device driver.
EXT OPTIONS
openx ext option |
Device Driver Action | |
---|---|---|
Open | Close | |
none | normal | normal |
diag | no commands | no commands |
diag + force | issue SCIOLRESET; otherwise, no commands issued | no commands |
diag + force + no_reserve | issue SCIOLRESET; otherwise, no commands issued | no commands |
diag + force + no_reserve + single | issue SCIOLRESET; otherwise, no commands issued. | no commands |
diag + force + retain | issue SCIOLRESET; otherwise, no commands issued | no commands |
diag + force + retain + no_reserve | issue SCIOLRESET; otherwise, no commands issued | no commands |
diag + force + retain + no_reserve + single | issue SCIOLRESET; otherwise, no commands issued | no commands |
diag + force + retain + single | issue SCIOLRESET; otherwise, no commands issued | no commands |
diag + force + single | issue SCIOLRESET; otherwise, no commands issued | no commands |
diag + no_reserve | no commands | no commands |
diag + retain | no commands | no commands |
diag + retain + no_reserve | no commands | no commands |
diag + retain + no_reserve + single | no commands | no commands |
diag + retain + single | no commands | no commands |
diag + single | no commands | no commands |
diag + single + no_reserve | no commands | no commands |
force | normal, except SCIOLRESET issued prior to any commands. | normal |
force + no_reserve | normal, except SCIOLRESET issued prior to any commands. No RESERVE command issued | normal except no RELEASE |
force + retain | normal, except SCIOLRESET issued prior to any commands | no RELEASE |
force + retain + no_reserve | normal except SCIOLRESET issued prior to any commands. No RESERVE command issued. | no RELEASE |
force + retain + no_reserve + single | normal, except SCIOLRESET issued prior to any commands. No RESERVE command issued. | no RELEASE |
force + retain + single | normal, except SCIOLRESET issued prior to any commands. | no RELEASE |
force + single | normal, except SCIOLRESET issued prior to any commands. | normal |
force + single + no_reserve | normal, except SCIOLRESET issued prior to any commands. No RESERVE command issued | no RELEASE |
no_reserve | no RESERVE | no RELEASE |
retain | normal | no RELEASE |
retain + no_reserve | no RESERVE | no RELEASE |
retain + single | normal | no RELEASE |
retain + single + no_reserve | normal, except no RESERVE command issued | no RELEASE |
single | normal | normal |
single + no_reserve | no RESERVE | no RELEASE |
When a device driver is preparing to close a device through the adapter device driver, it must ensure that all transactions are complete. When the adapter device driver receives a SCIOLSTOP ioctl operation and there are pending I/O requests, the ioctl operation does not return until all have completed. New requests received during this time are rejected from the adapter device driver's ddstrategy routine.
It is the responsibility of the device driver to process check conditions and other returned errors properly. The adapter device driver only passes commands without otherwise processing them and is not responsible for device error recovery.
Commands initiated by the device driver internally or as subordinates to a transaction from above must have data phase transfers of 256 bytes or less to prevent DMA/CPU memory conflicts. The length indicates to the adapter device driver that data phase transfers are to be handled internally in its address space. This is required to prevent DMA/CPU memory conflicts for the device driver. The adapter device driver specifically interprets a byte count of 256 or less as an indication that it can not perform data-phase DMA transfers directly to or from the destination buffer.
The actual DMA transfer goes to a dummy buffer inside the adapter device driver and then is block-copied to the destination buffer. Internal device driver operations that typically have small data-transfer phases are control-type commands, such as Mode select, Mode sense, and Request sense. However, this discussion applies to any command received by the adapter device driver that has a data-phase size of 256 bytes or less.
Internal commands with data phases larger than 256 bytes require the device driver to allocate specifically the required memory on the process level. The memory pages containing this memory cannot be accessed in any way by the CPU (that is, the device driver) from the time the transaction is passed to the adapter device driver until the device driver receives the iodone call for the transaction.
The device drivers can have both character (raw) and block special files in the /dev directory. The adapter device driver has only character (raw) special files in the /dev directory and has only the ddconfig, ddopen, ddclose, dddump, and ddioctl entry points available to operating system programs. The ddread and ddwrite entry points are not implemented.
Internally, the devsw table has entry points for the ddconfig, ddopen, ddclose, dddump, ddioctl, and ddstrat routines. The device drivers pass their commands to the adapter device driver by calling the adapter device driver ddstrat routine. (This routine is unavailable to other operating system programs due to the lack of a block-device special file.)
Access to the adapter device driver's ddconfig, ddopen, ddclose, dddump, ddioctl, and ddstrat entry points by the device drivers is performed through the kernel services provided. These include such services as fp_opendev, fp_close, fp_ioctl, devdump, and devstrat.
A adapter device driver must have a dddump entry point if it is used to access a system dump device. A device driver must have a dddump entry point if it drives a dump device. Examples of dump devices are disks and tapes.
Note: Adapter-device-driver writers should be aware that system services providing interrupt and timer services are unavailable for use in the dump routine. Kernel DMA services are assumed to be available for use by the dump routine. The adapter device driver should be designed to ignore extra DUMPINIT and DUMPSTART commands to the dddump entry point.
The DUMPQUERY option should return a minimum transfer size of 0 bytes, and a maximum transfer size equal to the maximum transfer size supported by the adapter device driver.
Calls to the adapter device driver DUMPWRITE option should use the arg parameter as a pointer to the scsi_buf structure to be processed. Using this interface, a write command can be executed on a previously started (opened) target device. The uiop parameter is ignored by the adapter device driver during the DUMPWRITE command. Spanned, or consolidated, commands are not supported using the DUMPWRITE option. Gathered write commands are also not supported using the DUMPWRITE option. No queuing of scsi_buf structures is supported during dump processing because the dump routine runs essentially as a subroutine call from the caller's dump routine. Control is returned when the entire scsi_buf structure has been processed.
Successful completion of the selected operation is indicated by a 0 return value to the subroutine. Unsuccessful completion is indicated by a return code set to one of the following values for the errno global variable. The various scsi_buf status fields, including the b_error field, are not set by the adapter device driver at completion of the DUMPWRITE command. Error logging is, of necessity, not supported during the dump.