Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1350606
  • 博文数量: 281
  • 博客积分: 8800
  • 博客等级: 中将
  • 技术积分: 3346
  • 用 户 组: 普通用户
  • 注册时间: 2006-05-17 22:31
文章分类

全部博文(281)

文章存档

2013年(1)

2012年(18)

2011年(16)

2010年(44)

2009年(86)

2008年(41)

2007年(10)

2006年(65)

我的朋友

分类: LINUX

2009-03-08 14:18:48

Computers control and transfer data to SCSI devices via SCSI commands. In this article, the author introduces some of the SCSI commands and methods of executing SCSI commands when using SCSI API in Linux®. He provides background on the SCSI client/server model and the storage SCSI command. Next, he explains the Linux generic SCSI driver API and offers an example of using a system that focuses on executing the inquiry command using the generic driver.

 

During the communication between a host and storage, a host generally acts as a SCSI initiator. In computer storage, the SCSI initiator is the endpoint that initiates a SCSI session, meaning it sends a SCSI command. The storage often acts as a SCSI target that receives and processes SCSI commands. The SCSI target waits for the initiator's commands and then provides required input/output data transfers.

The target usually provides the initiators one or more logical unit numbers (LUN). In computer storage, a LUN is simply the number assigned to a logical unit. A logical unit is a SCSI protocol entity, the only one that may be addressed by the actual I/O operations. Each SCSI target provides one or more logical units; it does not perform I/O as itself, but on behalf of a specific logical unit.

In a storage area, a LUN often represents a SCSI disk on which a host can perform a read and write operation. Figure 1 shows how the SCSI client/server model works.



The initiator first sends commands to the target, which decodes the command and then may request data from the initiator or send data to the initiator. After that, the target sends the status to the initiator. If the status is bad, then the initiator sends a request sense command to the target. The target returns the sense data to indicate what went wrong.

Now let's focus on storage-related SCSI commands.

 

 

Storage-related SCSI commands are defined mainly in the SCSI Architecture Model (SAM), SCSI Primary Commands (SPC), and SCSI Block Commands (SBC):

  • SAM defines the SCSI systems model, the functional partitioning of the SCSI standard set, and the requirements applicable to all SCSI implementations and implementation standards.
  • SPC defines behaviors that are common to all SCSI device models.
  • SBC defines the command set extensions to facilitate operation of SCSI direct-access block devices.

Each SCSI command is described by a Command Descriptor Block (CDB), which defines the operations to be performed by the SCSI device. The SCSI commands involve data commands that are used for transferring data from or to SCSI devices and non-data commands that request or set the configure parameters of a SCSI device. In Table 1, you can see the most commonly used commands.


Command

Description

Inquiry

Requests general information of the target device

Test/Unit/Ready

Checks whether the target device is ready for the transfer operation

READ

Transfers data from the SCSI target device

WRITE

Transfers data to the SCSI target device

Request Sense

Requests the sense data of the last command

Read Capacity

Requests the storage capacity information

All SCSI commands should begin with an operation code as the first byte. This indicates what operation it represents. All SCSI commands should also contain a control byte. This is typically the last byte of the command, used for vendor-specific information and other uses.

Now on to the generic SCSI driver.

 

 

SCSI devices under Linux are often named to help the user identify the device. For example, the first SCSI CD-ROM is /dev/scd0. SCSI disks are labeled /dev/sda, /dev/sdb, /dev/sdc, etc. Once device initialization is complete, the Linux SCSI disk driver interfaces (sd) send only SCSI READ and WRITE commands.

These SCSI devices may also have generic names or interfaces, such as /dev/sg0, /dev/sg1 or /dev/sga, /dev/sgb, etc. With these generic driver interfaces, you can directly send SCSI commands to SCSI devices, bypassing a file system that is normally created on a SCSI disk and mounted under a directory. In Figure 2, you can see how different applications communicate with SCSI devices.


Figure 2. The myriad ways of communicating with a SCSI device

With a Linux generic driver interface, you can build applications that can send more kinds of SCSI commands to SCSI devices. In other words, you have a choice. To determine which SCSI device stands for which sg interface, you can use the sg_map command to list the maps:

[root@taomaoy ~]# sg_map -i

