Issue 14
Contents
Features
- | Foreword
- | Tip of the day
- | A Bird's Nest
- | Snap Happy
- | The SCSIDRV programming interface
- | Sprite Editor
- | Atari UK
- | E-Jag Day 2k1
- | Put some Charm in your Chaos
- | Anodyne Competition results
Reviews
- | PhotoTip 3.10
- | AtarIRC and AtarICQ
News
The SCSIDRV programming interface Building SCSI (and IDE) support into your code by Roger Burrows When Atari designed its first 32-bit systems, it included a proprietary interface, ACSI, for connecting peripherals such as hard disk drives. ACSI is a stripped-down (and thus less expensive) version of the SCSI interface, but the much greater volume of SCSI peripherals together with the greater competition in this area made it cheaper to use an ACSI-to-SCSI convertor (usually known as a host adaptor) to connect off-the-shelf SCSI peripherals to Ataris. Later Atari systems, such as the TT030 and Falcon, included a SCSI interface as standard, and so SCSI devices have dominated the Atari peripheral market. But this is not without its downside. SCSI protocol has generally been complex, there was no built-in programming support for SCSI in TOS (unlike, for example, the Mac’s SCSI Manager), the instructions required for low-level access to the SCSI hardware differ between systems, and the possibility of running your code under MagiC Mac or MagiC PC adds yet another complexity. The use of ATAPI (IDE) interfaces on later systems (such as the Falcon and the Milan) has added yet more work for anyone wishing to support peripheral devices in their software. The SCSIDRV programming interface, however, offers a straightforward way to build SCSI and ATAPI capability into your code. In this article, I'll examine the SCSIDRV standard and discuss how to use it. The problem with SCSI/ATAPI The SCSI and ATAPI standards define a communications protocol and a command set and, fortunately for programmers wishing to support the most devices with the least work, the command sets are by-and-large exactly the same. However, the missing link for the Atari programmer is the interface to the SCSI/ATAPI buses. If you tackle the problem through low-level hardware programming, you must transmit the appropriate commands through one of multiple different buses. And of course, all programs that need to send commands directly to a SCSI or ATAPI peripheral must have the same capability, requiring duplication of efforts. A further issue is that certain actions on the bus (such as a reset) can affect the state of other devices, which can lead to interference between programs, each of which behaves as though it "owns" the bus. The SCSIDRV programming interface, proposed by Steffen Engel in 1994-5, defines a set of high-level functions for communicating with devices attached to a SCSI (or ATAPI) bus. It protects you from the pitfalls of hardware-level programming and provides a standard way of transmitting commands across a bus to a peripheral. The SCSIDRV programming interface The original SCSIDRV driver was written by Steffen Engel for the ST and TT030. This was extended and eventually incorporated into the CBHD disk driver (originally by Claus Brod, now maintained by Steffen Engel). It supports ACSI, SCSI, and ATAPI buses on the ST, TT030, and Falcon, as well as devices under MagiC Mac and MagiC PC. Another, independently-developed driver is built into HD-Driver (by Dr Uwe Seimet), starting in v7.00. This provides support for the ACSI, SCSI, and ATAPI buses on the ST, TT030, Falcon, and Milan (the Hades is not officially supported, but normally works just fine). SCSIDRV offers many advantages to the SCSI/ATAPI programmer. Because it is available on all Atari-compatible systems, it provides hardware and platform independence. Furthermore, SCSIDRV support is available for TOS, MagiC and MiNT operating systems. Best of all, SCSIDRV provides a high-level function set that's easy to use and can dramatically shorten your development time. SCSIDRV hides the inner workings of the bus protocol from the programmer. The SCSIDRV-compatible driver handles the details of arbitration, selection, and message passing, returning status codes and sense data when appropriate. You still need a basic knowledge of SCSI/ATAPI structures and protocol to use SCSIDRV effectively, but it can shorten your learning curve by making experimentation easy. Using SCSIDRV does have its shortcomings. For example, if the SCSIDRV driver does not support a particular device type, you will not be able to use it. How SCSIDRV works The SCSIDRV driver is either built into your hard disk driver (and therefore loaded during the boot process), or it is loaded as a separate program via the AUTO folder. At startup, the SCSIDRV driver installs a cookie ("SCSI") which points to a structure containing the version of the SCSIDRV specification that is supported, together with the entry addresses of the functions supported (see diagram 1). It then polls the system buses, looking for attached devices, and saves the information to internal tables. A device must be turned on before start-up in order for SCSIDRV to recognise it. To use a SCSIDRV function, you put the appropriate parameters on the stack and then issue a sub-routine call to the appropriate address, obtained from the SCSIDRV structure. Note that the entry points must be called from supervisor mode; since the driver is frequently used by other drivers (such as our own product, ExtenDOS Gold) which are already in supervisor mode, this is usually a benefit.
Offset | Contents
+0 | version
+2 | pointer to "In" routine
+6 | pointer to "Out" routine
+10 | pointer to "InquireSCSI" routine
+14 | pointer to "InquireBus" routine
+18 | pointer to "CheckDev" routine
+22 | pointer to "RescanBus" routine
+26 | pointer to "Open" routine
+30 | pointer to "Close" routine
+34 | pointer to "Error" routine
Diagram 1: structure pointed to by "SCSI" cookie.
Using SCSIDRV requires knowledge of the SCSI/ATAPI command set and capabilities for the device you wish to support. Keep in mind that SCSIDRV provides interface functions, not high-level SCSI functions. The SCSIDRV driver merely passes data through to the SCSI device without modifying or inspecting it. The basic SCSIDRV function set is small, but powerful. Some of the functions return information about the system and devices, while others actually communicate with SCSI/ATAPI devices. The base SCSIDRV specification defines the functions in table 1. The essential functions are In and Out; all other functions are essentially support functions. The In and Out functions send a SCSI CDB to the device, handle data transfer, and return messages and status codes. If the request results in a Check Condition status, SCSIDRV requests sense data from the device, making it available to the calling program.
Function name | Description
In | Perform SCSI input command
Out | Perform SCSI output command
InquireSCSI | Determine available buses in system
InquireBus | Determine available devices on a bus
CheckDev | Get information for a specific bus/device
RescanBus | Requests driver to rescan bus for available devices
Open | Get a device handle
Close | Release device handle
Error | Set/query error status for a device
Table 1: SCSIDRV basic functions.
For completeness, you should know that the SCSIDRV specification also defines a set of functions that are only used for "target handling" (see table 2). These allow the computer system to be used as a peripheral, for example by another computer on the same SCSI bus. We won’t cover these functions in this article.
Function name | Description
Install | Install target handler routine
Deinstall | De-install target handler routine
GetCmd | Get SCSI command from initiator
SendData | Send data to initiator
GetData | Get data from initiator
SendStatus | Send SCSI status to initiator
SendMsg | Send SCSI message to initiator
GetMsg | Get SCSI message from initiator
Table 2: SCSIDRV target-handling functions.
Listing 1 (SCSIDEMO.C) shows the use of the basic SCSIDRV functions to determine which devices are currently available via SCSIDRV. In order to find out details about each device, we issue the Inquiry command. This SCSI command is mandatory for all devices and is often used by driver programs to dynamically identify available devices. We’ll examine each routine in turn and see how the SCSIDRV functions are used. The routine init_scsi() locates the "SCSI" cookie and save its value, which is a pointer to the SCSIDRV structure, in the variable scsicall. The routine scan_busses() then manages the rest of the job. It uses the SCSIDRV function InquireSCSI to determine available busses. For those who are familiar with the GEMDOS Fsfirst and Fsnext functions, InquireSCSI behaves in a similar manner. You call it with the argument cInqFirst to obtain information about the first available bus, and then call it repeatedly with the argument cInqNext to retrieve information on the remaining buses (if any). The list_devices() routine displays information about all the devices on a specific bus. It uses the SCSIDRV function InquireBus to determine available devices, in the same way as init_scsi() uses InquireSCSI, using cInqFirst and cInqNext. For each device that exists, it gets a device handle via a SCSIDRV Open, and then calls scsi_inquiry() to print information about the device. The scsi_inquiry() function demonstrates the In function to get data from the device. Like the Out function (not shown here), it uses a SCSIDRV Command Block to contain all the information needed to perform a SCSI I/O. This includes the device handle, a pointer to the SCSI CDB (command) to be passed to the device, the length of the SCSI CDB, a pointer to the data buffer that will receive the data, and the length of data to be read. The SCSIDRV Command Block also contains a pointer to an 18-byte buffer that SCSIDRV will use for Request Sense data if a Check Condition occurs, as well as a flag field and a time-out value (in system ticks). The time-out value specifies the maximum length of time that the SCSIDRV driver should wait for the command to complete; if the command takes longer than this, the driver will terminate the command and return control to the caller of In, with an error code indicating a time-out. The purpose of this is to avoid the system hanging due to a problem in a peripheral device. The time-out value should be chosen with care: you must avoid terminating commands that are progressing normally, but not wait so long that, if a problem does occur, the user thinks that the system has crashed. Conclusion For those wishing to experiment further, the source for the program, including header files and .PRJ files for Lattice C (SCSIDEMO.PRJ) and Pure C (PC_SCSID.PRJ) is here. If you want to read more about SCSIDRV, the documentation is available here. This includes the specification (in both English and German), C-language headers with useful structure and constant definitions, and sample SCSIDRV programs. The current version of CBHD (version 5.02) is available here; this also includes documentation, but in German only.
Useful contacts Roger is the founder of Anodyne Software, which specialises in CD driver and related software. He can be reached at roger.burrows@anodynesoftware.com
MyAtari magazine - Feature #5, December 2001
[ Top of page ]
Copyright 2001 MyAtari magazine |