Linux下的SCSI驱动的实现,驱动与用户层交互接口规范的制定,以及用户态的配置管理工具主要由“The Linux SCSI Generic (sg) Driver”项目负责。

The Linux sg driver is a upper level SCSI subsystem device driver that is used primarily to handle devices _not_ covered by the
other upper level drivers: sd (disks), st (tapes) and sr (CDROMs and DVDs). The sg driver is used for enclosure management, cd
writers, applications that read cd audio digitally and scanners. Sg can also be used for less usual tasks performed on disks, tapes
and cdroms. Sg is a character device driver which, in some contexts, gives it advantages over block device drivers such as sd and
sr. The interface of sg is at the level of SCSI command requests and their associated responses.The term SCSI has several meaning depending on the context. This leads to confusion. One practical way of defining it today is
everything that the T10 INCITS committee controls, see www.t10.org . Probably the most succinct overview is this standards
architecture page . For practical purposes a "SCSI device" in Linux is any device that uses the Linux SCSI subsystem and this often
includes SATA disks.From about Linux kernel 2.6.24, there is an alternate SCSI pass-through driver called "bsg" (block SCSI generic driver). The bsg
driver has device names of the form /dev/bsg/0:1:2:3 and supports the SG_IO ioctl with the sg version 3 interface. The bsg driver
also supports the sg version 4 interface which at this time the sg driver does not. Amongst other improvements the sg version 4
interface supports SCSI bidirectional commands. All recent "sg" user space packages (i.e. sg3_utils, sdparm, ddpt and smp_utils)
work equally well on both sg and bsg device names.

