linux scsi generic howto学习笔记

Linux SCSI Generic Driver接口,目的是为了能够将SCSI命令直接发送给SCSI设备,并获得返回信息。以SCSIdisk为例,这样做会旁路掉block子系统。

 

很多设备使用其他非SCSI类型总线,比如ATAPI、USB、IEEE1394,也利用了SCSI命令集。通过Linux pseudo SCSI device drivers,(这个驱动桥接实际的协议栈和SCSI子系统),使得SCSI设备驱动能够控制non-SCSI设备。

 

Sg驱动的功能:

Sg驱动允许应用程序直接向设备发送懂得的SCSI命令。需要先初始化设备,然后发送SCSI READ和SCSI WRITE命令。

 

有时候底层驱动(比如HBA驱动)无法将命令发送给设备,此时会返回‘host_status’或‘driver_status’错误给用户应用程序。

如果SCSI命令(有时带有数据)被顺序发送给设备,设备会返回一个单字节值:scsi_status。GOOD表示一切安好,而大多数情况下会是CHECK_CONDITION。在返回CHECK_CONDITION情况下,SCSI mid level会执行一个REQUEST_SENSE_SCSI命令,该命令返回信息是一个>=18B的“sense buffer”。这个sense buffer昭示了原SCSI命令无法成功执行的原因。CHECK_CONDITION表示的可能是仅仅通知一下,可以通过重试来执行成功,或者可能是致命的,需要换盘。

 

“sense buffer”的信息有时候需要传回给用户应用层,read命令时,sg驱动也要将读取的数据从设备传给应用层。

 

实际上,对于磁盘有专用的sd驱动,CD有scd,tapes有st。sg是一个scsi generic驱动。

设备初始化时第一个执行的命令是INQUIRY命令,所有设备均需正确翻译,提供vendor, product designation and revision等信息。

 

Sg驱动版本号:早期的sg驱动或者没有版本号,或者以2开头,现在的sg驱动版本号以3为主版本号,格式为“x.y.z”通过ioctl():SG_GET_VERSION_NUM得到的数字是x*10000+y*100+z,还可以从cat/proc/scsi/sg/version获得版本号。

 

Sg驱动支持的系统调用接口有:

  • open()
  • close()
  • write()
  • read()
  • ioctl()
  • poll()
  • fcntl(sg_fd, F_SETFL, oflags | FASYNC)
  • mmap()

[root@oss5 sgpdd-survey]# ll /dev/sg2

crw------- 1 root root 21, 2 May  4 09:32 /dev/sg2

注意是:字符设备,主设备号:21。

如果支持devfs,则可能会有:

$ cd /dev/scsi/host1/bus0/target0/lun0

$ ls -l generic

crw-r-----    1 root     root      21,   1 Dec 31  1969 generic

一旦devfs运行,则there would usually be a symbolic linkfrom /dev/sg1 to/dev/scsi/host1/bus0/target0/lun0/generic,使用devfs的好处是onlyattached SCSI devices appear in the /dev/scsi subtree,仅有attached的SCSI设备才会出现在/dev/scsi子树中。

 

新的sg v3驱动接受ioctl():SG_IO,等同于a write() followed by a blocking read()。有时write()/read()组合要优于SG_IO。

 

 Sg_v3驱动调用既接受老式的sg_header结构体,也接收新式的sg_io_hdr_t结构体,根据sg_header::reply_lenor sg_io_hdr_t::dxfer_direction来判断使用哪个接口。新式接口中dxfer_direction是负数值。函数write()/read()必须使用同一种接口。

 

操作理论:

通过sg driver的请求可以分为三个不同的阶段:

1、   The request is received fromthe user, resources are reserved as required (e.g. kernel buffer for indirectIO). If necessary, data in the user space is transferred into kernel buffers.Then the request is submitted to the SCSI mid level (and then onto the adapter)for execution. The SCSI mid level maintains a queue so the request may have towait. If a SCSI device supports command queuing then it may be able toaccommodate multiple outstanding requests.

