Copyright (c) Hyperion Entertainment and contributors.

NSD Thoughts

From AmigaOS Documentation Wiki
Jump to navigation Jump to search

Revision

Version 1.5 (2013-04-11)

Thoughts & Consequences

This chapter may count as a set of annotations to NSD. It should shed some light on certain decisions and the consequences for users and implementers of NSD devices.

You may have noticed that there isn't a device type for SCSI or narrator. This is intentional. There is no NSD narrator right now and it is probably unwise to rely on the interface of the old narrator. A scsi device is typically a logical superset of trackdisk functionality and, for non disk devices relying only on HD_SCSICMD, a subset of scsi.device, which in turn classifies as trackdisk like. So in some way simple trackdisk functionality is the common base. It is also expected that any user visible difference between a SCSI like device and a trackdisk like device will tend to disappear. So SCSI and trackdisk like device have been put under the common label of NSDEVTYPE_TRACKDISK. The CD 32 cd.device is also a trackdisk like device within this meaning.

IOERR_NOCMD support is a design basis for NSD. Actually, support of IOERR_NOCMD is _the_ design basis for NSD. There are very few very broken devices out there which don't even support IOERR_NOCMD correctly and simply crash on unknown commands. These are not supported under NSD, and some kind of patch or "wrapper device" is needed for them to avoid a crash with a NSD using application. This was expected when NSD was designed, and based on the saying "the needs of the many outweigh the needs of the few", it was accepted that NSD cannot be safe for absolutely every single device in existence.

Another design basis for NSD is mentioned in Exec Device I/O:

The philosophy behind the devices is that I/O operations should be consistent and uniform.

This means that many commands like CMD_WRITE have similar functionality among very different types of devices. The philosophy is reflected by the general reserved command area and the general query command. This philosophy also extends to the meaning of IOERR_NOCMD which is described in <exec/errors.h> and referred to on page 924 of the RKM Libraries, 3rd edition. IOERR_NOCMD should be returned consistently for unsupported, i.e. unimplemented commands by the device. This means that it is not an acceptable error value for commands that are in fact supported by the device, but can't be executed correctly currently, because of limitations of the currently set up underlying hardware or configuration. It is only acceptable as error value if the respective command will never ever at any time under any circumstance be available.

A basic problem exists with old style SANA devices. They tweak the OpenDevice() usage by passing in parameters via the request. In Exec Device I/O it is stated that:

In addition to establishing the link to the device, OpenDevice() also initializes fields in the I/O request.

Passing in configuration data via an "uninitialized" request on OpenDevice() is therefore somewhat special and unusual. This is considered a design flaw in the SANA specification as it breaks the uniform nature of device access. So SANA devices can put a monkey wrench into the NSD system and this lead to the "safer assumptions" kludge. NSD is based on the assumption that devices can be "probed", so a general query on a SANA device may not return what you expect. Unless absolutely required by the original device specification, it is unwise to pass in configuration information on OpenDevice() within the NSD framework. For a SANA-device you would have to close it after the query and reopen it with the correct configuration data to be able to use it, if you don't pass in the configuration information right away. This leaves an access hole that isn't there for other types of devices. 3rd party devices needing this feature for 3rd party functionality should better use a configuration command to set parameters. For device specific usage of an NSD device, this isn't really a problem as you expect to get the right device type on OpenDevice(), which should be OK except for pathological cases. A query is mainly a verification of the required feature set here, so the risk is minimal. In general, it is an issue to think about, though.

The mn_Length check has been originally introduced into NSD to make use of a device safer. The easiest check is for the minimum required request size in OpenDevice(). This will catch basic programming errors and, in the worst case, only make OpenDevice() fail, rather than make the computer crash in unexpected ways. Refusal to open is deemed better than definitely overwriting or referencing garbage memory.

An exact check for mn_Length is very unwise and cannot be recommended, as a user may decide to use an extended IORequest with some additional user private fields. It would also be a fairly simple improvement to add mn_Length checks to all individual commands in the device. The overhead of a simple compare can typically be neglected, and the device can make sure that the size of the request is acceptable for the specific command. This would be of additional help for devices which support different sizes of IORequests for different commands.

Be aware that the minimum required request size on OpenDevice() may be less than what the commands need. So design the mn_Length check in OpenDevice() carefully to include the most error checking possible right there without keeping the device from opening. Don't forget that a general NSCMD_DEVICEQUERY must be possible, too, even if the device itself does use completely different request sizes. Note also that early NSD using software may use just a simple struct IOStdReq for the general query. As you can see by now, checking mn_Length for each command is not a bad idea, either.

Validating mn_Length is a very simple way to catch fundamental but obscure errors to avoid a system crash. There will always be a pathological case that cannot reasonably be caught like special broken parameter settings, but simple validations like an mn_Length check make device access a lot safer. Along these lines, other fields, like io_Unit, of a request could be validated. If a device can easily check for broken user SW, it should do so and return decent error values instead of crashing the system.