(来源: http://sg.danny.cz/sg/index.html。)

Linux SCSI设备的管理接口

用户层与驱动层通过ioctl的SG_IO命令发送SCSI命令和返回SCSI命令执行结果,从Linux 2.6内核开始,所有的块设备均支持ioctl的SG_IO命令。

The SG_IO ioctl permits user applications to send SCSI commands to a device. In the linux 2.4 series this ioctl was only available
via the SCSI generic (sg) driver. In the linux 2.6 series the SG_IO ioctl is additionally available for block devices and SCSI tape
(st) devices.  So there are multiple implementations of this ioctl within the kernel with slightly different characteristics and
describing these is the purpose of this document.

(来源: http://sg.danny.cz/sg/sg_io.html。)

SG_IO命令的数据结构

typedef struct sg_iovec { /* parallels "struct iovec" in readv() system call */ void * iov_base;            /* start address */ size_t iov_len;             /* length in bytes */
} sg_iovec_t; /* the scatter-gather list is an array of objects of this type */typedef struct sg_io_hdr
{ int interface_id;           /* [i] 'S' for SCSI generic (required) */ int dxfer_direction;        /* [i] data transfer direction  */ unsigned char cmd_len;      /* [i] SCSI command length ( <= 16 bytes) */ unsigned char mx_sb_len;    /* [i] max length to write to sbp */ unsigned short iovec_count; /* [i] 0 implies no scatter gather */ unsigned int dxfer_len;     /* [i] byte count of data transfer */ void * dxferp;              /* [i] [*io] points to data transfer memory or scatter gather list */ unsigned char * cmdp;       /* [i] [*i] points to SCSI command to perform */ unsigned char * sbp;        /* [i] [*o] points to sense_buffer memory */ unsigned int timeout;       /* [i] MAX_UINT->no timeout (unit: millisec) */ unsigned int flags;         /* [i] 0 -> default, see SG_FLAG... */ int pack_id;                /* [i->o] unused internally (normally) */ void * usr_ptr;             /* [i->o] unused internally */ unsigned char status;       /* [o] scsi status */ unsigned char masked_status;/* [o] shifted, masked scsi status */ unsigned char msg_status;   /* [o] messaging level data (optional) */ unsigned char sb_len_wr;    /* [o] byte count actually written to sbp */ unsigned short host_status; /* [o] errors from host adapter */ unsigned short driver_status;/* [o] errors from software driver */ int resid;                  /* [o] dxfer_len - actual_transferred */ unsigned int duration;      /* [o] time taken (unit: millisec) */ unsigned int info;          /* [o] auxiliary information */
} sg_io_hdr_t;  /* around 64 bytes long (on i386) *//* Use negative values to flag difference from original sg_header structure */
#define SG_DXFER_NONE -1        /* e.g. a SCSI Test Unit Ready command */
#define SG_DXFER_TO_DEV -2      /* e.g. a SCSI WRITE command */
#define SG_DXFER_FROM_DEV -3    /* e.g. a SCSI READ command */
#define SG_DXFER_TO_FROM_DEV -4 /* treated like SG_DXFER_FROM_DEV with the additional property than during indirect IO user buffer is copied into the kernel buffers before the transfer */
#define SG_DXFER_UNKNOWN -5     /* Unknown data direction *//* following flag values can be "or"-ed together */
#define SG_FLAG_DIRECT_IO 1     /* default is indirect IO */
#define SG_FLAG_LUN_INHIBIT 2   /* default is to put device's lun into */ /* the 2nd byte of SCSI command */
#define SG_FLAG_MMAP_IO 4       /* selects memory mapped IO. Introduced in version 3.1.22 . May not be present in GNU library headders for some time */
#define SG_FLAG_NO_DXFER 0x10000 /* no transfer of kernel buffers to/from */ /* user space (debug indirect IO) */ /* following 'info' values are "or"-ed together */
#define SG_INFO_OK_MASK 0x1
#define SG_INFO_OK 0x0          /* no sense, host nor driver "noise" */
#define SG_INFO_CHECK 0x1       /* something abnormal happened */#define SG_INFO_DIRECT_IO_MASK 0x6
#define SG_INFO_INDIRECT_IO 0x0 /* data xfer via kernel buffers (or no xfer) */
#define SG_INFO_DIRECT_IO 0x2
#define SG_INFO_MIXED_IO 0x4    /* part direct, part indirect IO */

(来源: http://sg.danny.cz/sg/s_packet.html。)

使用“Direct IO”的方式执行SCSI命令

读写的数据保存在用户分配的buffer中,需要一次拷贝:

/* 0 -> successful, SG_LIB_SYNTAX_ERROR -> unable to build cdb,SG_LIB_CAT_UNIT_ATTENTION -> try again,SG_LIB_CAT_MEDIUM_HARD_WITH_INFO -> 'io_addrp' written to,SG_LIB_CAT_MEDIUM_HARD -> no info field,SG_LIB_CAT_NOT_READY, SG_LIB_CAT_ABORTED_COMMAND,-2 -> ENOMEM-1 other errors */
static int
sg_read_low(int sg_fd, unsigned char * buff, int blocks, int64_t from_block,int bs, const struct flags_t * ifp, int * diop,uint64_t * io_addrp)
{unsigned char rdCmd[MAX_SCSI_CDBSZ];unsigned char senseBuff[SENSE_BUFF_LEN];const unsigned char * sbp;struct sg_io_hdr io_hdr;int res, k, info_valid, slen;if (sg_build_scsi_cdb(rdCmd, ifp->cdbsz, blocks, from_block, 0,ifp->fua, ifp->dpo)) {fprintf(stderr, ME "bad rd cdb build, from_block=%" PRId64", blocks=%d\n", from_block, blocks);return SG_LIB_SYNTAX_ERROR;}memset(&io_hdr, 0, sizeof(struct sg_io_hdr));io_hdr.interface_id = 'S';io_hdr.cmd_len = ifp->cdbsz;io_hdr.cmdp = rdCmd;io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;io_hdr.dxfer_len = bs * blocks;io_hdr.dxferp = buff;io_hdr.mx_sb_len = SENSE_BUFF_LEN;io_hdr.sbp = senseBuff;io_hdr.timeout = DEF_TIMEOUT;io_hdr.pack_id = (int)from_block;if (diop && *diop)io_hdr.flags |= SG_FLAG_DIRECT_IO;if (verbose > 2) {fprintf(stderr, "    read cdb: ");for (k = 0; k < ifp->cdbsz; ++k)fprintf(stderr, "%02x ", rdCmd[k]);fprintf(stderr, "\n");}while (((res = ioctl(sg_fd, SG_IO, &io_hdr)) < 0) && (EINTR == errno));if (res < 0) {if (ENOMEM == errno)return -2;perror("reading (SG_IO) on sg device, error");return -1;}if (verbose > 2)fprintf(stderr, "      duration=%u ms\n", io_hdr.duration);res = sg_err_category3(&io_hdr);sbp = io_hdr.sbp;slen = io_hdr.sb_len_wr;switch (res) {case SG_LIB_CAT_CLEAN:break;case SG_LIB_CAT_RECOVERED:++recovered_errs;info_valid = sg_get_sense_info_fld(sbp, slen, io_addrp);if (info_valid) {fprintf(stderr, "    lba of last recovered error in this ""READ=0x%" PRIx64 "\n", *io_addrp);if (verbose > 1)sg_chk_n_print3("reading", &io_hdr, 1);} else {fprintf(stderr, "Recovered error: [no info] reading from ""block=0x%" PRIx64 ", num=%d\n", from_block, blocks);sg_chk_n_print3("reading", &io_hdr, verbose > 1);}break;case SG_LIB_CAT_ABORTED_COMMAND:case SG_LIB_CAT_UNIT_ATTENTION:sg_chk_n_print3("reading", &io_hdr, verbose > 1);return res;case SG_LIB_CAT_MEDIUM_HARD:if (verbose > 1)sg_chk_n_print3("reading", &io_hdr, verbose > 1);++unrecovered_errs;info_valid = sg_get_sense_info_fld(sbp, slen, io_addrp);/* MMC devices don't necessarily set VALID bit */if ((info_valid) || ((5 == ifp->pdt) && (*io_addrp > 0)))return SG_LIB_CAT_MEDIUM_HARD_WITH_INFO;else {fprintf(stderr, "Medium, hardware or blank check error but ""no lba of failure in sense\n");return res;}break;case SG_LIB_CAT_NOT_READY:++unrecovered_errs;if (verbose > 0)sg_chk_n_print3("reading", &io_hdr, verbose > 1);return res;case SG_LIB_CAT_ILLEGAL_REQ:if (5 == ifp->pdt) {    /* MMC READs can go down this path */struct sg_scsi_sense_hdr ssh;int ili;if (verbose > 1)sg_chk_n_print3("reading", &io_hdr, verbose > 1);if (sg_scsi_normalize_sense(sbp, slen, &ssh) &&(0x64 == ssh.asc) && (0x0 == ssh.ascq)) {if (sg_get_sense_filemark_eom_ili(sbp, slen, NULL, NULL,&ili) && ili) {info_valid = sg_get_sense_info_fld(sbp, slen, io_addrp);if (*io_addrp > 0) {++unrecovered_errs;return SG_LIB_CAT_MEDIUM_HARD_WITH_INFO;} elsefprintf(stderr, "MMC READ gave 'illegal mode for ""this track' and ILI but no LBA of failure\n");}++unrecovered_errs;return SG_LIB_CAT_MEDIUM_HARD;}}/* drop through */default:++unrecovered_errs;if (verbose > 0)sg_chk_n_print3("reading", &io_hdr, verbose > 1);return res;}if (diop && *diop &&((io_hdr.info & SG_INFO_DIRECT_IO_MASK) != SG_INFO_DIRECT_IO))*diop = 0;      /* flag that dio not done (completely) */sum_of_resids += io_hdr.resid;return 0;
}

(来源:src/sg_dd.c)

缓冲应该按照页面对齐:

    psz = getpagesize(); if (NULL == (alloc_bp = malloc(sz + psz)))  /* 'sz' bytes required */ exit(1);  /* out of memory */ buffp = (unsigned char *) (((unsigned long)alloc_bp + psz - 1) & (~(psz - 1)));

(来源: http://sg.danny.cz/sg/s_packet.html)

使用“MMap”的方式执行SCSI命令

读写的数据保存在驱动分配的一块内存中,不需要额外的拷贝数据:

/* 0 -> successful, SG_LIB_CAT_UNIT_ATTENTION, SG_LIB_SYNTAX_ERROR,* SG_LIB_CAT_NOT_READY, SG_LIB_CAT_MEDIUM_HARD, SG_LIB_CAT_ILLEGAL_REQ,* SG_LIB_CAT_ABORTED_COMMAND, -2 -> recoverable (ENOMEM),* -1 -> unrecoverable error */
static int
sg_read(int sg_fd, unsigned char * buff, int blocks, int64_t from_block,int bs, int cdbsz, int fua, int dpo, int do_mmap)
{unsigned char rdCmd[MAX_SCSI_CDBSZ];unsigned char senseBuff[SENSE_BUFF_LEN];struct sg_io_hdr io_hdr;int k, res;if (sg_build_scsi_cdb(rdCmd, cdbsz, blocks, from_block, 0, fua, dpo)) {fprintf(stderr, ME "bad rd cdb build, from_block=%" PRId64", blocks=%d\n", from_block, blocks);return SG_LIB_SYNTAX_ERROR;}memset(&io_hdr, 0, sizeof(struct sg_io_hdr));io_hdr.interface_id = 'S';io_hdr.cmd_len = cdbsz;io_hdr.cmdp = rdCmd;io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;io_hdr.dxfer_len = bs * blocks;if (! do_mmap)io_hdr.dxferp = buff;io_hdr.mx_sb_len = SENSE_BUFF_LEN;io_hdr.sbp = senseBuff;io_hdr.timeout = DEF_TIMEOUT;io_hdr.pack_id = (int)from_block;if (do_mmap)io_hdr.flags |= SG_FLAG_MMAP_IO;if (verbose > 2) {fprintf(stderr, "    read cdb: ");for (k = 0; k < cdbsz; ++k)fprintf(stderr, "%02x ", rdCmd[k]);fprintf(stderr, "\n");}#if 1while (((res = ioctl(sg_fd, SG_IO, &io_hdr)) < 0) && (EINTR == errno))sleep(1);if (res < 0) {perror(ME "SG_IO error (sg_read)");return -1;}
#elsewhile (((res = write(sg_fd, &io_hdr, sizeof(io_hdr))) < 0) &&(EINTR == errno));if (res < 0) {if (ENOMEM == errno)return -2;perror("reading (wr) on sg device, error");return -1;}while (((res = read(sg_fd, &io_hdr, sizeof(io_hdr))) < 0) &&(EINTR == errno));if (res < 0) {perror("reading (rd) on sg device, error");return -1;}
#endifif (verbose > 2)fprintf(stderr, "      duration=%u ms\n", io_hdr.duration);res =  sg_err_category3(&io_hdr);switch (res) {case SG_LIB_CAT_CLEAN:break;case SG_LIB_CAT_RECOVERED:sg_chk_n_print3("Reading, continuing", &io_hdr, verbose > 1);break;case SG_LIB_CAT_NOT_READY:case SG_LIB_CAT_MEDIUM_HARD:return res;case SG_LIB_CAT_ABORTED_COMMAND:case SG_LIB_CAT_UNIT_ATTENTION:case SG_LIB_CAT_ILLEGAL_REQ:default:sg_chk_n_print3("reading", &io_hdr, verbose > 1);return res;}sum_of_resids += io_hdr.resid;
#ifdef SG_DEBUGfprintf(stderr, "duration=%u ms\n", io_hdr.duration);
#endifreturn 0;
}...int
main(int argc, char * argv[])
{
...wrkMmap = (unsigned char *)mmap(NULL, in_res_sz,PROT_READ | PROT_WRITE, MAP_SHARED, infd, 0);if (MAP_FAILED == wrkMmap) {snprintf(ebuff, EBUFF_SZ,ME "error using mmap() on file: %s", inf);perror(ebuff);return SG_LIB_FILE_ERROR;
...if (wrkMmap) {wrkPos = wrkMmap;
#ifdef SG_WANT_SHARED_MMAP_IOif (! (mmap_shareable && out_flags.smmap &&  (FT_SG == out_type)))mmap_shareable = 0;
#endif} else {
...if (FT_SG == in_type) {ret = sg_read(infd, wrkPos, blocks, skip, blk_sz, scsi_cdbsz_in,in_flags.fua, in_flags.dpo, 1);if ((SG_LIB_CAT_UNIT_ATTENTION == ret) ||(SG_LIB_CAT_ABORTED_COMMAND == ret)) {fprintf(stderr, "Unit attention or aborted command, ""continuing (r)\n");ret = sg_read(infd, wrkPos, blocks, skip, blk_sz,scsi_cdbsz_in, in_flags.fua, in_flags.dpo, 1);}if (0 != ret) {fprintf(stderr, "sg_read failed, skip=%" PRId64 "\n", skip);break;}elsein_full += blocks;
...

(来源:src/sgm_dd.c)

可以使用SG_SET_RESERVED_SIZE ioctl命令来设置内核buffer的大小,这个buffer是一个fd对应一个。

SG工具包(sg3_utils)

概述

sg3_utils软件包支持50多种SCSI命令,支持所有SPC、SBC和MMC标准中的命令,基本格式为:

UTILITY_NAME [OPTIONS] DEVICE

其中的“DEVICE”可以是“/dev/sda”, “/dev/scd0”, “/dev/st0”或者/dev/hdd,在2.6.28之后的版本中还支持“/dev/bsg/3:0:0:0”这类设备名。

每个命令都有详细的man手册,此处不再详述。

一些简单的例子

(“/dev/sde”和“/dev/sdf”是连接至一个使用“Linux tgt”软件包搭建的“iSCSI Target”服务上的一个LUN的两条路径)

  • 查询设备的基本信息:
$ sg_inq /dev/sde
standard INQUIRY:PQual=0  Device_type=0  RMB=0  version=0x05  [SPC-3][AERC=0]  [TrmTsk=0]  NormACA=0  HiSUP=1  Resp_data_format=2SCCS=0  ACC=0  TPGS=0  3PC=0  Protect=0  [BQue=0]EncServ=0  MultiP=0  [MChngr=0]  [ACKREQQ=0]  Addr16=0[RelAdr=0]  WBus16=0  Sync=0  Linked=0  [TranDis=0]  CmdQue=1[SPI: Clocking=0x0  QAS=0  IUS=0]length=66 (0x42)   Peripheral device type: diskVendor identification: IET     Product identification: VIRTUAL-DISKProduct revision level: 0001Unit serial number:                               beaf21

可以看到该设备采用SPC-3标准,说明这个设备支持新的PRs命令,且废弃了旧的“RESERVE”和“RELEASE”命令。

  • 查询设备的基本信息的同时,查看可解释的描述信息:
$ sg_inq -d /dev/sde
standard INQUIRY:PQual=0  Device_type=0  RMB=0  version=0x05  [SPC-3][AERC=0]  [TrmTsk=0]  NormACA=0  HiSUP=1  Resp_data_format=2SCCS=0  ACC=0  TPGS=0  3PC=0  Protect=0  [BQue=0]EncServ=0  MultiP=0  [MChngr=0]  [ACKREQQ=0]  Addr16=0[RelAdr=0]  WBus16=0  Sync=0  Linked=0  [TranDis=0]  CmdQue=1[SPI: Clocking=0x0  QAS=0  IUS=0]length=66 (0x42)   Peripheral device type: diskVendor identification: IET     Product identification: VIRTUAL-DISKProduct revision level: 0001Unit serial number:                               beaf21Version descriptors:SBC-3 (no version claimed)iSCSI (no version claimed)SPC-3 (no version claimed)
  • 查看设备的VPD(Vital Product Data,重要产品数据)数据:
$ sg_inq -e /dev/sde
VPD INQUIRY, page code=0x00:[PQual=0  Peripheral device type: disk]Supported VPD pages:0x0    Supported VPD pages0x80 Unit serial number0x83  Device identification0xb0   Block limits (sbc2)0xb2 Logical block provisioning (sbc3)

或者:

$ sg_vpd /dev/sde
Supported VPD pages VPD page:Supported VPD pages [sv]Unit serial number [sn]Device identification [di]Block limits (SBC) [bl]Logical block provisioning (SBC) [lbpv]

可以看到该设备含有5个参数页。

  • 查看lbpv参数页:
$ sg_vpd --page=lbp /dev/sde
abbreviation doesn't match a VPD page
available VPD pages:ai         0x89      ATA information (SAT)aod        0x82      ASCII implemented operating definition (obsolete)adsn       0xb3      Automation device serial number (SSC)bl         0xb0      Block limits (SBC)bdc        0xb1      Block device characteristics (SBC)cfa        0x8c      CFA profile informationdc         0x8b      Device constituentsdi         0x83      Device identificationdi_asis    0x83      Like 'di' but designators ordered as founddi_lu      0x83      Device identification, lu onlydi_port    0x83      Device identification, target port onlydi_target  0x83      Device identification, target device onlydtde       0xb4      Data transfer device element address (SSC)ei         0x86      Extended inquiry dataiod        0x81      Implemented operating definition (obsolete)lbpv       0xb2      Logical block provisioning (SBC)mas        0xb1      Manufacturer assigned serial number (SSC)masa       0xb1      Manufacturer assigned serial number (ADC)mna        0x85      Management network addressesmpp        0x87      Mode page policyoi         0xb0      OSD informationpc         0x8a      Power conditionpsm        0x8d      Power consumptionpslu       0x90      Protocol-specific logical unit informationpspo       0x91      Protocol-specific port informationref        0xb3      Referrals (SBC)sad        0xb0      Sequential access device capabilities (SSC)sii        0x84      Software interface identificationsinq       -1        Standard inquiry responsesn         0x80      Unit serial numbersp         0x88      SCSI portsst         0xb1      Security token (OSD)sv         0x00      Supported VPD pagestas        0xb2      TapeAlert supported flags (SSC)tpc        0x8f      Third party copyVendor specific VPD pages:datc       0xc1,0      Date code (Seagate)devb       0xc3,0      Device behavior (Seagate)edid       0xc8,0      Extended device identification (RDAC)prm4       0xc3,1      Feature Parameters (RDAC)firm       0xc0,0      Firmware numbers (Seagate)fwr4       0xc1,1      Firmware version (RDAC)hp3par     0xc0,2      Volume information (HP/3PAR)hwr4       0xc0,3      Hardware version (RDAC)jump       0xc2,0      Jump setting (Seagate)rvsi       0xca,0      Replicated volume source identifier (RDAC)said       0xd0,0      Storage array world wide name (RDAC)subs       0xc4,0      Subsystem identifier (RDAC)swr4       0xc2,1      Software version (RDAC)upr        0xc0,1      Unit path report (EMC)vac1       0xc9,0      Volume access control (RDAC)$ sg_vpd --page=lbpv /dev/sde
Logical block provisioning VPD page (SBC):Unmap command supported (LBPU): 0Write same (16) with unmap bit supported (LBWS): 0Write same (10) with unmap bit supported (LBWS10): 0Logical block provisioning read zeros (LBPRZ): 0Anchored LBAs supported (ANC_SUP): 0Threshold exponent: 0Descriptor present (DP): 0Provisioning type: 0

当输入错误的参数页名称时,命令会打印所有可以使用的参数页名称,当然,并不是所有设备都支持全部这些参数页。

  • 查看当前系统上有哪些SCSI设备及其映射关系:
$ cat /proc/scsi/scsi
Attached devices:
Host: scsi2 Channel: 00 Id: 00 Lun: 00Vendor: VMware,  Model: VMware Virtual S Rev: 1.0 Type:   Direct-Access                    ANSI  SCSI revision: 02
Host: scsi2 Channel: 00 Id: 01 Lun: 00Vendor: VMware,  Model: VMware Virtual S Rev: 1.0 Type:   Direct-Access                    ANSI  SCSI revision: 02
Host: scsi2 Channel: 00 Id: 02 Lun: 00Vendor: VMware,  Model: VMware Virtual S Rev: 1.0 Type:   Direct-Access                    ANSI  SCSI revision: 02
Host: scsi2 Channel: 00 Id: 03 Lun: 00Vendor: VMware,  Model: VMware Virtual S Rev: 1.0 Type:   Direct-Access                    ANSI  SCSI revision: 02
Host: scsi1 Channel: 00 Id: 00 Lun: 00Vendor: NECVMWar Model: VMware IDE CDR10 Rev: 1.00Type:   CD-ROM                           ANSI  SCSI revision: 05
Host: scsi3 Channel: 00 Id: 00 Lun: 00Vendor: IET      Model: Controller       Rev: 0001Type:   RAID                             ANSI  SCSI revision: 05
Host: scsi3 Channel: 00 Id: 00 Lun: 01Vendor: IET      Model: VIRTUAL-DISK     Rev: 0001Type:   Direct-Access                    ANSI  SCSI revision: 05
Host: scsi4 Channel: 00 Id: 00 Lun: 00Vendor: IET      Model: Controller       Rev: 0001Type:   RAID                             ANSI  SCSI revision: 05
Host: scsi8 Channel: 00 Id: 00 Lun: 00Vendor: IET      Model: Controller       Rev: 0001Type:   RAID                             ANSI  SCSI revision: 05
Host: scsi4 Channel: 00 Id: 00 Lun: 01Vendor: IET      Model: VIRTUAL-DISK     Rev: 0001Type:   Direct-Access                    ANSI  SCSI revision: 05
Host: scsi8 Channel: 00 Id: 00 Lun: 01Vendor: IET      Model: VIRTUAL-DISK     Rev: 0001Type:   Direct-Access                    ANSI  SCSI revision: 05
Host: scsi5 Channel: 00 Id: 00 Lun: 00Vendor: IET      Model: Controller       Rev: 0001Type:   RAID                             ANSI  SCSI revision: 05
Host: scsi6 Channel: 00 Id: 00 Lun: 00Vendor: IET      Model: Controller       Rev: 0001Type:   RAID                             ANSI  SCSI revision: 05
Host: scsi5 Channel: 00 Id: 00 Lun: 01Vendor: IET      Model: VIRTUAL-DISK     Rev: 0001Type:   Direct-Access                    ANSI  SCSI revision: 05
Host: scsi6 Channel: 00 Id: 00 Lun: 01Vendor: IET      Model: VIRTUAL-DISK     Rev: 0001Type:   Direct-Access                    ANSI  SCSI revision: 05
Host: scsi9 Channel: 00 Id: 00 Lun: 00Vendor: IET      Model: Controller       Rev: 0001Type:   RAID                             ANSI  SCSI revision: 05
Host: scsi9 Channel: 00 Id: 00 Lun: 01Vendor: IET      Model: VIRTUAL-DISK     Rev: 0001Type:   Direct-Access                    ANSI  SCSI revision: 05

或者:

$ sg_scan
/dev/sg0: scsi2 channel=0 id=0 lun=0
/dev/sg1: scsi2 channel=0 id=1 lun=0
/dev/sg2: scsi2 channel=0 id=2 lun=0
/dev/sg3: scsi2 channel=0 id=3 lun=0
/dev/sg4: scsi1 channel=0 id=0 lun=0 [em]
/dev/sg5: scsi3 channel=0 id=0 lun=0
/dev/sg6: scsi3 channel=0 id=0 lun=1
/dev/sg7: scsi4 channel=0 id=0 lun=0
/dev/sg8: scsi8 channel=0 id=0 lun=0
/dev/sg9: scsi4 channel=0 id=0 lun=1
/dev/sg10: scsi9 channel=0 id=0 lun=0
/dev/sg11: scsi8 channel=0 id=0 lun=1
/dev/sg12: scsi5 channel=0 id=0 lun=0
/dev/sg13: scsi9 channel=0 id=0 lun=1
/dev/sg14: scsi6 channel=0 id=0 lun=0
/dev/sg15: scsi5 channel=0 id=0 lun=1
/dev/sg16: scsi6 channel=0 id=0 lun=1

或者:

$ sg_scan -i
/dev/sg0: scsi2 channel=0 id=0 lun=0VMware,   VMware Virtual S  1.0  [rmb=0 cmdq=1 pqual=0 pdev=0x0]
/dev/sg1: scsi2 channel=0 id=1 lun=0VMware,   VMware Virtual S  1.0  [rmb=0 cmdq=1 pqual=0 pdev=0x0]
/dev/sg2: scsi2 channel=0 id=2 lun=0VMware,   VMware Virtual S  1.0  [rmb=0 cmdq=1 pqual=0 pdev=0x0]
/dev/sg3: scsi2 channel=0 id=3 lun=0VMware,   VMware Virtual S  1.0  [rmb=0 cmdq=1 pqual=0 pdev=0x0]
/dev/sg4: scsi1 channel=0 id=0 lun=0 [em]NECVMWar  VMware IDE CDR10  1.00 [rmb=1 cmdq=0 pqual=0 pdev=0x5]
/dev/sg5: scsi3 channel=0 id=0 lun=0IET       Controller  0001 [rmb=0 cmdq=1 pqual=0 pdev=0xc]
/dev/sg6: scsi3 channel=0 id=0 lun=1IET       VIRTUAL-DISK  0001 [rmb=0 cmdq=1 pqual=0 pdev=0x0]
/dev/sg7: scsi4 channel=0 id=0 lun=0IET       Controller  0001 [rmb=0 cmdq=1 pqual=0 pdev=0xc]
/dev/sg8: scsi8 channel=0 id=0 lun=0IET       Controller  0001 [rmb=0 cmdq=1 pqual=0 pdev=0xc]
/dev/sg9: scsi4 channel=0 id=0 lun=1IET       VIRTUAL-DISK  0001 [rmb=0 cmdq=1 pqual=0 pdev=0x0]
/dev/sg10: scsi9 channel=0 id=0 lun=0IET       Controller  0001 [rmb=0 cmdq=1 pqual=0 pdev=0xc]
/dev/sg11: scsi8 channel=0 id=0 lun=1IET       VIRTUAL-DISK  0001 [rmb=0 cmdq=1 pqual=0 pdev=0x0]
/dev/sg12: scsi5 channel=0 id=0 lun=0IET       Controller  0001 [rmb=0 cmdq=1 pqual=0 pdev=0xc]
/dev/sg13: scsi9 channel=0 id=0 lun=1IET       VIRTUAL-DISK  0001 [rmb=0 cmdq=1 pqual=0 pdev=0x0]
/dev/sg14: scsi6 channel=0 id=0 lun=0IET       Controller  0001 [rmb=0 cmdq=1 pqual=0 pdev=0xc]
/dev/sg15: scsi5 channel=0 id=0 lun=1IET       VIRTUAL-DISK  0001 [rmb=0 cmdq=1 pqual=0 pdev=0x0]
/dev/sg16: scsi6 channel=0 id=0 lun=1IET       VIRTUAL-DISK  0001 [rmb=0 cmdq=1 pqual=0 pdev=0x0]

或者:

$ sg_map
/dev/sg0  /dev/sda
/dev/sg1  /dev/sdb
/dev/sg2  /dev/sdc
/dev/sg3  /dev/sdd
/dev/sg4  /dev/sr0
/dev/sg5
/dev/sg6  /dev/sde
/dev/sg7
/dev/sg8
/dev/sg9  /dev/sdf
/dev/sg10
/dev/sg11  /dev/sdg
/dev/sg12
/dev/sg13  /dev/sdh
/dev/sg14
/dev/sg15  /dev/sdi
/dev/sg16  /dev/sdj
  • 查看sg_persist命令帮助:
$ sg_persist -h
Usage: sg_persist [OPTIONS] [DEVICE]where OPTIONS include:--alloc-length=LEN|-l LEN    allocation length hex value (used withPR In only) (default: 8192 (2000 in hex))--clear|-C                 PR Out: Clear--device=DEVICE|-d DEVICE    query or change DEVICE--help|-h                  output this usage message--hex|-H                   output response in hex--in|-i                    request PR In command (default)--no-inquiry|-n            skip INQUIRY (default: do INQUIRY)--out|-o                   request PR Out command--param-alltgpt|-Y         PR Out parameter 'ALL_TG_PT'--param-aptpl|-Z           PR Out parameter 'APTPL'--param-rk=RK|-K RK        PR Out parameter reservation key(RK is in hex)--param-sark=SARK|-S SARK    PR Out parameter service actionreservation key (SARK is in hex)--preempt|-P               PR Out: Preempt--preempt-abort|-A         PR Out: Preempt and Abort--prout-type=TYPE|-T TYPE    PR Out command type--read-full-status|-s      PR In: Read Full Status--read-keys|-k             PR In: Read Keys--read-reservation|-r      PR In: Read Reservation--read-status|-s           PR In: Read Full Status--register|-G              PR Out: Register--register-ignore|-I       PR Out: Register and Ignore--register-move|-M         PR Out: Register and Move--relative-target-port=RTPI|-Q RTPI    relative target port identifierfor '--register-move'--release|-L               PR Out: Release--report-capabilities|-c   PR In: Report Capabilities--reserve|-R               PR Out: Reserve--transport-id=TIDS|-X TIDS    one or more TransportIDs canbe given in several forms--unreg|-U                 optional with PR Out Register and Move--verbose|-v               output additional debug information--version|-V               output version string-?                         output this usage messagePerforms a SCSI PERSISTENT RESERVE (IN or OUT) command
  • 查询块设备的功能特性:
$ sg_persist -c /dev/sde -vvv
open /dev/sde with flags=0x800inquiry cdb: 12 00 00 00 24 00 duration=1 msIET       VIRTUAL-DISK  0001Peripheral device type: disk
open /dev/sde with flags=0x802Persistent Reservation In cmd: 5e 02 00 00 00 00 00 20 00 00 duration=0 mspersistent reservation in: pass-through requested 8192 bytes but got 8 bytespersistent reserve in: response00 08 00 80 ea 01 00 00
Report capabilities response:Compatible Reservation Handling(CRH): 0Specify Initiator Ports Capable(SIP_C): 0All Target Ports Capable(ATP_C): 0Persist Through Power Loss Capable(PTPL_C): 0Type Mask Valid(TMV): 1Allow Commands: 0Persist Through Power Loss Active(PTPL_A): 0Support indicated in Type mask:Write Exclusive, all registrants: 1Exclusive Access, registrants only: 1Write Exclusive, registrants only: 1Exclusive Access: 1Write Exclusive: 1Exclusive Access, all registrants: 1

如果不支持PRs功能,则会直接返回错误。同时这里面的参数描述显示可能不全,可根据“persistent reserve in: response”下面的数据参照PRs命令规范进行对照查看。

  • 查看设备上有哪些“Registered Reservation Key”:
$ sg_persist -k /dev/sde -vvv
open /dev/sde with flags=0x800inquiry cdb: 12 00 00 00 24 00 duration=0 msIET       VIRTUAL-DISK  0001Peripheral device type: disk
open /dev/sde with flags=0x802Persistent Reservation In cmd: 5e 00 00 00 00 00 00 20 00 00 duration=1 mspersistent reservation in: pass-through requested 8192 bytes but got 16 bytespersistent reserve in: response00 00 00 07 00 00 00 08  00 00 00 00 00 00 0a bcPR generation=0x7, 1 registered reservation key follows:0xabc
  • 查看设备上的“Persistent Reservation”状态:
$ sg_persist -r /dev/sde -vvv
open /dev/sde with flags=0x800inquiry cdb: 12 00 00 00 24 00 duration=0 msIET       VIRTUAL-DISK  0001Peripheral device type: disk
open /dev/sde with flags=0x802Persistent Reservation In cmd: 5e 01 00 00 00 00 00 20 00 00 duration=0 mspersistent reservation in: pass-through requested 8192 bytes but got 8 bytespersistent reserve in: response00 00 00 07 00 00 00 00PR generation=0x7, there is NO reservation held
  • 注册“Reservation Key”,

在节点1上的两条链路注册“abc”:

$ sg_persist --out --register --param-sark=abc /dev/sdeIET       VIRTUAL-DISK  0001Peripheral device type: disk$ sg_persist --out --register --param-sark=abc /dev/sdfIET       VIRTUAL-DISK  0001Peripheral device type: disk$ sg_persist /dev/sde
>> No service action given; assume Persistent Reserve In command
>> with Read Keys service actionIET       VIRTUAL-DISK  0001Peripheral device type: diskPR generation=0x16, 2 registered reservation keys follow:0xabc0xabc

在节点2上的两条链路注册“123”:

$ sg_persist --out --register --param-sark=123 /dev/sdeIET       VIRTUAL-DISK  0001Peripheral device type: disk$ sg_persist --out --register --param-sark=123 /dev/sdfIET       VIRTUAL-DISK  0001Peripheral device type: disk$ sg_persist /dev/sde
>> No service action given; assume Persistent Reserve In command
>> with Read Keys service actionIET       VIRTUAL-DISK  0001Peripheral device type: diskPR generation=0x18, 4 registered reservation keys follow:0xabc0xabc0x1230x123
  • 获取“Exclusive Access”类型的“Persistent Reservation”,

在节点1上使“abc”获取“Exclusive Access”类型的“Persistent Reservation”,并进行读取:

$ sg_persist --out --reserve --prout-type=3 --param-rk=abc /dev/sdeIET       VIRTUAL-DISK  0001Peripheral device type: disk$ sg_persist -r /dev/sdeIET       VIRTUAL-DISK  0001Peripheral device type: diskPR generation=0x18, Reservation follows:Key=0xabcscope: LU_SCOPE,  type: Exclusive Access$ sg_persist -r /dev/sdfIET       VIRTUAL-DISK  0001Peripheral device type: diskPR generation=0x18, Reservation follows:Key=0xabcscope: LU_SCOPE,  type: Exclusive Access$ dd if=/dev/sde of=/dev/null bs=512 count=1 iflag=direct
记录了1+0 的读入
记录了1+0 的写出
512字节(512 B)已复制,0.000620821 秒,825 kB/秒$ dd if=/dev/sdf of=/dev/null bs=512 count=1 iflag=direct
dd: 读取"/dev/sdf" 时出错: 输入/输出错误
记录了0+0 的读入
记录了0+0 的写出
0字节(0 B)已复制,0.000495205 秒,0.0 kB/秒

在节点2上进行读取操作:

$ dd if=/dev/sde of=/dev/null bs=512 count=1 iflag=direct
dd: 读取"/dev/sde" 时出错: 输入/输出错误
记录了0+0 的读入
记录了0+0 的写出
0字节(0 B)已复制,0.000766011 秒,0.0 kB/秒$ dd if=/dev/sdf of=/dev/null bs=512 count=1 iflag=direct
dd: 读取"/dev/sdf" 时出错: 输入/输出错误
记录了0+0 的读入
记录了0+0 的写出
0字节(0 B)已复制,0.000623766 秒,0.0 kB/秒

释放“Persistent Reservation”,并在节点1上进行读取:

$ sg_persist --out --release --prout-type=3 --param-rk=abc /dev/sdeIET       VIRTUAL-DISK  0001Peripheral device type: disk$ sg_persist -k /dev/sdeIET       VIRTUAL-DISK  0001Peripheral device type: diskPR generation=0x18, 4 registered reservation keys follow:0xabc0xabc0x1230x123$ sg_persist -r /dev/sdeIET       VIRTUAL-DISK  0001Peripheral device type: diskPR generation=0x18, there is NO reservation held$ dd if=/dev/sde of=/dev/null bs=512 count=1 iflag=direct
记录了1+0 的读入
记录了1+0 的写出
512字节(512 B)已复制,0.000321204 秒,1.6 MB/秒$ dd if=/dev/sdf of=/dev/null bs=512 count=1 iflag=direct
记录了1+0 的读入
记录了1+0 的写出
512字节(512 B)已复制,0.000342411 秒,1.5 MB/秒

在节点2上进行读取操作:

$ dd if=/dev/sde of=/dev/null bs=512 count=1 iflag=direct
记录了1+0 的读入
记录了1+0 的写出
512字节(512 B)已复制,0.00289339 秒,177 kB/秒$ dd if=/dev/sdf of=/dev/null bs=512 count=1 iflag=direct
记录了1+0 的读入
记录了1+0 的写出
512字节(512 B)已复制,0.000511372 秒,1.0 MB/秒
  • 获取“Exclusive Access − Registrants Only”类型的“Persistent Reservation”,

在节点1上使“abc”获取“Exclusive Access − Registrants Only”类型的“Persistent Reservation”,并进行读取:

$ sg_persist --out --reserve --prout-type=6 --param-rk=abc /dev/sdeIET       VIRTUAL-DISK  0001Peripheral device type: disk
$ sg_persist -r /dev/sdeIET       VIRTUAL-DISK  0001Peripheral device type: diskPR generation=0x18, Reservation follows:Key=0xabcscope: LU_SCOPE,  type: Exclusive Access, registrants only$ dd if=/dev/sde of=/dev/null bs=512 count=1 iflag=direct
记录了1+0 的读入
记录了1+0 的写出
512字节(512 B)已复制,0.000351323 秒,1.5 MB/秒
$ dd if=/dev/sdf of=/dev/null bs=512 count=1 iflag=direct
记录了1+0 的读入
记录了1+0 的写出
512字节(512 B)已复制,0.000422081 秒,1.2 MB/秒

在节点2上进行读取操作:

$ dd if=/dev/sde of=/dev/null bs=512 count=1 iflag=direct
记录了1+0 的读入
记录了1+0 的写出
512字节(512 B)已复制,0.00289339 秒,177 kB/秒$ dd if=/dev/sdf of=/dev/null bs=512 count=1 iflag=direct
记录了1+0 的读入
记录了1+0 的写出
512字节(512 B)已复制,0.000511372 秒,1.0 MB/秒
  • 在同一个LUN上的多个LV上进行测试:
$ sg_persist -k /dev/storage/dmd-test01 IET       VIRTUAL-DISK  0001Peripheral device type: diskPR generation=0x0, there are NO registered reservation keys$ sg_persist --out --register --param-sark=abc /dev/storage/dmd-test01 IET       VIRTUAL-DISK  0001Peripheral device type: disk$ sg_persist -k /dev/storage/dmd-test01IET       VIRTUAL-DISK  0001Peripheral device type: diskPR generation=0x1, 1 registered reservation key follows:0xabc$ sg_persist -k /dev/storage/dmd-test02IET       VIRTUAL-DISK  0001Peripheral device type: diskPR generation=0x1, 1 registered reservation key follows:0xabc$ dd if=/dev/storage/dmd-test02 of=/dev/null bs=512 count=1 iflag=direct
记录了1+0 的读入
记录了1+0 的写出
512字节(512 B)已复制,0.00127375 秒,402 kB/秒$ sg_persist --out --reserve --prout-type=3 --param-rk=abc /dev/storage/dmd-test01IET       VIRTUAL-DISK  0001Peripheral device type: disk$ sg_persist -r /dev/storage/dmd-test01IET       VIRTUAL-DISK  0001Peripheral device type: diskPR generation=0xb, Reservation follows:Key=0xabcscope: LU_SCOPE,  type: Exclusive Access$ sg_persist -r /dev/storage/dmd-test02IET       VIRTUAL-DISK  0001Peripheral device type: diskPR generation=0xb, Reservation follows:Key=0xabcscope: LU_SCOPE,  type: Exclusive Access$ dd if=/dev/storage/dmd-test02 of=/dev/null bs=512 count=1 iflag=direct
记录了1+0 的读入
记录了1+0 的写出
512字节(512 B)已复制,0.000892315 秒,574 kB/秒$ dd if=/dev/storage/dmd-test01 of=/dev/null bs=512 count=1 iflag=direct
记录了1+0 的读入
记录了1+0 的写出
512字节(512 B)已复制,0.000615345 秒,832 kB/秒
  • 反注册“Reservation Key”:
$ sg_persist --out --register --param-rk=abc /dev/sdeIET       VIRTUAL-DISK  0001Peripheral device type: disk$ sg_persist /dev/sde
>> No service action given; assume Persistent Reserve In command
>> with Read Keys service actionIET       VIRTUAL-DISK  0001Peripheral device type: diskPR generation=0x10, there are NO registered reservation keys

SCSI PRs命令研究总结3 - Linux中的SCSI相关实现相关推荐

  1. SCSI PRs命令研究总结1 - SCSI标准和架构

    SCSI-2的标准与SCSI-3的标准并没有本质的区别,只是SCSI-3的标准进行了全面的重写,组织更加合理. SCSI-3标准组成 从SCSI-3开始,SCSI的标准主要有5大部分: 架构模型(SC ...

  2. SCSI PRs命令研究总结2 - PRs命令规范

    Persistent Reservations(PRs)概述 PRs包含"PERSISTENT RESERVE IN"和"PERSISTENT RESERVE OUT&q ...

  3. linux xargs命令_如何在Linux中使用xargs命令?

    linux xargs命令 The xargs command allows us to pass the output of one command as the input for another ...

  4. echo命令详细解析(linux中超级详细,图文展示)

    echo命令详细解析(linux中超级详细,图文展示) echo作为最基本,最常用的命令,在初学linux,或运维操作中,有着广泛性的使用:特别是在写shell脚本的时候,更是会经常性的用到. 虽然e ...

  5. The driver has not received any packets from the server.(linux中关于mysql相关命令)

    原因: 1.呃呃.重启服务器,没有重新启动mysql; 2.如果还不能连接可能是3306是不允许进行远程连接的,所以在防火墙中设置3306开启远程服务: /sbin/iptables -I INPUT ...

  6. linux中grep命令查找目录下,linux中查找grep与find命令的使用

    在日常工作中,我们常常会在自己的电脑寻找某些不知道放在哪里的私密文件,通常我们会在资源管理器的搜索栏里输入一些关键字去帮助我们快速去定位查找该文件.在linux系统中也有这样的功能,只不过在linux ...

  7. linux系统md5sum命令用不了,Linux中md5sum命令起什么作用呢?

    摘要: 下文讲述Linux中md5sum命令的功能说明,如下所示: md5sum命令功能: 用于为一个文件生成其内容的MD5值, 此命令的原理是对文件的内容进行校验, 生成文件内容的MD5值 此方式常 ...

  8. linux命令 socket,如何从linux中的命令行向socket.io websocket发送消息?

    是否可以使用linux中的命令行向我的localhost服务器(节点)发送socket.io消息?我不确定这是否可行--从稀缺的谷歌搜索结果来看,我猜这不可能或不复杂-- 我的socket.io代码如 ...

  9. linux使用find命令_如何在Linux中使用FIND

    linux使用find命令 在最近的Opensource.com文章中 ,刘易斯·考尔斯介绍了find命令. 在日常工具箱中, find是功能更强大,更灵活的命令行程序之一,因此值得花一些时间在上面. ...

最新文章

  1. 中国互联网+户外广告行业商业模式创新与投资机会深度研究报告
  2. 【linux命令】readelf工具中英文说明
  3. AIX 访问Linux NFS共享错误案例
  4. unused import statement
  5. 2017年天津市大学生数学竞赛试题 (理工类)
  6. 在asp.net中调用process.start执行程序
  7. Any-Proxy在线反向代理源码
  8. 觉得Win 10不如WP好?微软确认可以降级
  9. 双机热备、双机互备与 双机双工的区别
  10. Javascript特效代码大全(420个)(转)
  11. windows下grep的安装与使用
  12. java基础笔试题(50题)
  13. 通行宝通过注册:年营收5.9亿拟募资5.6亿 腾讯云与上汽是股东
  14. 网易有道一面9.16(45min)
  15. java模拟器修改游戏分辨率_海马玩模拟器修改分辨率DPI和隐藏虚拟按键的方法...
  16. mysql中两根竖线什么意思_五线谱中两根竖线是什么意思?
  17. 当年明月 Vs. 阎崇年
  18. 文件新旧判断和字符串判断
  19. Java DecimalFormat 格式化数字,取2位小数,按位取小数,按要求格式化小数 float,double,int,等类型都支持
  20. 这本书为什么会被誉为Spring开发百科全书(文末附带源码视频)

热门文章

  1. web前端实训作业 html+css+javascript 水果超市网页设计实例 企业网站制作
  2. oracle 用户权限批量授予
  3. 迪士尼2016年压轴巨作---《海洋奇缘》观后感
  4. jsp页面如何调用本机的应用程序?例如c:/netterm.exe?(转载)
  5. 【git学习】git clone 出错 error:1407742E:SSL routines:SSL23_GET_SERVER_HELLO:tlsv1 alert protocol version
  6. 使用命令行激活window10 亲测有效【不要修改命令】
  7. 计算机丢失wswool.dll什么意思,如何修复Windows 10中丢失的DLL文件
  8. 有个疑问--RTOS系统中,低优先级任务什么时候得到cpu去运行
  9. Game 迷城的国度 Next(类似暗黑的游戏)
  10. 计算机核心论文投稿的一点碎碎念