2、   Assuming the SCSI adaptersupports interrupts, then an interrupt is received when the request iscompleted. When this interrupt arrives the data transfer is complete. Thismeans that if the SCSI command was a READ then the data is in kernel buffers(indirect IO) or in user buffers (direct or mmap-ed IO). The sg driver isinformed of this interrupt via a kernel mechanism called a "bottomhalf" handler. Some kernel resources are freed up.

3、   The user makes a call to fetchthe result of the request. If necessary, data in kernel buffers is transferredto the user space. If necessary, the sense buffer is written out to the userspace. The remaining kernel resources associated with this request are freedup.

系统调用write()执行1,而read()执行3。如果read()在stage 2完成之前调用,则该read()或者等待或者被放弃掉(依赖于文件描述符blocking or not)。如果使用异步通知,则stage2会发送一个SIGPOLL信号给用户进程。则poll()系统调用会显示该文件描述符是readable的。

 

SG_IO ioctl()执行stage1,然后等待stage2,然后执行stage3。使用SG_IO时,如果文件描述符被设置成O_NONBLOCK,SG_IO会忽略之,并且继续block。SG_IO也不会影响poll()状态,也不会导致SIGPOLL信号被发送。如果你确实想要non-blocking操作,就不要使用SG_IO,使用write()->read()顺序代替之。

 

Sg使用21作为主设备号,支持256个设备,如果更多,则会被拒绝,并向终端和log文件发送消息。Devfs有扩展超过256个设备的补丁。

 

系统调用:

1、 open(const char * filename,int flags)