/dev/sg0  /dev/sda  ATA       ST3160812AS       3.AA

/dev/sg1  /dev/scd0  HL-DT-ST  RW/DVD GCC-4244N  1.02

 

With Red Hat or Fedora, sg3_utils should be installed. Let's take a look at how to performa a typical SCSI system call command.

 

 

SCSI generic driver supports many typical system calls for character device, such as open(), close(), read(), write, poll(), ioctl(). The procedure for sending SCSI commands to a specific SCSI device is also very simple:

1.       Open the SCSI generic device file (such as sg1) to get the file descriptor of SCSI device.

2.       Prepare the SCSI command.

3.       Set related memory buffers.

4.       Call the ioctl() function to execute the SCSI command.

5.       Close the device file.

A typical ioctl() function could be written like this: ioctl(fd,SG_IO,p_io_hdr);.

The ioctl() function here requires three parameters:

1.       fd is the file descriptor of the device file. After the device file is successfully opened by calling open(), this parameter could be acquired.

2.       SG_IO indicates that an sg_io_hdr object is handed as the third parameter of the ioctl() function and will return when the SCSI command is finished.

3.       The p_io_hdr is a pointer to the sg_io_hdr object, which contains the SCSI command and other settings.

The most important data structure for the SCSI generic driver is struct sg_io_hdr, which is defined in scsi/sg.h and contains information on how to use the SCSI command. Listing 1 shows the definition of the structure.


 

typedef struct sg_io_hdr

{

    int interface_id;               /* [i] 'S' (required) */

    int dxfer_direction;            /* [i] */

    unsigned char cmd_len;          /* [i] */

    unsigned char mx_sb_len;        /* [i] */

    unsigned short iovec_count;     /* [i] */

    unsigned int dxfer_len;         /* [i] */

    void * dxferp;                  /* [i], [*io] */

    unsigned char * cmdp;           /* [i], [*i]  */

    unsigned char * sbp;            /* [i], [*o]  */

    unsigned int timeout;           /* [i] unit: millisecs */

    unsigned int flags;             /* [i] */

    int pack_id;                    /* [i->o] */

    void * usr_ptr;                 /* [i->o] */

    unsigned char status;           /* [o] */

    unsigned char masked_status;    /* [o] */

    unsigned char msg_status;       /* [o] */

    unsigned char sb_len_wr;        /* [o] */

    unsigned short host_status;     /* [o] */

    unsigned short driver_status;   /* [o] */

    int resid;                      /* [o] */

    unsigned int duration;          /* [o] */

    unsigned int info;              /* [o] */

} sg_io_hdr_t;  /* 64 bytes long (on i386) */

 

Not all the fields in this structure are required, so only those that are commonly used are introduced here:

  • interface_id: Should always be S.
  • dxfer_direction: Used for data transfer direction; could be one of the following values:
    • SG_DXFER_NONE: No data transfer is needed. Example: a SCSI Test Unit Ready command.
    • SG_DXFER_TO_DEV: Data is transferred to device. A SCSI WRITE command.
    • SG_DXFER_FROM_DEV: Data is transferred from device. A SCSI READ command.
    • SG_DXFER_TO_FROM_DEV: Data is transferred both ways.
    • SG_DXFER_UNKNOWN: The data transfer direction is unknown.
  • cmd_len: The length in bytes of cmdp that points to the SCSI command.
  • mx_sb_len: The maximum size that can be written back to the sbp when a sense_buffer is output.
  • dxfer_len: The length of the user memory for data transfer.
  • dxferp: A pointer to user memory of at least dxfer_len bytes in length for data transfer.
  • cmdp: A pointer to the SCSI command to be executed.
  • sbp: A pointer to the sense buffer.
  • timeout: Used to timeout the given command.
  • status: SCSI status byte as defined by the SCSI standard.

In summary, when data is about to be transferred using this method, cmdp must point to SCSI CDB whose length is stored in cmd_len; sbp points to a user memory whose maximum length is mx_sb_len. In case an error occurs, the sense data would be written back to this place. dxferp points to a memory; the data would be transferred from or to the SCSI device depending on the dxfer_direction.

Finally, let's look at an inquiry command and how it would execute using the generic driver.

 

阅读(854) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~