ADC Home > Reference Library > Technical Notes > Legacy Documents > Mac OS 9 & Earlier >

Legacy Documentclose button

Important: This document is part of the Legacy section of the ADC Reference Library. This information should not be used for new development.

Current information on this Reference Library topic can be found here:

Write Cache Flushing: Techniques for Properly Handling System Shutdown

CONTENTS

Many high-performance disk drives available for Macintosh computers utilize an on-board hardware write cache mechanism. Although these devices can enhance disk performance, they also require special software consideration to avoid the loss of data on shutdown.

This Technote is directed primarily to third-party IDE and SCSI disk interface module software developers, and addresses ways to flush the disk's write cache during the shutdown process.

 Updated: [Mar 1 1996]






Write Caching

Many disk drive manufacturers now include a write cache on the drive hardware. This cache is usually an area of temporary volatile storage (RAM) that has a faster access time than the actual drive media. Its purpose is to increase throughput.

These devices use an algorithm to write back the cache. When the write back cache mode is enabled, the disk controller uses the cache to temporarily store data that is promised to be written to the medium at a later time. This allows the disk controller to indicate to the computer that a write command has completed prior to the blocks of data actually being transferred to the medium. The process of transferring the cached data to the drive medium is known as cache-synchronization.

Because cache hardware uses volatile RAM, there is a period of time prior to cache-synchronization when the data is vulnerable to being lost if a power failure occurs before the media is updated.

Most drives will flush the cache periodically if there is no activity. However, some drives are unpredictable because if you don't explicitly synchronize their cache, they won't do it. This may pose a problem especially at system shutdown. Either the amount of time they wait after idle before synchronizing is sufficiently long enough that the power is shut off, or the Macintosh resets the bus before the data gets written. Delaying shutdown is not a reliable way to flush write cache because of varying vendor implementations.

Macintosh systems that use disk driver software which improperly handles write-caching run the risk of data loss or even corruption of the disks' file structure on shutdown.

Back to top

The Good, the Bad and the Ugly

Caching is such a popular technique that any particular Mac OS configuration could be used in any number of layers. For instance, the Macintosh File System maintains a cache. Even the disk interface card (e.g., PCI or NuBus) might also have a cache. These can coexist seamlessly, provided that during the shutdown process they are synchronized in a certain order: from the inside out. This is required to ensure data stored actually gets to the media.Yet in the current OS, the driver writer has only limited control of this process. Let's examine some of the available options.

Doing nothing - Bad

In the past, Apple shipped systems with drives which either did not support write caching or had the cache disabled. However, this is no longer necessarily true. If your driver still ignores the shutdown synchronization, you will suffer volume corruption.

Disabling the cache - Ugly

Some disk driver vendors simply attempted to prevent this circumstance by explicitly requesting the drive to select a write-through caching algorithm -- in effect, disabling the cache. This method is ugly, since it fails to take full advantage of the drive performance available.

Tail Patching of _UnmountVol - Uglier

Let's assume we enable the cache. The next question is, how do we ensure that our sync code runs after the file system is done with the volume? That's easy, you say, tail patch the _UnmountVol trap and flush the drive after the file system is done with it. In a perfect world, this idea might work. Unfortunately, some developers (including those at Apple) who depend on modifying the behavior of the File Manager had the same idea. Things can get pretty ugly, because there is no guarantee that your cache-synch code will run last.

Shutdown Task - Close, But No Cigar

The Macintosh Process Manager actually has a mechanism that allows code to run before shutdown or reset occurs. By invoking a call to ShutDwnInstall, your driver code can install an entry in the Shutdown Manager's power down queue. The Mac OS will then call your ShutDownProc during the power down process.

I'd like to say it was that simple, but after further examination of the code, I discovered that the File Manager also uses this method. So even though you are guaranteed to run, you can't be certain if it will be before or after the volumes unmount.

Actually, the solution is close at hand. I mentioned earlier that disabling the cache was one option. But instead of doing it all the time, we just disable caching at shutdown only and then force a synchronization. Even if any transfers happen after our ShutDownProc runs, they won't get caught waiting around in the write cache.

Back to top

Installing the Shutdown Procedure

To setup your shutdown proc when your driver is opened, instruct the Shutdown Manager to install a task in the sdRestartOrPower queue.

    ShutDwnInstall(YourShutDownProc, sdRestartOrPower);

