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, cdwriters, applications that readcd audio digitally and scanners. Sg can also be used for less usual tasks performed on disks, tapesand cdroms. Sg is a character device driver which, in some contexts, gives it advantages over block device drivers such as sd andsr. 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命令的数据结构
typedefstructsg_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 */typedefstructsg_io_hdr{int interface_id; /* [i] 'S' for SCSI generic (required) */int dxfer_direction; /* [i] data transfer direction */unsignedchar cmd_len; /* [i] SCSI command length ( <= 16 bytes) */unsignedchar mx_sb_len; /* [i] max length to write to sbp */unsigned short iovec_count; /* [i] 0 implies no scatter gather */unsignedint dxfer_len; /* [i] byte count of data transfer */void * dxferp; /* [i] [*io] points to data transfer memory or scatter gather list */unsignedchar * cmdp; /* [i] [*i] points to SCSI command to perform */unsignedchar * sbp; /* [i] [*o] points to sense_buffer memory */unsignedint timeout; /* [i] MAX_UINT->no timeout (unit: millisec) */unsignedint flags; /* [i] 0 -> default, see SG_FLAG... */int pack_id; /* [i->o] unused internally (normally) */void * usr_ptr; /* [i->o] unused internally */unsignedchar status; /* [o] scsi status */unsignedchar masked_status;/* [o] shifted, masked scsi status */unsignedchar msg_status; /* [o] messaging level data (optional) */unsignedchar 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 */unsignedint duration; /* [o] time taken (unit: millisec) */unsignedint 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 */staticintsg_read_low(int sg_fd, unsignedchar * buff, int blocks, int64_t from_block,int bs, const struct flags_t * ifp, int * diop,uint64_t * io_addrp){unsignedchar rdCmd[MAX_SCSI_CDBSZ];unsignedchar senseBuff[SENSE_BUFF_LEN];constunsignedchar * sbp;structsg_io_hdrio_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 */structsg_scsi_sense_hdrssh;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;return0;}
(来源:src/sg_dd.c)
缓冲应该按照页面对齐:
psz = getpagesize(); if (NULL == (alloc_bp = malloc(sz + psz))) /* 'sz' bytes required */exit(1); /* out of memory */ buffp = (unsignedchar *) (((unsignedlong)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 */staticintsg_read(int sg_fd, unsignedchar * buff, int blocks, int64_t from_block,int bs, int cdbsz, int fua, int dpo, int do_mmap){unsignedchar rdCmd[MAX_SCSI_CDBSZ];unsignedchar senseBuff[SENSE_BUFF_LEN];structsg_io_hdrio_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);#endifreturn0;}...intmain(int argc, char * argv[]){... wrkMmap = (unsignedchar *)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; }else in_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/sdestandard INQUIRY: PQual=0 Device_type=0 RMB=0 version=0x05 [SPC-3] [AERC=0] [TrmTsk=0] NormACA=0 HiSUP=1 Resp_data_format=2 SCCS=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: disk Vendor identification: IET Product identification: VIRTUAL-DISK Product revision level: 0001 Unit serial number: beaf21
可以看到该设备采用SPC-3标准,说明这个设备支持新的PRs命令,且废弃了旧的“RESERVE”和“RELEASE”命令。
$ sg_inq -d /dev/sdestandard INQUIRY: PQual=0 Device_type=0 RMB=0 version=0x05 [SPC-3] [AERC=0] [TrmTsk=0] NormACA=0 HiSUP=1 Resp_data_format=2 SCCS=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: disk Vendor identification: IET Product identification: VIRTUAL-DISK Product revision level: 0001 Unit serial number: beaf21 Version descriptors: SBC-3 (no version claimed) iSCSI (no version claimed) SPC-3 (no version claimed)
- 查看设备的VPD(Vital Product Data,重要产品数据)数据:
$ sg_inq -e /dev/sdeVPD INQUIRY, page code=0x00: [PQual=0 Peripheral device type: disk] Supported VPD pages: 0x0 Supported VPD pages 0x80 Unit serial number 0x83 Device identification 0xb0 Block limits (sbc2) 0xb2 Logical block provisioning (sbc3)
或者:
$ sg_vpd /dev/sdeSupported 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个参数页。
$ sg_vpd --page=lbp /dev/sdeabbreviation doesn't match a VPD pageavailable 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 information dc 0x8b Device constituents di 0x83 Device identification di_asis 0x83 Like 'di' but designators ordered as found di_lu 0x83 Device identification, lu only di_port 0x83 Device identification, target port only di_target 0x83 Device identification, target device only dtde 0xb4 Data transfer device element address (SSC) ei 0x86 Extended inquiry data iod 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 addresses mpp 0x87 Mode page policy oi 0xb0 OSD information pc 0x8a Power condition psm 0x8d Power consumption pslu 0x90 Protocol-specific logical unit information pspo 0x91 Protocol-specific port information ref 0xb3 Referrals (SBC) sad 0xb0 Sequential access device capabilities (SSC) sii 0x84 Software interface identification sinq -1 Standard inquiry response sn 0x80 Unit serial number sp 0x88 SCSI ports st 0xb1 Security token (OSD) sv 0x00 Supported VPD pages tas 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/sdeLogical block provisioning VPD page (SBC): Unmap command supported (LBPU): 0 Write same (16) with unmap bit supported (LBWS): 0 Write same (10) with unmap bit supported (LBWS10): 0 Logical block provisioning read zeros (LBPRZ): 0 Anchored LBAs supported (ANC_SUP): 0 Threshold exponent: 0 Descriptor present (DP): 0 Provisioning type: 0
当输入错误的参数页名称时,命令会打印所有可以使用的参数页名称,当然,并不是所有设备都支持全部这些参数页。
$ cat /proc/scsi/scsiAttached devices:Host: scsi2 Channel: 00 Id: 00 Lun: 00 Vendor: VMware, Model: VMware Virtual S Rev: 1.0 Type: Direct-Access ANSI SCSI revision: 02Host: scsi2 Channel: 00 Id: 01 Lun: 00 Vendor: VMware, Model: VMware Virtual S Rev: 1.0 Type: Direct-Access ANSI SCSI revision: 02Host: scsi2 Channel: 00 Id: 02 Lun: 00 Vendor: VMware, Model: VMware Virtual S Rev: 1.0 Type: Direct-Access ANSI SCSI revision: 02Host: scsi2 Channel: 00 Id: 03 Lun: 00 Vendor: VMware, Model: VMware Virtual S Rev: 1.0 Type: Direct-Access ANSI SCSI revision: 02Host: scsi1 Channel: 00 Id: 00 Lun: 00 Vendor: NECVMWar Model: VMware IDE CDR10 Rev: 1.00 Type: CD-ROM ANSI SCSI revision: 05Host: scsi3 Channel: 00 Id: 00 Lun: 00 Vendor: IET Model: Controller Rev: 0001 Type: RAID ANSI SCSI revision: 05Host: scsi3 Channel: 00 Id: 00 Lun: 01 Vendor: IET Model: VIRTUAL-DISK Rev: 0001 Type: Direct-Access ANSI SCSI revision: 05Host: scsi4 Channel: 00 Id: 00 Lun: 00 Vendor: IET Model: Controller Rev: 0001 Type: RAID ANSI SCSI revision: 05Host: scsi8 Channel: 00 Id: 00 Lun: 00 Vendor: IET Model: Controller Rev: 0001 Type: RAID ANSI SCSI revision: 05Host: scsi4 Channel: 00 Id: 00 Lun: 01 Vendor: IET Model: VIRTUAL-DISK Rev: 0001 Type: Direct-Access ANSI SCSI revision: 05Host: scsi8 Channel: 00 Id: 00 Lun: 01 Vendor: IET Model: VIRTUAL-DISK Rev: 0001 Type: Direct-Access ANSI SCSI revision: 05Host: scsi5 Channel: 00 Id: 00 Lun: 00 Vendor: IET Model: Controller Rev: 0001 Type: RAID ANSI SCSI revision: 05Host: scsi6 Channel: 00 Id: 00 Lun: 00 Vendor: IET Model: Controller Rev: 0001 Type: RAID ANSI SCSI revision: 05Host: scsi5 Channel: 00 Id: 00 Lun: 01 Vendor: IET Model: VIRTUAL-DISK Rev: 0001 Type: Direct-Access ANSI SCSI revision: 05Host: scsi6 Channel: 00 Id: 00 Lun: 01 Vendor: IET Model: VIRTUAL-DISK Rev: 0001 Type: Direct-Access ANSI SCSI revision: 05Host: scsi9 Channel: 00 Id: 00 Lun: 00 Vendor: IET Model: Controller Rev: 0001 Type: RAID ANSI SCSI revision: 05Host: scsi9 Channel: 00 Id: 00 Lun: 01 Vendor: IET Model: VIRTUAL-DISK Rev: 0001 Type: 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=0 VMware, VMware Virtual S 1.0 [rmb=0 cmdq=1 pqual=0 pdev=0x0] /dev/sg1: scsi2 channel=0 id=1 lun=0 VMware, VMware Virtual S 1.0 [rmb=0 cmdq=1 pqual=0 pdev=0x0] /dev/sg2: scsi2 channel=0 id=2 lun=0 VMware, VMware Virtual S 1.0 [rmb=0 cmdq=1 pqual=0 pdev=0x0] /dev/sg3: scsi2 channel=0 id=3 lun=0 VMware, 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=0 IET Controller 0001 [rmb=0 cmdq=1 pqual=0 pdev=0xc] /dev/sg6: scsi3 channel=0 id=0 lun=1 IET VIRTUAL-DISK 0001 [rmb=0 cmdq=1 pqual=0 pdev=0x0] /dev/sg7: scsi4 channel=0 id=0 lun=0 IET Controller 0001 [rmb=0 cmdq=1 pqual=0 pdev=0xc] /dev/sg8: scsi8 channel=0 id=0 lun=0 IET Controller 0001 [rmb=0 cmdq=1 pqual=0 pdev=0xc] /dev/sg9: scsi4 channel=0 id=0 lun=1 IET VIRTUAL-DISK 0001 [rmb=0 cmdq=1 pqual=0 pdev=0x0] /dev/sg10: scsi9 channel=0 id=0 lun=0 IET Controller 0001 [rmb=0 cmdq=1 pqual=0 pdev=0xc] /dev/sg11: scsi8 channel=0 id=0 lun=1 IET VIRTUAL-DISK 0001 [rmb=0 cmdq=1 pqual=0 pdev=0x0] /dev/sg12: scsi5 channel=0 id=0 lun=0 IET Controller 0001 [rmb=0 cmdq=1 pqual=0 pdev=0xc] /dev/sg13: scsi9 channel=0 id=0 lun=1 IET VIRTUAL-DISK 0001 [rmb=0 cmdq=1 pqual=0 pdev=0x0] /dev/sg14: scsi6 channel=0 id=0 lun=0 IET Controller 0001 [rmb=0 cmdq=1 pqual=0 pdev=0xc] /dev/sg15: scsi5 channel=0 id=0 lun=1 IET VIRTUAL-DISK 0001 [rmb=0 cmdq=1 pqual=0 pdev=0x0] /dev/sg16: scsi6 channel=0 id=0 lun=1 IET 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 -hUsage: sg_persist [OPTIONS] [DEVICE]where OPTIONS include: --alloc-length=LEN|-l LEN allocation length hex value (used with PR 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 action reservation 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 commandtype --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 can be 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 -vvvopen /dev/sde with flags=0x800 inquiry cdb: 12 00 00 00 24 00 duration=1 ms IET VIRTUAL-DISK 0001 Peripheral device type: diskopen /dev/sde with flags=0x802 Persistent Reservation In cmd: 5e 02 00 00 00 00 00 20 00 00 duration=0 ms persistent reservation in: pass-through requested 8192 bytes but got 8 bytes persistent reserve in: response 00 08 00 80 ea 01 00 00Report capabilities response: Compatible Reservation Handling(CRH): 0 Specify Initiator Ports Capable(SIP_C): 0 All Target Ports Capable(ATP_C): 0 Persist Through Power Loss Capable(PTPL_C): 0 Type Mask Valid(TMV): 1 Allow Commands: 0 Persist Through Power Loss Active(PTPL_A): 0 Support indicated in Type mask: Write Exclusive, all registrants: 1 Exclusive Access, registrants only: 1 Write Exclusive, registrants only: 1 Exclusive Access: 1 Write Exclusive: 1 Exclusive Access, all registrants: 1
如果不支持PRs功能,则会直接返回错误。同时这里面的参数描述显示可能不全,可根据“persistent reserve in: response”下面的数据参照PRs命令规范进行对照查看。
- 查看设备上有哪些“Registered Reservation Key”:
$ sg_persist -k /dev/sde -vvvopen /dev/sde with flags=0x800 inquiry cdb: 12 00 00 00 24 00 duration=0 ms IET VIRTUAL-DISK 0001 Peripheral device type: diskopen /dev/sde with flags=0x802 Persistent Reservation In cmd: 5e 00 00 00 00 00 00 20 00 00 duration=1 ms persistent reservation in: pass-through requested 8192 bytes but got 16 bytes persistent reserve in: response 00 00 00 07 00 00 00 08 00 00 00 00 00 00 0a bc PR generation=0x7, 1 registered reservation key follows: 0xabc
- 查看设备上的“Persistent Reservation”状态:
$ sg_persist -r /dev/sde -vvvopen /dev/sde with flags=0x800 inquiry cdb: 12 00 00 00 24 00 duration=0 ms IET VIRTUAL-DISK 0001 Peripheral device type: diskopen /dev/sde with flags=0x802 Persistent Reservation In cmd: 5e 01 00 00 00 00 00 20 00 00 duration=0 ms persistent reservation in: pass-through requested 8192 bytes but got 8 bytes persistent reserve in: response 00 00 00 07 00 00 00 00 PR generation=0x7, there is NO reservation held
在节点1上的两条链路注册“abc”:
$ sg_persist --out --register --param-sark=abc /dev/sde IET VIRTUAL-DISK 0001 Peripheral device type: disk$ sg_persist --out --register --param-sark=abc /dev/sdf IET VIRTUAL-DISK 0001 Peripheral device type: disk$ sg_persist /dev/sde>> No service action given; assume Persistent Reserve In command>> with Read Keys service action IET VIRTUAL-DISK 0001 Peripheral device type: disk PR generation=0x16, 2 registered reservation keys follow: 0xabc 0xabc
在节点2上的两条链路注册“123”:
$ sg_persist --out --register --param-sark=123 /dev/sde IET VIRTUAL-DISK 0001 Peripheral device type: disk$ sg_persist --out --register --param-sark=123 /dev/sdf IET VIRTUAL-DISK 0001 Peripheral device type: disk$ sg_persist /dev/sde>> No service action given; assume Persistent Reserve In command>> with Read Keys service action IET VIRTUAL-DISK 0001 Peripheral device type: disk PR generation=0x18, 4 registered reservation keys follow: 0xabc 0xabc 0x123 0x123
- 获取“Exclusive Access”类型的“Persistent Reservation”,
在节点1上使“abc”获取“Exclusive Access”类型的“Persistent Reservation”,并进行读取:
$ sg_persist --out --reserve --prout-type=3 --param-rk=abc /dev/sde IET VIRTUAL-DISK 0001 Peripheral device type: disk$ sg_persist -r /dev/sde IET VIRTUAL-DISK 0001 Peripheral device type: disk PR generation=0x18, Reservation follows: Key=0xabc scope: LU_SCOPE, type: Exclusive Access$ sg_persist -r /dev/sdf IET VIRTUAL-DISK 0001 Peripheral device type: disk PR generation=0x18, Reservation follows: Key=0xabc scope: 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=directdd: 读取"/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=directdd: 读取"/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=directdd: 读取"/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/sde IET VIRTUAL-DISK 0001 Peripheral device type: disk$ sg_persist -k /dev/sde IET VIRTUAL-DISK 0001 Peripheral device type: disk PR generation=0x18, 4 registered reservation keys follow: 0xabc 0xabc 0x123 0x123$ sg_persist -r /dev/sde IET VIRTUAL-DISK 0001 Peripheral device type: disk PR 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/sde IET VIRTUAL-DISK 0001 Peripheral device type: disk$ sg_persist -r /dev/sde IET VIRTUAL-DISK 0001 Peripheral device type: disk PR generation=0x18, Reservation follows: Key=0xabc scope: 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/秒
$ sg_persist -k /dev/storage/dmd-test01 IET VIRTUAL-DISK 0001 Peripheral device type: disk PR generation=0x0, there are NO registered reservation keys$ sg_persist --out --register --param-sark=abc /dev/storage/dmd-test01 IET VIRTUAL-DISK 0001 Peripheral device type: disk$ sg_persist -k /dev/storage/dmd-test01 IET VIRTUAL-DISK 0001 Peripheral device type: disk PR generation=0x1, 1 registered reservation key follows: 0xabc$ sg_persist -k /dev/storage/dmd-test02 IET VIRTUAL-DISK 0001 Peripheral device type: disk PR 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-test01 IET VIRTUAL-DISK 0001 Peripheral device type: disk$ sg_persist -r /dev/storage/dmd-test01 IET VIRTUAL-DISK 0001 Peripheral device type: disk PR generation=0xb, Reservation follows: Key=0xabc scope: LU_SCOPE, type: Exclusive Access$ sg_persist -r /dev/storage/dmd-test02 IET VIRTUAL-DISK 0001 Peripheral device type: disk PR generation=0xb, Reservation follows: Key=0xabc scope: 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/秒
$ sg_persist --out --register --param-rk=abc /dev/sde IET VIRTUAL-DISK 0001 Peripheral device type: disk$ sg_persist /dev/sde>> No service action given; assume Persistent Reserve In command>> with Read Keys service action IET VIRTUAL-DISK 0001 Peripheral device type: disk PR generation=0x10, there are NO registered reservation keys
如果喜欢,请麻烦点个关注,会更快的更新!