Darwin • 48:16
Mac OS X supports an ATA or SCSI device with a stack of drivers that manage the services used by the system from the device. This technology also provides applications with access to specific device functionality based on the peripheral type of the device. This session covers how applications can access the functionality provided by such devices through the use of file systems, BSD nodes, IORegistry, and both system and custom user clients. Partition schemes and filters are also discussed.
Speakers: Tim McLeod, Craig Marciniak, Dan Preston, Chris Sarcone
Unlisted on Apple Developer site
Transcript
This transcript was generated using Whisper, it has known transcription errors. We are working on an improved version.
Good afternoon. My name is Mark Tozer. I'm the technology evangelist for hardware. You're in session 111, Accessing SCSI and ATA Devices in Mac OS X. Today we'll go over lots of topics, and this is not SCSI as SCSI hardware connecting SCSI, so for those of you who think we're going back to SCSI, that's not the case. This is the protocol. I'd like to invite Tim McLeod, engineer in the mass storage software group.
Thank you, Marc. So, this session today, we're going to talk about SCSI and ATA Devices. The last couple years, we focused on how to write drivers so that these devices can be used by Mac OS X. This year, we're going to focus more on how do applications make use of these services provided by these devices. There's already many services built into Mac OS X, The next release of JAGUAR will be adding even more, such as scanner support via image capture, printing support via CUPS, and disk burning through the disk recording framework.
So, I know the question everyone here has is, what are these services, how do they differ, and which one should you be using? So what you will actually take away from this session is what SCSI and ATA devices are, what we mean when we use the term SCSI or ATA, how these devices are represented in Mac OS X, the services that are provided by these devices, and how to access these devices from applications.
So first, what is a SCSI device? A SCSI device is defined as a device that complies with one of the SCSI command sets as defined by the T10 committee, which is the controlling committee for SCSI and SCSI specifications. A SCSI device can actually be connected via different physical interconnects, such as FireWire, ATA using the Atapi protocol, USB, or traditional SCSI parallel.
More information on these can be found at the T10 website at www.t10.org. Now, in Mac OS X, when we say SCSI, we don't mean traditional parallel SCSI. When we do mean the traditional SCSI, parallel SCSI, we will actually be talking about the SCSI protocol. We will actually use the name SCSI parallel, or the more formal name, SCSI parallel interface.
So next, what is an ATA device? Well, an ATA device is a device that meets one of the specifications defined by the T13 Committee, which is the controlling committee for ATA. And these are such devices as standard ATA hard drives or PCMCIA ATA devices such as the IBM MicroDrive or CompactFlash. And more information on this can be found at the T13 website at www.t13.org.
So SCSI and ATA devices can provide different types of services. One is, of course, standard storage services such as mounting volumes and reading/writing blocks. Other are application-specific services such as tape drives, scanners, and printers. Or a device can actually provide both, such as DVD drives, which provide both block read and write and an application-specific service such as disk writing.
Now, there are a couple assumptions and limitations that are placed on these type of devices in Mac OS X. One of the main assumptions is we treat all devices as detachable from the system. So any device is designed to be hot-pluggable regardless of what bus it's connected via. and the other one is only a single entity can control a device at any given time. So basically one driver or application owns the device at any time.
So first, let's look at the general model of how storage devices are presented in Mac OS X. So first you have the controller layer, which is actually the lowest level hardware layer, which encompasses things like the PCI chip, the controller chip, and any of the services provided by the hardware. To allow the transport layer to talk to it. The transport layers actually have requests get sent down across a physical bus.
On top of the transport layer, we have the device services layer, which is these are the services that are provided by these devices to the system, and this is how the system and applications access these services. And in storage on top of that, we have the media access layer, which provides an entry point for the BSD media shims and allows volumes to be mounted on it so that block reading rights can occur.
So first we'll look at the ATA model. So the way an ATA device fits into this is you have the control at the bottom, which creates an IO-ATA device, which on top is the IO-ATA block storage driver, and this makes up the transport layer. On top of that, in the device services layer, you have the IO-ATA block storage device, which actually translates between the IO block storage driver, which is the entry point into the device services layer, for the IO media object, which represents the media in the device. And then on top of that, you can have BSD media shims and more IO media objects that represent volumes.
For SCSI storage, and in this example we use a DVD drive, in the controller layer we have the IO-ATA controller. The transport layer in this case actually has three pieces. We have the IOTOPI protocol transport, which converts between the SCSI architecture model pieces and the ATA bus. That's how SCSI tasks get sent to the device across ATA.
On top of that we have the IOScsi peripheral device nub, which represents the physical device. And then we have the IOScsi peripheral device type 5 driver, which is actually what builds and sends commands to the device. On top of that we have the IODVD services, which provides an interface for IODVD block storage driver, which allows system requests for reading and writing from the IOMedia object, which allows us to read and write blocks from the volumes on that media.
So the next we have is SCSI application-specific model. So like I said, devices can either provide storage function or application-specific function. In this example, we use a FireWire tape drive. In the control layer, we have IO FireWire family and IO FireWire SBB2. This represents the necessary protocols for the IO FireWire serial bus protocol transport to send commands across the bus.
the IFYWire serial bus protocol transport, Connects the SCSI architecture model pieces with the I/O Firewire family. On top of that, we have I/O SCSI peripheral device nub. But in this case, since it's a device that does not have a driver already in the system, it actually will allow the SCSI task user client to load on top of it in the device services layer, which allows an application to talk to the device.
So there are actually several methods of access to talk to these devices in Mac OS X. And an application can access the provided services via these methods, the Media Access Layer and BSD Media Shims and IR Media Filters. This is basically how you would talk to a mounted volume. The other is user clients, both provided and custom. Mac OS X provides some, and it also allows third parties to provide their own for special and specific vendor features.
The IORegistry for doing very simple transfer of the information between an application and the device's driver. And then the last thing we're actually going to talk about are older methods of access which are being obsoleted and how you can migrate from these. And these are such things as the IOSSCSI Live, IOCDB Live, and SCSI Action. And so now to talk about the first method of access, which is the media access layer, the BSD shims and volumes, is Craig Marciniak. Thank you.
Good evening. I'm Craig Marciniak, and we're going to have so much fun tonight, you just won't be able to contain yourself. There's a myth that mass storage is kind of boring, and we're here to dispel that. Okay, so we're going to learn about IO Media Objects. And the BSD and Unix experts in here are going to have to bear with me a little bit. For the benefit of traditional Mac programmers, I'm going to give a real brief overview of some real basic IO functions and how the BSD APIs work.
And then we'll talk a little bit about, once we understand that, of how you get to the BSD APIs from Carbon and Cocoa. And then I'm going to talk about how IO filters work, which are going to be interesting to some people here. And then to bring it all home, tie it all together, we've prepared a zippy, fun little demo.
So just to set context, I'm going to be talking about the media access layer and the objects and the support in that section of the stack. Okay, IO Media Objects are contiguous logical object representations of storage. This is all abstracted up away from all the bus specifics and idiosyncrasies. It's really pretty straightforward. It's a byte-based API that's 64-bit clean at this point.
So here's the overview of the BSD stuff. Device nodes, we talk about device nodes, you'll hear people talk about device nodes. They're nothing but file representations of physical hardware on your machine. If you go to the directory dev slash dev and do a listing, you're going to see file representations of your hardware and you can open them up and read and write, close, and we're going to learn about something called iOcto a little bit later.
The BSD interface is the user client access point. The examples I have here are dev disk zero and you'll see a lot of things that mirror it with an R in front of it. The R in this case for disk zero means raw. And so it's a real straightforward, simple, five-point API, open, read, write, close, iOctl. Some of the books, when you go get Unix books, we'll talk about other API stuff that we don't implement. So there are two BSD device interfaces, the raw and the block.
There's a lot of confusion about the RAW. If you go and read the, there's the red book with the devil on it, the design and implementation of BSD 4.4. It refers to and it talks to it and it's known as the character device interface. This really confuses people because this is what we're talking about here is a block interface and you shouldn't think of characters as 8 byte ASCII values or byte streams. This has nothing to do with it.
This goes back to legacy terminology for this was a way to do TTY access. So the block interface, what we've done to try to avoid the confusion internally is we always refer to the RAW device interface and the block device interface. If you're really interested in the details on this, on page 201 of the design and implementation of BSD 4.4, about halfway down the page, there's a really good description. That brings up all this stuff for the curious.
The raw device accesses through the /dev, R, disk, blah, blah, blah device nodes. Access must be a multiple of the natural block size of that device or it will be rejected with an error. Low-level disk utilities should be using this interface. Another example is, let's say someone has a high-end database that does not want to go through the UBC. The unified buffer cache. Because they have a usage pattern that isn't optimized for that particular caching scheme and they want to implement their own caching scheme, they would be candidates that might want to use the raw device interface.
So the block device interface, media is accessed through just the normal disk entry. Access does not have to be a multiple of the natural block size of the device. You can ask for arbitrary lengths and arbitrary addresses of stuff. The file systems generally use this interface. So using the interfaces, you would use the POSIX style IO functions. This is the open, read, write, close, and iOctal. And this shouldn't be confused with the ANSI standard C APIs.
The modes follow the established Unix semantics. Modes is the permissions, and you can use the man page to get all the Unix semantics if you're not familiar with them. And so once you get to this point, you need a BSD path to do stuff. So, ending paths from Cocoa. Cocoa's NS file manager and workspace, NS workspace, use mount points. Mount points can be translated to BSD paths from the get mount info call or statfs.
So here's an example. This is kind of goofy pseudocode. and We're going to look for something as a mount to name that equals mount point. When we find that, there's an element off this StataFS structure called mount to from name, and we can get the BSD path from there. It turns out that getMountInfo actually calls StataFS. This is a shortcut if you don't have the requirement to iterate through stuff.
So getting BSD passed from Carbon. Carbon traditional APIs use volume reference numbers. There's a whole bunch of different ways you can get volume reference numbers. Most people that have experience with that know what they need. And so here's one example of taking a VREFNUM and using the PBH get volume parameters sync call. We have the VM device ID here, which actually turns out to be the path. So.
I'm going to go through those APIs really quick. Open. Basically, we need to... The first argument is going to be our path. The second argument is the mode. In this case, it's a read-only. There's a pattern here. The FDU, the file descriptor in this case, if it comes back negative one, it failed to open, and you can use AirNode to get refined information on that error. Again, see the man pages. The BSD design and implementation for an operating system book is really good, and Stephen's advanced programming in the Unix environment is also a really good reference.
Read and writes are pretty straightforward. Once we have a valid opened file descriptor, we can pass that in. We give it our read count again. If it fails, we'll get a negative one in the byte count, and we can go look at that error. Reads use the similar thing. Very straightforward.
Now we go to IOctals. IOctals, I've also heard some people call them IO Controls. It means IO Controls. Traditional Mac programmers, this is just like a PB Control call. We provide a whole bunch of them for you. Actually, not that many. You can go to the IO Media BSD client and the CD Media BSD client, and these header files will define them. The examples I have on the bottom here are... DKIOC Eject.
They look kind of hard to read at first. Historically, just for the trivia, DK means disk. The IOC means IO Control. The first one would be an Eject. The second one is a Get Block Size. New to Jaguar, we've added some stuff for our optical devices. The flush, excuse me, synchronized cache call, the read talk, the read disk info and read track information for the CDs.
Then in DV, we've added read disk info and read our zone info. So here's an example where we actually open up and get a valid descriptor. And we're going to use the iActl to get the block size. And once we call that, when we come back without an error, we can actually print BS to the screen.
Media filters provide block-oriented parsing at a strategic place high up in the stack at this media access layer that's completely abstracted away from all the buzz specifics and idiosyncrasies. Again, this is a byte-based API with 64-bit parameters. Last year's presentation, we did an overview of the whole mass storage architecture. In the last chapter of that book, we actually have a brief description and some example code to actually write a filter.
We have refined and polished and made a much better example, which will be available to you from our website. And we've actually, for this session, designed and wrote a nice little filter that I'm going to call up. Dan, I'm sorry, I'm ahead of myself. The simple media filter, I've got to back up.
A simple media filter basically takes this IO media object, which is a representation of media, filters it, and then presents filtered media to the system. What we've done here is the filter represents this purple color which is tinted, this hard drive, to show that it is now filtered. As it turns out, a partition scheme is nothing more than a complex filter. So we take an IO media representation of a full volume and we supply multiple partitions.
We can do arbitrarily complex filters. The classic example is Software Raid, where we can take any amount of IO objects, filter them, and present anything we really want to. There's really no limit to what you can do with this. We expect to see lots of interesting things from our... and other developers. Now I'll bring up Dan Preston for the demo.
So, we came up with an example filter scheme for this session. And all it does is simple byte swapping. So, in any filter scheme, the most important calls are the read and the write because they're actually doing the filtering for you. So, let's go ahead and take a look at the read example right here.
Since we're actually not going to be doing any manipulation of the data until after the read actually completes, we need to set up a completion routine in order to post-process the data. So that's where we're going to be doing our byte swapping. But first there's some setup we need to do. So one of the things we're doing is we're going to be using memory mapping instead of read bytes, write bytes. Now, memory mapping gets you a little bit of a performance gain over the read bytes, write bytes.
So that's kind of a win. And then as you can see, we set up our completion structure here. And we call read. And when the read completes, it'll go down to our completion routine. So you can see here, and David Breslis have been involved in the development of the BITESwap project.
[Tim McLeod]
So, the first thing we're going to do is we're going to do a BITESwap project. So, we're going to use the BITESwap project. So one kind of subtle aspect of this is that you're going to take a performance hit when you initially map the buffer. So you want to kind of, you want to do that on the client side, which is in the initial read call.
Everything on the read completion call is on the work loop, and so you want to keep your stuff there real inexpensive and fast if possible. So that's why we map it actually up here. So that's pretty much the read routine. If we take a look at the write now.
It's pretty much the same thing. You know, we're going to save a completion routine and map the buffer. And then we're going to actually byte swap the data as it comes in before we write it to the drive. The reason we're doing, setting up a completion again is because you're potentially, when you are byte swapping this, you're potentially manipulating the client's actual in-memory copy of this data. And so there's two ways to deal with this.
You can, if it's a cheap operation, if you're only doing something simple like byte swapping, you can have a completion routine that will actually swap the data back and get you back to the initial state of the data. Otherwise, if it's something expensive like encryption or compression or something like that, you might want to think about double buffering the data www.timclmc.com/sci-access and Chris Schaefer are the speakers.
So that's a look at the code. So let's take a look at how this all works. So we've got this text loaded on our system right now. I'm going to go ahead and create a disk image that's going to be filtered using our filter. So to do that, we use this command line utility called hdiutil. Tell it how big we want it to be.
We're going to pass it a partition type. Now what this partition type is, is it's actually the content hit that gets placed on the image. So if you're creating some sort of filtering scheme, that's how your driver is going to match, is by the content hit. And you're going to be putting a property in your driver's personality called content hit, and then it's going to match on that value.
So that's how our project is set up. It's set up to match on Apple ByteSwap to HFS. So then we'll give it a name.
[Transcript missing]
and you can see that our driver has found it and there's an extra slide called Apple Byte Swapped HFS. Now we're going to create a file system on there.
[Transcript missing]
If we take a look, you'll be able to see. So we'll take a look at the filtered slice first. If we go to offset 400, we should see the file system signature right there. It says H+. Now if we open up the unfiltered slice, and we go to the same offset, and David Koehn, and I'm going to give you a quick example of a few of the things that we've been working on. are some of the important aspects of writing a filter scheme. And now I'd like to call up Chris Sarcone. He's going to talk for a bit.
Thanks, Dan. So I have the front part of the methods of access here, the user clients, something that everybody wants to know about. There are... Probably a lot of questions out there, like what is a user client? A user client is actually an intermediary between a kernel object and a user space client, such as an application. A user client exports control to user space code via one of several mechanisms.
The most popular is a device interface. Device interfaces are based on an IO CFPlugin structure, and they act as proxies for kernel objects. Another method, which Craig went into detail about, is the IOCTL. And there are other methods which you can use, such as like raw mic Mach IPC.
So, you're probably asking what user clients does Apple actually supply? Apple supplies several user clients, some at the media layer and some at the device layer. Craig's kind of gone into what the user clients do at the media layer, and I'm going to talk to you a lot about what the user clients do at the device layer. At the device layer, we provide two user clients, the ATA Smart user client and the SCSI Task user client.
First, let's look at the ATA user client. The user client for ATA devices is called ATA Smart User Client. It's only available for those devices which report that they support the self-monitoring analysis and reporting technology as defined in the ATA 6 specification. There's actually an identifier in their identified data that says that they support that.
If they do support that, there will be some keys placed in the IORegistry. A smart user client can attach, as you can see at the ATA block storage device object, and the client application can talk through the ATA smart interface to get smart information from the device. Documentation for this is forthcoming. This is a new feature in Jaguar. For now, you can consult the HeaderDoc placed in the ATA smart lib header file. And like I said, it will be fully documented, I hope, by the time Jaguar ships.
Now let's look at user clients for SCSI devices. The user client for SCSI device provides two device interfaces. One is the SCSI task device interface. The other is the MMC device interface. There are also supplemental interfaces which aren't actually device interfaces, such as the SCSI task interface. We may add more device interfaces or supplemental interfaces as more features are requested from you.
So if you have more feature requests, let us know. These device interfaces and supplemental interfaces are fully documented inside Mac OS X, accessing hardware from applications. There's a chapter on using SCSI architecture model devices, and you can find that in soft copy and hard copy. And we have an SDK available for you to get up to speed on SCSI task user client today.
Let's look at the SCSI TAS device interface. The SCSI TAS device interface is provided for peripheral device types not supported by Apple with in-kernel drivers. These devices are tape drives, scanners, printers, medium changers, basically anything that doesn't have storage built in like a hard drive. The SCSI TAS device interface requires an exclusive access model so that it can provide the client application with full control of the device. New in Jaguar, we're going to be adding the SCSI task management functions. These task management functions include things like abort task, abort task set, reset logical unit, reset target device, etc.
So, here's an illustration of the stack and how it builds up for a user client for a SCSI device. In this example, we have a FireWire tape drive. There's the FireWire family and FireWire SPP2, which represents the physical interconnect. We then have the IO FireWire serial bus protocol transport and the IO SCSI peripheral device NUM. The stack doesn't build up any higher than this for us because there is no internal logical unit driver for tape drives.
So, the SCSI task user client is used by the client application to communicate with this device. As you can see, the client application and SCSI task user client, when used in conjunction, become the logical unit driver. And the SCSI task user client sort of straddles the application and kernel address space, so it does the dirty work for transferring the commands.
Now let's look at the MMC device interface. The MMC device interface is provided for all MMC2 compliant drives capable of authoring. Apple defines an authoring capable drive as one which provides get configuration profiles that says that it does CD or DVD burning, or it says that in the mechanical capabilities mode page.
The MMC device interface can be used in conjunction with the SCSI task device interface to gain exclusive access to authoring devices. However, if you are going to be doing authoring, you might want to look at the disk recording framework. It's much, much more simple than using the SCSI task device interface, and it will simplify the amount of time that you need to spend to get burning working in your applications.
We also wanted to let you know that part of the MMC device interface is a little bit more complicated. The MMC device interface today provides information which has now been migrated to iOctools at the media layer. And so in the next couple of revisions of the MMC device interface, we'll be phasing out some of those commands in preference for you using the iOctools.
Here we have an example stack diagram for a DVD burner. It's an Atopy DVD drive, so we have an Atopy protocol transport driver. We also noticed that the stack builds all the way up to the IO DVD block storage driver. Now when the SCSI task user client connects and the client gets exclusive access to the device, you'll notice the peripheral device type 5 driver and up are sort of grayed out. That's to note that they're sort of quiesced at that time. And so, again, the client application, when used in conjunction with the SCSI task user client, become the logical unit driver and have full control of the device.
So now you're probably asking, well, how do I obtain exclusive access to one of these devices? The first thing you need to do is make sure that you've unmounted all mounted volumes for that device. We have new Carbon APIs in Files.h to unmount the volumes. Some of these APIs include fscreate volume operation, fsdespose volume operation, and fsunmount volume synchronous or the async variety, depending on what your applications need is.
Also, you can use a new feature in Jaguar. The digital hub, which we have as the center for all of your digital products, such as the CD burners and any sort of camera and stuff, the digital hub will actually send notifications when blank media is inserted to the drive, and it'll send notifications to the app that is chosen in the user's preference pane as the one for blank CD media or blank media. And these new APIs are there because previously people had to use a sort of private SPI called disk arbitration. We're hoping that developers will migrate to these new APIs so that we can wean them from disk arbitration.
So once you've unmounted all volumes, you can use the SCSI task device interface to query whether exclusive access is available. If exclusive access is available, you can then obtain it. And once you've obtained it, your application again becomes the logical unit driver, and it can send SCSI tasks down to the device. Now I'd like to call up Dan Preston again to do a demo using the SCSI task user client. Thanks, Chris.
Okay, so let's open up the project here. So we thought it'd be kind of cool to create a demo that does, it kind of is a simple diagnostic utility, and all it really does is perform a sequence of, you know, sequential reads on a CD, and then it kind of measures how fast it goes. So, um, the main function in this is run exclusive test suite. So the first thing that happens before this gets called is that we use the new Carbon APIs to unmount any devices or any volumes.
So then this gets past a SCSI task device interface. Now the first thing that we do is we obtain exclusive access for the device, and if that fails, then we bail out. Otherwise, we have obtained exclusive access. Second, we're going to create the SCSI task, and that's what we're going to use to do our work.
We allocate some memory in here. And then we're going to start looping and doing our reads. So... The next thing we do is we fill out our CDB. And in this case, it's just a read 10. And we're going to set the command descriptor block within the task. And then we're going to set the scatter gather entries.
And after that, you have to set the timeout. And optionally, you can set task attributes with the set task attribute call. In our case, we're setting head of queue. That's just an example. It's, you don't have to...
[Transcript missing]
Finally, all we have to do is release our memory, release a task, and then release exclusive access to the device. So let's fire this thing up. And it shows all the devices on the computer right here.
[Transcript missing]
So it does 100 reads on the drive. And then you can see it's getting a little over a meg and a half a second.
[Transcript missing]
So that's about it. Chris? Thanks, Dan. So now, now that we've covered the Apple-supplied user clients, the ATA user client and the SCSI task user client, and we've given you an example of how to use the SCSI task user client, these two user clients might not satisfy all your needs. You might need to actually write a custom user client.
Before you go down the path of writing a custom user client, we'd like you to ask yourself a few questions. First of all, is a user client really necessary? Well, you might ask yourself, "Well, how do I know if it's necessary or not?" The questions to ask yourself are, "Well, how much data do I need to move back and forth "between my application and my driver? "And how often do I need to do it?" If your data is very, very small, something less than four kilobytes, or you're not doing it too often, like say you're doing it less than, you know, once every ten seconds, you might be able to get away with other methods. And so we'd like you to consider some other options.
You can use I/O registry properties. You can find static properties in an application, and you can set static properties in a driver. This is all documented in the I/O Kit Fundamentals book. Also, you can dynamically set properties. Dynamically setting properties requires an application to build a dictionary and send the properties down to a device.
And all the device driver has to do is override a I/O Kit Fundamentals. And then it's a function to get those properties. This works really well for people that have to set preferences. So if you have to set preferences, you might want to think about creating a system startup item and then use this method to dynamically set properties in your driver. Also, there's a method of doing asynchronous notifications from the driver to interested applications. An application can register for general interest notifications and attach that to their run loop, and then get notified asynchronously from the driver when certain things happen.
So if you decide that those methods can't help you and you really have to write a user client, you need to create a subclass of the IO user client class. You then need to define the API you want to use between your application and your driver. You need to implement those functions in the kernel. And then finally you can test it with a command line app or tool. There's actually sample code provided by DTS to do simple user clients, and that can be expanded to do lots of different things.
Now we're going to move on to another method of access, the IORegistry. As I mentioned a couple slides before, you can get static properties from the registry from an application. You do this by first finding out which IO service you want to get information from. You do that by calling IOServiceGetMatchingServices, and you pass it the I/O Kit master port and a dictionary for stuff that signifies what you want it to match. In this case, we'll be matching on a driver whose name is my class name.
This call returns an iterator to you. You can then loop over that iterator to get the actual IOService objects. On that, you can get the actual IOService object. You can call IORegistryEntryCreateCFProperties, and that gives you back a CFDictionary in which you can inspect that and look for properties that you're interested in.
The other way is to dynamically set properties. Like I mentioned, if you wanted to write a system startup item to set properties, again, you would try and find the object you're trying to look for, and then you call IORegistryEntry set CF properties after building a dictionary to send down using the core foundation routines.
In the kernel, for the set properties, you would have to override set properties. It gets passed in an OS object. You can cast that to an OS dictionary and make sure it's the right type. And once you get that OS dictionary object, you can look inside it for properties that the driver understands. And from there, you can go ahead and execute whatever commands you need to to set those properties correctly.
Finally, we're going to talk about migration from obsoleted methods. There are some methods we would like to obsolete. Number one, we'd like to obsolete SCSI action. We will be obsoleting SCSI action in the future because I/O Kit should contain hardware APIs. Carbon is going to formally deprecate this API in Jaguar. Carbon will remove this API post-Jaguar.
One of the major reasons why we are getting rid of SCSI action is because the performance is not very great. It's a shim on top of a shim, and you don't tend to get too great a performance from that. SCSI action is actually shimmed on top of IOSCSI lib and IOCDB lib. Both of these have a limitation inherent that they will only work with IOSCSI family-based drivers.
IOSCSI family itself is going to be replaced by a new IOSCSI parallel family in Jaguar. We're hoping to have all of the major host-bust adapters for SCSI using the new IOSCSI parallel family. When they do, IOSCSI lib and IOCDB lib will no longer function. One of the main reasons why we're getting rid of IOSCSI lib is because most of the functionality is equivalent or better in the SCSI task user clients.
Finally, those of you who are working on scanner or printer drivers, you should look into using the image capture architecture so that you can promote system-wide use for applications for scanners or printers. For CUPS printers, the CUPS architecture, the Common Unix Printing System architecture, is what will be used in Jaguar for system-wide printing. You can use SCSI task user clients to actually talk to your devices, but you'd really like to make them fit within these Apple-supplied architectures for doing good drivers.
Finally, we have a roadmap of other sessions you might be interested in. There's a session tomorrow at 2 p.m., session 008, the Disrecording APIs. This shows you how to write CDs and DVDs from your applications. Also, session 510, Printing in Mac OS X. This is an overview of the CUPS architecture, and that is tomorrow at 10.30 a.m. And finally, session 515, the Image Capture Framework, and that is Friday at 2 p.m.
For more information, you can look at the T10 Committee website for the SCSI specifications. It's found at www.t10.org. And for ATA specifications, you can visit www.t13.org. Also, we have a mass storage discussion list. To subscribe, you can send an email to requests at sam.apple.com, and the message would be subscribe xmassstorage.
Finally, we also have some documentation. As mentioned earlier, we have the Accessing Hardware from Applications book. The chapter that you'd probably be interested would be working with SCSI Architecture Model Devices. Both soft copy and hard copy are available at the following URLs. and there's also an excellent book on writing drivers for mass storage devices. And again, soft copy and hard copy are available. And finally, if you need to contact somebody, you can contact Mark Tozer. He's the hardware evangelist.