通过 sg 驱动程序的请求路径可以分为 3 个不同的阶段
请求从用户处接收,并根据需要预留资源(例如,用于间接 IO 的内核缓冲区)。如果必要,用户空间中的数据将被传输到内核缓冲区。然后,请求被提交到 SCSI 中间层(然后到适配器)以执行。SCSI 中间层维护一个队列,因此请求可能需要等待。如果 SCSI 设备支持命令队列,则它可以容纳多个未完成的请求。
假设 SCSI 适配器支持中断,那么当请求完成时,会收到一个中断。当此中断到达时,数据传输完成。这意味着如果 SCSI 命令是 READ,则数据位于内核缓冲区(间接 IO)或用户缓冲区(直接或 mmap-ed IO)中。sg 驱动程序通过称为 “bottom half” 处理程序的内核机制获知此中断。一些内核资源被释放。
用户调用以获取请求的结果。如果必要,内核缓冲区中的数据将被传输到用户空间。如果必要,sense 缓冲区将被写入用户空间。与此请求关联的剩余内核资源被释放。
write() 调用执行阶段 1,而 read() 调用执行阶段 3。如果在阶段 2 完成之前发出 read() 调用,那么它将等待或产生 EAGAIN(取决于文件描述符是否为阻塞的)。如果正在使用异步通知,则阶段 2 将向用户进程发送 SIGPOLL 信号。poll() 系统调用将显示此文件描述符现在可读(除非它是由 SG_IO ioctl() 发送的)。
SG_IO ioctl() 执行阶段 1,等待阶段 2,然后执行阶段 3。如果所讨论的文件描述符设置为 O_NONBLOCK,则 SG_IO 将忽略此设置并且仍然阻塞!此外,SG_IO 调用不会影响 poll() 状态,也不会导致发送 SIGPOLL 信号。如果你真的想要非阻塞操作(例如,用于命令队列),那么不要使用 SG_IO;而是使用 write() read() 序列。
有关普通(或间接)、直接和 mmap-ed IO 的更多信息,请参见第 9 章 。
目前,sg 驱动程序使用一个 Linux 主设备号(字符 21),这在 lk 2.4 系列中将其限制为处理 256 个 SCSI 设备。任何尝试连接超过此数量的设备都将被拒绝,并且会向控制台和日志文件发送消息。[1]
存在用于 sg 的补丁,当使用设备文件系统 (devfs) 时,可以将 SCSI 设备数量扩展到超过 256 个限制。