Be sure to load your shutdown procedure into the system heap because the Process Manager frees all applications and other temporary heaps before calling the Shutdown Manager.

Back to top

Shutdown Procedure for SCSI Devices

Disabling the drive cache

The first thing you must do is disable the write cache by resetting the write cache enable (WCE) bit of the caching page, as shown in Table 1.

+=====-========-========-========-========-========-========-========-========+
|  Bit|   7    |   6    |   5    |   4    |   3    |   2    |   1    |   0    |
|Byte |        |        |        |        |        |        |        |        |
|=====+========+========+=====================================================|
| 0   |   PS   |Reserved|        Page code (08h)                              |
|-----+-----------------------------------------------------------------------|
| 1   |                          Page length (0Ah)                            |
|-----+-----------------------------------------------------------------------|
| 2   |                          Reserved          |  WCE   |   MF   |  RCD   |
|-----+-----------------------------------------------------------------------|
| 3   |   Demand read retention priority  |     Write retention priority      |
|-----+-----------------------------------------------------------------------|
| 4   | (MSB)                                                                 |
|-----+---                       Disable pre-fetch transfer length         ---|
| 5   |                                                                 (LSB) |
|-----+-----------------------------------------------------------------------|
| 6   | (MSB)                                                                 |
|-----+---                       Minimum pre-fetch                         ---|
| 7   |                                                                 (LSB) |
|-----+-----------------------------------------------------------------------|
| 8   | (MSB)                                                                 |
|-----+---                       Maximum pre-fetch                         ---|
| 9   |                                                                 (LSB) |
|-----+-----------------------------------------------------------------------|
| 10  | (MSB)                                                                 |
|-----+---                       Maximum pre-fetch ceiling                 ---|
| 11  |                                                                 (LSB) |
+=============================================================================+

Table 1. Caching page

You need to use the MODE SELECT command with (SP=0) to ensure that this change does not get written into the disk's non-volatile RAM. You just want the cache disabled for now, as shown in Table 2.

MODE SELECT(10) command
+=====-========-========-========-========-========-========-========-========+
|  Bit|   7    |   6    |   5    |   4    |   3    |   2    |   1    |   0    |
|Byte |        |        |        |        |        |        |        |        |
|=====+=======================================================================|
| 0   |                           Operation code (55h)                        |
|-----+-----------------------------------------------------------------------|
| 1   | Logical unit number      |  PF    |      Reserved    |     SP         |
|-----+-----------------------------------------------------------------------|
| 2   |                           Reserved                                    |
|-----+-----------------------------------------------------------------------|
| 3   |                           Reserved                                    |
|-----+-----------------------------------------------------------------------|
| 4   |                           Reserved                                    |
|-----+-----------------------------------------------------------------------|
| 5   |                           Reserved                                    |
|-----+-----------------------------------------------------------------------|
| 6   |                           Reserved                                    |
|-----+-----------------------------------------------------------------------|
| 7   | (MSB)                                                                 |
|-----+---                        Parameter list length                    ---|
| 8   |                                                                 (LSB) |
|-----+-----------------------------------------------------------------------|
| 9   |                           Control                                     |
+=============================================================================+

Table 2. Mode select command

Synchronizing the write cache

You have to force the disk to flush its write cache. Some drivers attempt to take shortcuts here by inserting a delay of a few hundred microseconds, assuming that the drives will flush automatically. Empirical evidence, however, indicates this is not always true. Some drives don't flush unless explicitly told to do so. You can blame this on a loose interpretation of the SCSI spec.

To be safe, send a SynchronizeCache (0x35, 10 byte CDB) command with all fields 0, to the drive. This guarantees all of the cache will be consistent with the media. The Immed bit must be clear to ensure the command will wait for completion, as shown in Table 3.

+=====-========-========-========-========-========-========-========-========+
|  Bit|   7    |   6    |   5    |   4    |   3    |   2    |   1    |   0    |
|Byte |        |        |        |        |        |        |        |        |
|=====+=======================================================================|
| 0   |                           Operation code (35h)                        |
|-----+-----------------------------------------------------------------------|
| 1   | Logical unit number       |         Reserved        |  Immed | RelAdr |
|-----+-----------------------------------------------------------------------|
| 2   | (MSB)                                                                 |
|-----+---                                                                 ---|
| 3   |                                                                       |
|-----+---                        Logical block address                    ---|
| 4   |                                                                       |
|-----+---                                                                 ---|
| 5   |                                                                 (LSB) |
|-----+-----------------------------------------------------------------------|
| 6   |                           Reserved                                    |
|-----+-----------------------------------------------------------------------|
| 7   | (MSB)                                                                 |
|-----+---                        Number of blocks                         ---|
| 8   |                                                                 (LSB) |
|-----+-----------------------------------------------------------------------|
| 9   |                           Control                                     |
+=============================================================================+

