| 
 Q: I'd like to use secondary interrupts in my SCSI
         Interface Module (SIM) but doing so causes strange deadlocks.
         Is it legal to use secondary interrupts in a SIM? A: In general, using secondary interrupts on the page
         fault path is not legal. There are, however, circumstances
         under which it works. As with most of my Q&A, this
         takes some explanation. 
  
 
| Note:The page fault path is the set
                  system of system software and device drivers that
                  are required to resolve a virtual memory page
                  fault. The page fault path is an interesting
                  concept in operating system design, because most
                  operating systems require that all entities on the
                  page fault path not cause a page fault. Double page
                  faults will commonly cause an operating system to
                  "panic".
 On Mac OS, double page faults are always fatal.
                  Mac OS prevents double page faults by disabling
                  "user code" while page fault path entities are
                  executing. In addition, all entities on the page
                  fault path must be capable of performing an I/O
                  request with interrupts disabled. For more information about the virtual memory
                  implementation on Mac OS, see Technote 1094
                  Virtual
                  Memory Application Compatibility. |  
  
 
| IMPORTANT:While this Q&A is couched in terms of SCSI
                  Manager SIMs, the same logic applies to any entity
                  on the page fault path. Third-party developer
                  opportunities on the page fault path currently
                  include SIMs, AIMs (ATA Interface Modules), and
                  disk drivers. This list will grow as new
                  technologies, like FireWire, evolve to support disk
                  devices.
 |  The two common reasons for using secondary interrupts in
         a device driver are: 
            Reducing interrupt latency -- By deferring complex
            work to a secondary interrupt, you can reduce the amount
            of time your driver spends at hardware interrupt time,
            and thereby reduce the overall interrupt latency of the
            system.Concurrency guarantee -- Secondary interrupts are
            guaranteed to be serialized; only one secondary interrupt
            handler can be running at any point in time. This is a
            very useful concurrency control mechanism. If you always
            access global data structures from your secondary
            interrupt handler, you can be assured that only one
            thread of execution is reading or writing those global
            data structures at a time. However, secondary interrupts can cause problems for
         devices on the page fault path. Imagine the following
         scenario: 
            Your SIM takes a hardware interrupt, schedules a
            secondary interrupt (SIH A), and then returns from its
            hardware interrupt handler. For your SIM to make forward
            progress, its secondary interrupt handler must execute to
            completion.The interrupt systems notices that it is returning to
            interrupt level 0 and begins processing secondary
            interrupts. It enables interrupts and starts running
            secondary interrupt handlers.While SIH A is running, a Time Manager interrupt
            occurs. The timer task executes, schedules a deferred
            task, and then returns.The interrupt system notices that it is returning
            from the Time Manager interrupt to interrupt level 0.
            There are deferred tasks to run, so it enables interrupts
            and starts running deferred tasks.One of the deferred tasks causes a page fault.The Virtual Memory Manager intercepts the page fault,
            and makes a synchronous request to the disk device driver
            to read the page contents from the backing store.The disk device driver calls SCSI Manager to execute
            a SCSI command, which in turn calls your SIM. Your SIM
            starts the command and returns, expecting a hardware
            interrupt to complete the command.Your SIM's hardware interrupt fires and schedules a
            secondary interrupt (SIH B) to complete the command. The system is now deadlocked. The SIH B cannot run
         because secondary interrupt handlers must be single-threaded
         and SIH A is already running. But the SIH A cannot run
         because it has been interrupted by a page fault, which is
         sitting in a synchronous wait loop waiting for SIH B to run.
          The solution is to not use secondary interrupt handlers
         in your SIM, or any software entity on the page fault path.
          Newer versions of Mac OS provide another workaround for
         this problem. On such systems, the OS detects these
         potential deadlock cases (waiting for a synchronous device
         request with an interrupt mask of 0 and with secondary
         interrupt handlers queued) and calls your
         SIMInterruptPollroutine. Your interrupt poll routine can detect that it has
         queued a secondary interrupt that has not yet run, and
         perform the appropriate action directly. Typically this
         involves calling your secondary interrupt handler routine
         directly. This approach has a number of important caveats: 
            It does not work on older systems. You can check for
            the presence of secondary interrupt polling using the
            code in Listing 1. You should find it available on Mac OS
            8.5 and later.Secondary interrupt polling may undermine the
            concurrency guarantees provided by secondary interrupts.
            In the above example, look carefully at what happens during
            the deadlock recovery process. The system calls your
            interrupt poll routine and your interrupt poll routine
            calls SIH B directly. At this point, you have two threads
            of execution inside secondary interrupt handlers, SIH A
            and SIH B. This could cause problems if you designed your
            SIM to rely on the concurrency guarantees provided by
            secondary interrupts. If you want to use secondary
            interrupts in your SIM, you must take this potential
            reentrancy into account.Secondary interrupt polling is only useful for
            devices with an interrupt poll routine, such as SIMs and
            AIMs. Other native drivers, such as disk drivers, do not
            have an interrupt poll routine and cannot use secondary
            interrupts if they are on the page fault path. Because of these caveats, it may just be easier to do
         everything in your SIMs hardware interrupt handler. SIMs are
         mostly I/O bound, so the interrupt latency increase of doing
         everything in your hardware interrupt handler is minimal.
          You can detect whether secondary interrupt polling is
         implemented using Gestalt, as shown in Listing
         1. Listing 1. Determining whether secondary interrupt
         polling is available 
  
 
| static Boolean HasSecondaryInterruptPolling(void)
{
    UInt32 response;
    return (Gestalt(gestaltSCSI, (SInt32 *) &response) == noErr) &&
            ((response & (1 << gestaltSCSIPollSIH)) != 0);
} |  In summary: 
            Prior to Mac OS 8.5, you must never use secondary
            interrupts on the page fault path.With Mac OS 8.5 and beyond, SIMs and AIMs may use
            secondary interrupts, but they must take special action
            in their interrupt poll routine.Despite the difficulties using secondary interrupts
            in a SIM, DTS recommends that SIM developers seriously
            consider adopting this technique. The primary advantage,
            lower system interrupt latency, is a significant benefit
            to real-time applications such as QuickTime. For more information about this mind-manglingly complex
         part of the Mac OS I/O subsystem, see: |