l  O_RDONLY     restricts operations to read()s and ioctl()s (i.e.can't use write() ).

l  O_RDWR       允许所有的系统调用执行。

l  O_EXCL         在处理之前等待相关SCSI设备的所有其他open操作关闭。如果设

置了O_NONBLOCK ,则在已经有someone打开了该设备时,立即返回EBUSY. 禁止组合使用 O_RDONLY 和 O_EXCL 。

l  O_NONBLOCK设置 non-blockingmode. Calls that would otherwise block yield EAGAIN (e.g. read() ) or EBUSY(e.g. open() ). T该标记被 ioctl(SG_IO) 忽略。

可能有多个file描述符对应同一scsi设备,在sg level层分别为它们保存了单独的状态信息,.这意味着即使同一scsi设备有多个file打开文件描述符,它们的write()、read()也是基本上独立的。

 

Open()可能会被互斥锁阻塞。An exclusive lock applies to asingle SCSI device and only to sg's use of that device (i.e. it has no effecton access via sd, sr or st to that device).

 

驱动试图预留SG_DEF_RESERVED_SIZE 字节 (32KBytes in the current sg.h) on open(). 可以用SG_SET_RESERVED_SIZE ioctl()改变这个预留内存的大小. 实际预留的大小可以用SG_GET_RESERVED_SIZE ioctl(). Thereserved buffer will be used if:

· it is not already in use (e.g.when command queuing is in use)

· a write() or ioctl(SG_IO) 请求数据传输的大小<= 预留缓存的大小

Returns a file descriptor if >= 0 , otherwise -1 implies an error.

2、  write(int sg_fd, const void * buffer, size_t count)

The 'buffer' 指向类型为struct sg_io_hdr_t的结构体实例,'count' 需要是sizeof(sg_io_hdr_t) [可以大于sizeof(sg_io_hdr_t)]. 写成功调用,则'count' 中是写入的数量.

 

最多SG_MAX_QUEUE (16) 个write()s 可以入队,before any finished requests are completed by read()[看来write()后必须read()一下来完成一个请求].An attempt to queue more than that will result in an EDOM error. [1] The write() command should return moreor less immediately. [2]

 

The "const" on the 'buffer' pointer is respectedby the sg driver. Data 从 sg_io_hdr object 中读出. Significantly this is when the 'sbp' and the 'dxferp' are recordedinternally (i.e. not from the sg_io_hdr object given to the correspondingread() ).

 

Notes

[1]   

SCSI device and the adapter driver 的queuecapacity也需要考虑. To this end the sg_scsi_id::h_cmd_per_lun andsg_scsi_id::d_queue_depth values returned bu ioctl(SG_GET_SCSI_ID) may beuseful. Also some devices that indicate in their INQUIRY response that they canaccept command queuing react badly when queuing is actually attempted.

[2]   

There is a small probability it will spend some timewaiting for a command block to become available. In this case the wait isinterruptible. If O_NONBLOCK is active then this scenario will cause a EAGAIN.

3、  read(int sg_fd, void * buffer, size_t count)

The 'buffer' 指向struct sg_io_hdr_t实例,并且'count' 为sizeof(sg_io_hdr_t) [可以 > sizeof(sg_io_hdr_t),但超出的部分会被忽略 ]. 如果read执行成功,则count是实际读取的数据字节数。

 

默认的, read() 会返回队列中已经完成的请求. Read()不会和SG_IO ioctl()的请求冲突、混淆,特殊情况例外:SG_IO ioctl() 被信号中断.

 

如果设置SG_SET_FORCE_PACK_ID,read()会去获取 pack_id (given earlier to write()) 和作为参数传递给这个read()的sg_io_hdr_t::pack_id相匹配的包. 如果没有,则会等待或返回 EAGAIN. As a special case, -1 in sg_io_hdr_t::pack_id given toread() will match the request whose response has been waiting for the longesttime. Take care to also set 'dxfer_direction' to any valid value (e.g.SG_DXFER_NONE) when in this mode. The 'interface_id' member should also be setappropriately.

 

Apart from the SG_SET_FORCE_PACK_ID case (and then only forthe 3 indicated fields), the sg_io_hdr_t object given to read() can beuninitialized. Note that the 'sbp' pointer value for optionally outputting asense buffer was recorded from the earlier, corresponding write().

4、  poll(struct pollfd *ufds, unsigned int nfds, int timeout)

检查一个sg文件描述符的状态,通常会立即返回。经典做法是周期性的去poll文件描述符状态,以决定为什么接到一个SIG_IO信号。

 

对和sg设备关联的文件描述符:

l  POLLIN one or more responses is awaiting a read()

l  POLLOUT command can be sent to write() without causing an EDOM error(i.e. sufficient space on sg's queues)

l  POLLHUP SCSI device has been detached, awaiting cleanup

l  POLLERR internal structures are inconsistent

POLLOUT indicates the sg will not block a new write() orSG_IO ioctl(). However it is still possible (but unlikely) that the mid levelor an adapter may block (or yield EAGAIN).

 

5、  close(int sg_fd)

在所有的write()对应的read()返回后,就需要关闭设备。但用户有时需要立即关闭设备,比如发送kill信号方式,Sg driver会实现一个fast关闭的语义,并且或长或短的时间内返回,因为sg driver需要安排顺序清理仍然in flight的包。

 

函数close()会让未完成的SCSI命令等待响应,sg driver会为已关闭“defunt”的文件描述符保留中间数据结构,internal structures会一直被维护,直到所有未完成的响应返回(有的是超时返回)。仍拥有打开文件描述符和“defunt”文件描述符的sg module不会被卸载,rmmod时会返回busy。

Defunct file descriptors that remain for some time, perhapsawaiting a timeout, can be observed with the cat /proc/scsi/sg/debugcommand。

Defunt文件描述符不会影响应用程序打开该SCSI设备新的文件描述符。

 

The kernel arranges for only the last close() on a filedescriptor to be seen by a driver (and to emphasize this, the corresponding sgdriver call is named sg_release() rather than sg_close()). This is onlysignificant when an application uses fork() or dup().

 

Returns 0 ifsuccessful, otherwise -1 implies an error.

 

6、  mmap(void * start, size_t length, int prot, int flags, int sg_fd,off_t offset)

该系统调用返回与文件描述符sg_fd关联的预留buffer地址。第一个参数start:是一个给内核的提示,被sg driver忽略,最好设置为0;第二个参数length<=预留buffer size,如果length超出了预留buffer size(后来length被调高到页面大小的倍数)则会返回MAP_FAILED,并且errno=ENOMEM;第三个参数prot或者是PROT_READ或者是(PROT_READ|PROT_WRITE);第四个参数flags需要包含MAP_SHARED。在某种意义上,用户应用和sg driver共享数据。MAP_PRIVATE和编译优化选项-O2合作的不好。第六个参数offset必须设置为0或NULL.

 

同一sg_fd上可以多次调用mmap(),刚close()调用后,就不必再调用munmap()。Mapped-IO在fork()/clone()产生子进程时性能良好,因为2进程和sg_driver会共享同一内存映射区域。最后一个关闭sg_fd或exit的进程会释放共享内存。

 

如果默认的32KB预留Buffer不够用,可用ioctl(SG_SET_RESERVED_SIZE)在调用任何mmap()之前重设预留buffer大小,如果请求的不是页大小倍数,则自动调成页大小倍数。

 

Mmaped IO是通过在sg_io_hdr的flag成员中设置SG_FLAG_MMAP_IO来完成的,在调用write()或ioctl(SG_IO)之前设置。

7、  fcntl(int sg_fd, int cmd, long arg)

主要不要被其他进程的O_EXCL锁影响而陷入等待。以O_NONBLOCK扫描,一旦扫描到该设备就立即调成blocked io。

open("/dev/sg0", O_RDONLY | O_NONBLOCK)

/* check device, EBUSY means some other process has O_EXCL lock on it */

/* when the device you want is found then ... */

flags = fcntl(sg_fd, F_GETFL)

fcntl(sg_fd, F_SETFL, flags & (~ O_NONBLOCK))

/* since, with simple apps, it is easier to use normal blocked io */

Sg dirver支持异步通知机制,这是一个non-blocking模式,当driver从设备接收到数据,因为read()可被调用时,它发送一个SIGPOLL信号给owning process。

sigemptyset(&sig_set)

sigaddset(&sig_set, SIGPOLL)

sigaction(SIGPOLL, &s_action, 0)

fcntl(sg_fd, F_SETOWN, getpid())

flags = fcntl(sg_fd, F_GETFL);

fcntl(sg_fd, F_SETFL, flags | O_ASYNC)

 

8、  错误报告

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.

 

8.1. SG_IO

8.2. SG_GET_ACCESS_COUNT

8.3. SG_SET_COMMAND_Q(and _GET_)

8.4. SG_SET_DEBUG

8.5. SG_EMULATED_HOST

8.6. SG_SET_KEEP_ORPHAN(and _GET_)

8.7. SG_SET_FORCE_LOW_DMA

8.8. SG_GET_LOW_DMA

8.9. SG_NEXT_CMD_LEN

8.10. SG_GET_NUM_WAITING

8.11. SG_SET_FORCE_PACK_ID

8.12. SG_GET_PACK_ID

8.13. SG_GET_REQUEST_TABLE

8.14. SG_SET_RESERVED_SIZE(and _GET_ )

8.15. SG_SCSI_RESET

8.16. SG_GET_SCSI_ID

8.17. SG_GET_SG_TABLESIZE

8.18. SG_GET_TIMEOUT

8.19. SG_SET_TIMEOUT

8.20. SG_SET_TRANSFORM

8.21. SG_GET_TRANSFORM

8.22. Sgioctls removed in version 3

8.23. SCSI_IOCTL_GET_IDLUN

8.24. SCSI_IOCTL_GET_PCI

8.25. SCSI_IOCTL_PROBE_HOST

8.26. SCSI_IOCTL_SEND_COMMAND

Ioctl指令依次通过Upper level--àmid level--àlower level(adapter) driver,直到有一个能处理它,如果都不能,则返回-1。SG_开头的由SG驱动处理,而SCSI_开头的由mid leveldriver处理

Sg读写数据的过程是:适配器<->kernelbuffer<->用户内存区域,为提升性能,可以用direct IO或Mapped IO,这两种方法都是直接在适配器和用户区域之间传递数据。

Direct IO

Direct IO利用了kiobuf技术,如果请求使用directIO而实际上无法执行direct IO时会自动使用indirect IO。如果请求并成功使用了direct IO,则请求完成后,struct sg_io_hdr_t的info成员中会被设置SG_INFO_DIRECT_IO位。Direct IO在ISA SCSI适配器上不支持,因为它只能定位24位地址空间。

 

One limit on direct IO is thatsg_io_hdr_t::iovec_count==0. So the user cannot (currently) use applicationlevel scatter gather and direct IO on the same request。

 

For direct IO to be worthwhile, areasonable amount of data should be requested for data transfer. For transfersless than 8 KByte it is probably not worth the trouble. On the other hand"locking down" a multiple 512 KB blocks of data for direct IO couldadversely impact overall system performance. Remember that for the duration ofa direct IO request, the data transfer buffer is mapped to a fixed memorylocation and locked in such a way that it won't be swapped out. This can"cramp the style" of the kernel if it is overdone.

 

通过echo 1 > /proc/scsi/sg/allow_dio来使能direct io,如果sg_io_hdr::flags中设置了SG_FLAG_DIRECT_IO而/proc/scsi/sg/allow_dio值为0,则仍使用indirectIO。

 

Mmaped-IO

在Mmaped-IO使用之前必须调用mmap(),使用的memory是sg driver为每个scsi文件描述符预留的buffer,默认32KB,可通过ioctl(SG_SET_RESERVED_SIZE)重新设置大小。

 

既然每个file只有1个预留buffer,因此每次只有1个mmaped-io命令是active的,如果希望perform command queuing with mmaped IO,则对同一scsi设备需要打开多个file描述符。一旦对一个file调用了mmap,后续对同一file描述符的mmap会返回EBUSY。

 

Mmap-ed has very low per command latencysince the reserved buffer mapping only needs to be done once per filedescriptor. Also the reserved buffer is set up by the sg driver to aid theefficient construction of the internal scatter gather list used by the lowerlevel (adapter) driver for DMA purposes. This tends to be more efficient thanthe user memory that direct IO requires the sg driver to process into aninternal scatter gather list. So on both these counts, mmap-ed IO has the edgeover direct IO.

 

驱动及模块初始化:

modprobe sg

modprobe sg def_reserved_size=<n>

rmmod sg

Sg和proc文件系统:

目录/proc/scsi/sg/

[root@oss5 sg]# ls

allow_dio  debug  def_reserved_size  device_hdr  devices  device_strs  version

代表的意义:

allow_dio       0 indicates direct IO disable, 1 for enabled

debug           debug information including active request data

def_reserved_size  default buffer size reserved for each file descriptor

devices         one line of numeric data per device

device_hdr      single line of column names corresponding to 'devices'

device_strs     one line of vendor, product and rev info per device

version         sg version as a number followed by a string representation

在device_hdr中的信息:

host            host number (indexes 'hosts' table, origin 0)

chan            channel number of device

id              SCSI id of device

lun             Logical Unit number of device

type            SCSI type (e.g. 0->disk, 5->cdrom, 6->scanner)

opens           number of opens (by sd, sr, sr and sg) at this time

depth           maximum queue depth supported by device

busy            number of commands being processed by host for this device

online          1 indicates device is in normal online state, 0->offline

执行sgp_dd if=/dev/sg9 of=/dev/null bs=512:

[root@oss5 sg]# cat debug

dev_max(currently)=32 max_active_device=18 (origin 1)

 def_reserved_size=32768

 >>> device=sg9 scsi1 chan=0 id=8 lun=0   em=0 sg_tablesize=256 excl=0

   FD(1): timeout=60000ms bufflen=65536 (res)sgat=2 low_dma=0

   cmd_q=1 f_packid=1 k_orphan=0 closed=0

     act: id=2098304 blen=65536 t_o/elap=60000/1ms sgat=2 op=0x28

     rb>> act: id=2098432 blen=65536 t_o/elap=60000/1ms sgat=2 op=0x28

     act: id=2098560 blen=65536 t_o/elap=60000/0ms sgat=2 op=0x28

     act: id=2098688 blen=65536 t_o/elap=60000/0ms sgat=2 op=0x28

The ">>>" line显示 the sgdevice 名,然后是the linux scsi adapter, channel, scsi id and lun numbers. The"em=" 释放驱动模拟了一个SCSI HBA. The ide-scsi driver 会设置"em=1".The "sg_tablesize" is the maximum number of scatter gather elementssupported by the adapter driver. The "excl=0" indicates no sg open()on this device is currently using the O_EXCL flag.

 

The next two linesstarting with "FD(1)" supply data about the first (and only in thiscase) open file descriptor on/dev/sg0. The default timeout is 60 secondshowever this is only significant if the sg_header interface is being used sincethe sg_io_hdr interface explicits sets the timeout on a per command basis."bufflen=65536" is the reserved buffer size for this file descriptor.The "(res)sgat=2" indicates that this reserved buffer requires 2scatter gather elements. The "low_dma" will be set to 1 for ISA HBAsindicating only the bottom 16 MB of RAM can be used for its kernel buffers. The"cmd_q=1" indicates command queuing is being allowed. The"f_packid=1" indicates the SG_SET_FORCE_PACK_ID mode is on. The"k_orphan" value is 1 in the rare cases when a SG_IO is interruptedwhile a SCSI command is "in flight". The "closed" value is1 in the rare cases the file descriptor has been closed while a SCSI command is"in flight".

 

Each line indented with 5 spaces representsa SCSI command. The state of the command is either:

  • prior: command hasn't been sent to mid level (rare)
  • act: mid level (adapter driver or device) has command
  • rcv: sg bottom half handler has received response to this command (awaiting read() or SG_IO ioctl to complete
  • fin: SCSI response (and optionally data) has been or is being read but the command data structures have not been removed

These states can be optionally prefixed by"rb>>" which means the reserved buffer is being used,"dio>>" which means this command is using direct IO, or"mmap>>" which means that mmap-ed IO is being used by this command.The "id" is the pack_id from this command's interface structure. The"blen" is the buffer length used by the data transfer associated withthis command. For commands that a response has been received "dur"shows its duration in milliseconds. For commands still "in flight" anindication of "t_o/elap=60000/1ms" means this command has a timeout of60000 milliseconds of which 1 milliseconds has already elapsed. The"sgat=2" argument indicates that this command's "blen"requires 2 scatter gather elements. The "op" value is the hexadecimalvalue of the SCSI command being executed.

 

Procfs使用固定大小缓存来存放debug,如果输出数据过多,则会看到的是最近的数据,其他的被丢弃了。

 

Sg的异步使用:

同步:SG_IO

异步:如果设备支持command queuing,则异步性能更好。即使设备不支持异步或临时busy,则在mid level或host driver层queuing command依然可以获得性能提升。

 

异步使用:通常首先设置O_NONBLOCK(open()或者fcntl(fd, SETFD, old_flags| O_NONBLOCK)),也可以在多线程posix环境下不需要使用O_NONBLOCK。策略如下:

  1. set O_NONBLOCK and use a poll() loop
  2. set O_NONBLOCK and use SIGPOLL signal to alert app when readable
  3. use POSIX threads and a single sg file descriptor
  4. use POSIX threads and multiple sg file descriptors to same device

The O_NONBLOCK标记依然允许open(),write() and read() [but not the ioctl(SG_IO)] 访问SCSI设备即使该设备被标记为offline.SCSI被标记为offline:(1)、可被检测到但无法响应初始化scsi命令;(2)在该设备上,一些scsi错误状态被检测到并且mid level error recovery logic无法重构设备. A SCSI devicethat is being reset (and still settling) could be accessed during this periodby using the O_NONBLOCK flag; this could lead to unexpected behaviour so the sguser should take care.

 

In Linux SIGIO and SIGPOLL are the same signal.If POSIX real time signals are used (e.g. when SA_SIGINFO is used withsigaction() and fcntl(fd, F_SETSIG, SIGRTMIN + <n>) ) then the filedescriptor with which the signal is associated is available to the signalhandler. The associated file descriptor is in the si_fd member of the siginfo_tstructure. The poll() system call that is often used after a signal is receivedcan thus be bypassed.


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值