Table 3. Synchronize cache command

Because the SynchronizeCache is described in the SCSI specification as an optional command, it's possible but unlikely that a drive could support write caching, but not support the SynchronizeCache command. Developers ought to be aware of this.

Ensuring That All Further Writes Go Directly to the Media

In some drives, disabling the write cache is not preferred. An alternative to doing this is to execute the synchronize cache command and from that point on only issue WRITE commands with the force unit access (FUA) bit set. This ensures that all further writes go directly to the media, as shown in Table 4.

+=====-========-========-========-========-========-========-========-========+
|  Bit|   7    |   6    |   5    |   4    |   3    |   2    |   1    |   0    |
|Byte |        |        |        |        |        |        |        |        |
|=====+=======================================================================|
| 0   |                           Operation code (2Ah)                        |
|-----+-----------------------------------------------------------------------|
| 1   | Logical unit number      |   DPO  | FUA  |Reserved|Reserved| RelAdr   |
|-----+-----------------------------------------------------------------------|
| 2   | (MSB)                                                                 |
|-----+---                                                                 ---|
| 3   |                                                                       |
|-----+---                        Logical block address                    ---|
| 4   |                                                                       |
|-----+---                                                                 ---|
| 5   |                                                                 (LSB) |
|-----+-----------------------------------------------------------------------|
| 6   |                           Reserved                                    |
|-----+-----------------------------------------------------------------------|
| 7   | (MSB)                                                                 |
|-----+---                        Transfer length                             |
| 8   |                                                                 (LSB) |
|-----+-----------------------------------------------------------------------|
| 9   |                           Control                                     |
+=============================================================================+

Table 4 Write Command

The driver must check if the disk supports this feature. You can do this by executing a MODE SENSE command to get the device-specific parameters and examining if the DPOFUA bit is set, as shown in Table 5.

+=====-========-========-========-========-========-========-========-========+
|  Bit|   7    |   6    |   5    |   4    |   3    |   2    |   1    |   0    |
|=====+========+=================+========+===================================|
|     |   WP   |     Reserved    |DPOFUA  |             Reserved              |
+=============================================================================+

Table 5. Device specific parameter

Back to top

Shutdown Procedure for ATA Devices

Due to loose interpretations and vendor uniqueness in the ATA Standard, there is no defined way that a driver can be assured that the disk's cache has been flushed. And the trigger to force a flush appears to vary by vendor. Even though the Set Features command can be used to disable the write cache, some drives don't flush it until they receive another command.

One way of handling this is to issue a Standby or Sleep command to the drive when you want to flush the cache. This works because the drive must flush the cache before spinning down. These commands may complete before the drive completely spins down, but they do not complete before the cache is flushed.

Unfortunately, at the time of this writing, ATA cache synchronization is still an unresolved issue with the X3T13 Standards Committee.

Back to top

Summary

Because it is part of the ANSI specification, Macintosh disk driver writers must support write caches and must assume that drives are shipped by manufacturers with write cache enabled.

Write caches may enhance system performance, but it is important to properly handle system shutdown to prevent any loss of data.

Not all drive vendors implement commands the same way. Therefore, it is the responsibility of the driver writer to understand the specific workings and implementations of the commands unique to a vendor's disk drive.

Back to top

References

Inside Macintosh: Devices, chapter on "SCSI Manager 4.3"

Inside Macintosh: Processes, chapter on "Shutdown Manager"

SCSI Spec: ANSI XT3T9.2/375R revision 10L,at ftp: //abekas.com: 8080/scsi2/

ATA-3 Spec: ANSI X3T10/ 2008D Revision 6,at

ftp://fission.dt.wdc.com/pub/standards/ata/ata-3

Back to top

Downloadables

Acrobat gif

Acrobat version of this Note (64K).

Download



Back to top


Did this document help you?
Yes: Tell us what works for you.
It’s good, but: Report typos, inaccuracies, and so forth.
It wasn’t helpful: Tell us what would have helped.