With the original interface almost any string could be accidentally given to write() and potentially (but rarely) something nasty could happen. If some error was detected then more than likely EIO was placed in errno.
Unfortunately this can still happen with write() since it can accept both the original struct sg_header or the newer sg_io_hdr_t described in this note. However since the SG_IO ioctl() will only accept the sg_io_hdr_t structure there is less chance of a random string being interpreted as a command. Since the sg_io_hdr_t interface does a lot more error checking, it attempts to give out more precise errno values to help the user pinpoint the problem. [Admittedly some of these errno values are picked in an arbitrary way from the large set of available values.]
In most cases when a system call on a sg file descriptor fails, the call in question will return -1. After an application detects that a system call has failed it should read the value in the "errno" variable (prior to do any more system calls). Applications should include the <errno.h> header.
errno which_calls Meaning ----- ----------- ---------------------------------------------- EACCES <some ioctls> Root permission (more precisely CAP_SYS_ADMIN or CAP_SYS_RAWIO) required. Also may occur during an attempted write to /proc/scsi/sg files. EAGAIN r The file descriptor is non-blocking and the request has not been completed yet. EAGAIN w,SG_IO SCSI sub-system has (temporarily) run out of command blocks. EBADF w File descriptor was not open()ed O_RDWR. EBUSY o Someone else has an O_EXCL lock on this device. EBUSY w With mmap-ed IO, the reserved buffer already in use. EBUSY <some ioctls> Attempt to change something (e.g. reserved buffer size) when the resource was in use. EDOM w,SG_IO Too many requests queued against this file descriptor. Limit is SG_MAX_QUEUE active requests. If sg_header interface is being used then the default queue depth is 1. Use SG_SET_COMMAND_Q ioctl() to increase it. EFAULT w,r,SG_IO Pointer to user space invalid. <most ioctls> EINVAL w,r Size given as 3rd argument not large enough for the sg_io_hdr_t structure. Both direct and mmap-ed IO selected. EIO w Size given as 3rd argument less than size of old header structure (sg_header). Additionally a write() with the old header will yield this error for most detected malformed requests. EIO r A read() with the older sg_header structure yields this value for some errors that it detects. EINTR o While waiting for the O_EXCL lock to clear this call was interrupted by a signal. EINTR r,SG_IO While waiting for the request to finish this call was interrupted by a signal. EINTR w [Very unlikely] While waiting for an internal SCSI resource this call was interrupted by a signal. EMSGSIZE w,SG_IO SCSI command size ('cmd_len') was too small (i.e. < 6) or too large ENODEV o Tried to open() a file with no associated device. [Perhaps sg has not been built into the kernel or is not available as a module?] ENODEV o,w,r,SG_IO SCSI device has detached, awaiting cleanup. User should close fd. Poll() will yield POLLHUP. ENOENT o Given filename not found. ENOMEM o [Very unlikely] Kernel was not even able to find enough memory for this file descriptor's context. ENOMEM w,SG_IO Kernel unable to find memory for internal buffers. This is usually associated with indirect IO. For mmap-ed IO 'dxfer_len' greater than reserved buffer size. Lower level (adapter) driver does not support enough scatter gather elements for requested data transfer. ENOSYS w,SG_IO 'interface_id' of a sg_io_hdr_t object was _not_ 'S'. ENXIO o "remove-single-device" may have removed this device. ENXIO o, w,r,SG_IO Internal error (including SCSI sub-system busy doing error processing - e.g. SCSI bus reset). When a SCSI device is offline, this is the response. This can be bypassed by opening O_NONBLOCK. EPERM o Can't use O_EXCL when open()ing with O_RDONLY EPERM w,SG_IO File descriptor open()-ed O_RDONLY but O_RDWR <some ioctls> access mode needed for this operation.