Writing a SCSI Device DriverThis section provides additional information you need to write a device driver that is compatible with both SCSI Manager 4.3 and the original SCSI Manager.
Loading and Initializing a DriverDuring system startup of Macintosh models that do not include SCSI Manager 4.3 in ROM, the Start Manager scans the SCSI bus from SCSI ID 6 to SCSI ID 0, looking for devices that have both an
Apple_Driverpartition. For each device found, the driver is loaded and executed, and installs itself into the unit table. The driver then places an element in the drive queue for any HFS partitions that are on the drive.
When SCSI Manager 4.3 is present in ROM, the Start Manager loads all SCSI Manager 4.3 drivers from all devices on all registered buses. Drivers that support SCSI Manager 4.3 are identified by the string
pmParTypefield of the partition map. Traditional (
Apple_Driver) drivers are then loaded for any devices on the virtual bus that do not contain a SCSI Manager 4.3 driver.
If SCSI Manager 4.3 is not present in ROM, the Start Manager treats SCSI Manager 4.3 drivers exactly like traditional drivers. Because the Start Manager in earlier Macintosh computers checks only the first 12 characters of the
pmParTypefield before loading and executing a driver, both SCSI Manager 4.3 drivers and traditional drivers will load on these models. To initialize the driver, the Start Manager jumps to the first byte of the driver's code (using a
JSRinstruction), with register D5 set to the SCSI ID of the device the driver was loaded from.
SCSI Manager 4.3 drivers contain a second entry point at an offset of 8 bytes from the standard entry. Use of this entry point means that SCSI Manager 4.3 is present and that register D5 contains a device identification record. No other registers are used.
There are seven unit table entries (32 through 38) reserved for SCSI drivers controlling devices at SCSI ID 0 through SCSI ID 6 on the virtual SCSI bus. For compatibility with existing SCSI utility software, drivers serving devices on the virtual bus should continue to install themselves in the unit table locations reserved for traditional SCSI drivers. Drivers for devices that are not on the virtual bus should choose a unit number outside the range reserved for traditional SCSI drivers. See the chapter "Device Manager" in this book for information about installing device drivers in the unit table.
To allow clients to determine whether a driver has been loaded for a particular SCSI device, the XPT maintains a driver registration table. This table cross-references device identification records with driver reference numbers. The device identification record is a SCSI Manager 4.3 data structure that specifies a device by its bus, SCSI ID, and logical unit number. The device identification record is defined by the
DeviceIdentdata type, which is described on page 4-19.
A device identification record can have only one driver reference number associated with it, but a single driver reference number may be registered to multiple devices. You can use the
SCSIRemoveRefNumXreffunctions to access the driver registration table. Drivers loaded through the SCSI Manager 4.3 entry point must use the
SCSICreateRefNumXreffunction to register with the XPT. This is done automatically by SCSI Manager 4.3 for traditional drivers.
Selecting a Startup DeviceAfter all device drivers are loaded and initialized, the Start Manager searches for the default startup device in the drive queue. If the device is found, it is mounted and the boot process begins. Macintosh models that do not include SCSI Manager 4.3 in ROM identify the boot drive by a driver reference number stored in PRAM. This works well when drivers retain the same reference number between startups, but SCSI Manager 4.3 drivers allocate unit table entries dynamically if the device they are controlling is not on the virtual bus.
Macintosh models that include SCSI Manager 4.3 in ROM designate the startup device using Slot Manager values in PRAM. Slot number 0 is used for devices on the built-in bus or buses. The
dCtlSlotIdfields of the driver's device control entry must contain the slot number and sResource ID number, respectively. These are available in the bus inquiry data from the SIM. The
dCtlExtDevfield should contain both the SCSI ID and LUN of the device that the driver is controlling. The high-order 5 bits contain the SCSI ID (up to 31 for a 32-bit wide SCSI bus) and the low-order 3 bits contain the LUN.
Transitions Between SCSI EnvironmentsBecause SCSI Manager 4.3 can be installed as a system extension in older Macintosh models, your device driver may be loaded before SCSI Manager 4.3 is active. This can also occur if a NuBus or PDS expansion card loads SCSI Manager 4.3 or an equivalent XPT from the card's ROM. In this case, the expansion card will load a subset of the SCSI Manager 4.3 XPT and a SIM responsible for the card's HBA, but it will not load a SIM for the built-in bus. This creates a situation in which SCSI Manager 4.3 is loaded but some buses may be accessible only through the original interface.
To determine whether to use the SCSI Manager 4.3 interface, your driver should first check for the presence of the
_SCSIAtomictrap (0xA089). If the trap exists, the driver can pass the SCSI ID of its device to the
SCSIGetVirtualIDInfofunction to get the device identification record of its device. If the
scsiExistsfield of the parameter block returns
true, the device is available through the SCSI Manager 4.3 interface. If the
false, the device is on a bus that is not available through SCSI Manager 4.3.
The best time for your driver to perform this check is at the first
accRuntick, which occurs after all system patches are in place. The Event Manager calls your driver at this time if you set the
dNeedTimeflag in the device control entry. If your driver can access its device through SCSI Manager 4.3, it should allocate and initialize a SCSI I/O parameter block at this time.
Even if your driver is loaded and initialized by a ROM-based SCSI Manager 4.3, you can use the first
accRuntick to check for new features that may have been installed by a system patch.
Handling Asynchronous RequestsWhen a client makes a read or write request to a device driver, the Device Manager places the request in the driver's I/O queue. When the driver is ready to accept the request, the Device Manager passes it to the driver's prime routine. The prime routine should fill in a SCSI I/O parameter block with the appropriate values and call the
SCSIExecIOfunction. The XPT passes the parameter block to the proper SIM, which then adds the request to its queue and possibly starts processing it before returning back to the driver.
noErr, the request was accepted and the contents of the parameter block cannot be reliably viewed by the driver. At this point, virtually nothing can be assumed about the request. It may only have been queued, or it may have proceeded all the way to completion.
- Once a parameter block is accepted by XPT, do not attempt to examine the parameter block until the completion routine is called.
SCSIExecIOreturns an error result, the request was rejected and the completion routine will not be called. This is usually due to an input parameter error.
Completion routines can execute before the XPT returns to your driver. Because the completion routine may initiate a new request to the driver, it is possible that by the time control returns to the calling function, the parameter block is being used for a completely different transaction.
Asynchronous I/O requests from a client to a device driver can occur at interrupt time. Because you cannot allocate memory at interrupt time, you must reserve memory for parameter blocks, scatter/gather lists, and any other structures you need when the driver is initialized. You cannot use the stack for this purpose (as you can for synchronous requests) because parameters on the stack are discarded when the device driver returns from its prime routine.
Asynchronous requests may start at any time and may end at any time. There is no implied ordering of requests with respect to when they were issued. An earlier request may start later, or a later request may complete earlier. However, a series of requests to the same device (bus number, target ID, and LUN) is issued to that device in the order received (unless the
scsiSIMQHeadflag is set in the
scsiFlagsfield of the SCSI I/O parameter block, in which case the request is inserted at the head of the queue).
Handling Immediate RequestsIf your device driver supports immediate requests, it must be reentrant. The Device Manager neither sets nor checks the
drvrActiveflag in the
dCtlFlagsfield of the device control entry before making an immediate request. Asynchronous operation makes it even more likely that an immediate request will happen when your driver is busy because the immediate request may have been made from application time while your driver was asynchronous. When this happens you need to be careful not to reuse parameter blocks or other variables that might be busy.
Virtual Memory CompatibilityBecause page faults can occur while interrupts are disabled, SCSI device drivers can receive synchronous I/O requests from the Virtual Memory Manager when the processor interrupt level is not 0. The SCSI Manager handles the resulting SCSI transaction without the benefit of interrupts. This requires that all synchronous wait loops be performed either in the SCSI Manager or in the Device Manager, where code is provided to poll the SCSI interrupt sources.
When your driver receives a synchronous I/O request, it can issue the subsequent SCSI I/O request synchronously as well, or it can issue the SCSI request asynchronously and return to the Device Manager. This second option is generally preferred because it simplifies driver design. The Device Manager waits for the synchronous request to complete, allowing your driver to handle it asynchronously. The driver should jump to
IODoneafter it receives the SCSI completion callback. If a single driver request translates to multiple SCSI requests, and your driver handles them asynchronously, the driver should not call
IODoneuntil after the callbacks for all of the SCSI requests have been received.
- Because SCSI completion routines must not cause a page fault, all code and data used by SCSI completion routines must be held in real memory. This is automatic for device drivers loaded in the system heap. Applications (or drivers within applications) must use the
HoldMemoryfunction to ensure their completion routine code and data is held. See the chapter "Virtual Memory Manager" in Inside Macintosh: Memory for more information.
© Apple Computer, Inc.
3 JUL 1996