USB 磁带客户机设备驱动程序

用途

支持顺序存取磁带设备驱动程序的通用串行总线 (USB) 协议。

语法

#include <sys/devinfo.h>
#include <sys/usb.h>
#include <sys/tape.h>
#include <sys/usbdi.h>

与设备相关的子例程

大多数磁带操作是使用 openclosereadwrite 子例程实现的。 但是,如果必须以 Diagnostic 方式打开设备,那么必须使用 openx 子例程。

打开和关闭子例程

openx 子例程主要用于诊断命令和实用程序。 需要适当的权限才能运行子例程。 如果在没有必要授权的情况下运行 openx 子例程,该子例程将返回 -1 值,并将 errno 全局变量设置为 EPERM 值。

openx 子例程对设备驱动程序启用 Diagnostic 方式,并禁用命令重试逻辑。 此操作允许执行与诊断处理关联的特殊功能的 ioctl 操作。 openx 子例程还可以强制打开和保留预留。

open 子例程应用基于对象数据管理器 (ODM) reserve_policy 属性的保留策略。 USB 磁带设备可能不支持 "小型计算机系统接口" (SCSI) 预留命令,因此可能会忽略这些命令。

传递到 openx 子例程的 ext 参数选择要用于目标设备的操作。 /usr/include/sys/scsi.h 文件定义 ext 参数的可能值。

扩展 参数可包含下列标志值的任何逻辑组合:

描述
SC_FORCED_OPEN 通过除去设备上可能禁止访问的任何类型的保留来强制访问该设备。 除去保留的行动类型取决于已建立的保留的特定类型。 如果指定了此标志,那么将对 USB 磁带 (即大容量存储批量设备) 发出大容量存储器重置命令。
SC_DIAGNOSTIC 将所选设备置于 Diagnostic 方式。 此方式是单入方式。 这意味着当设备处于 Diagnostic 方式时,将在 openclose 操作期间执行 SCSI 操作,并且将禁用错误日志记录。 在 Diagnostic 方式下,仅接受 closeioctl 操作。 所有其他设备支持的子程序都返回 -1 值,并将 errno 全局变量设置为 EACCES 值。

仅当当前未打开目标设备时,才能以 Diagnostic 方式打开设备。 如果在 Diagnostic 模式下打开设备,而目标设备已经打开,则子程序会返回 -1 值,并将 errno 全局变量设置为 EACCES 值。

ioctl 子例程

USB 磁带设备上支持以下 ioctl 操作:

操作 描述
IOCINFO 使用以下值填充由调用者传递的 devinfo 参数:
        devinfo.devtype           = DD_SCTAPE;
        devinfo.flags             = 0;
        devinfo.devsubtype        = 0x00;
        devinfo.un.scmt.type      = DT_STREAM;
        devinfo.un.scmt.blksize   = Block Size Set for the Tape Device;
STIOCTOP 指定 src/bos/usr/include/sys/tape.h 文件中定义的停止结构的地址。 在停止结构中的 st_op 字段中找到的操作将运行 st_count 次,但倒带,擦除和保留操作除外。

ioctl 命令支持具有相应实现详细信息的以下操作:

向磁带设备发出 REWIND 命令以倒带磁带。
STERASE
发出 SCSI ERASE 命令以擦除磁带介质的内容。 对于只读磁带,不允许擦除。
STRETEN 或 STINSRT
发出 SCSI LOAD 命令,并在命令的字节 4 中设置 LoadReten 位。
STWEOF
将文件结束符标记写入磁带。 只读磁带不允许 Write End-of-Filemark 操作。  
STDEOF
禁用 "磁带结束检查" 命令。
STFSF
发出 Forward Space File 命令。 st_count 字段指定磁带前进的文件标记数。
STFSR
发出 Forward Space Record 命令。 st_count 字段是磁带前进的记录数。
STRSF
发出 Reverse Space File 命令。 st_count 字段是磁带反转的文件标记数。
STRSR
发出 Reverse Space Record 命令。 st_count 字段是磁带反转的记录数。
STOFFL 或 STEJECT
将磁带从磁带机中弹出。 此操作发出 SCSI LOAD 命令,并将命令描述符块 (CDB) 的字节 4 中的 Load 位设置为零。
STIOCHGP
定义 ioctl 命令以动态更改此磁带设备的块大小。 对于打开操作的长度,块大小将更改,并在下一个打开操作时返回到原始值。 当执行此操作时,磁带被强制为 BOT (磁带开头)。

ioctl 命令的参数指定 src/bos/usr/include/sys/tape.h 文件中定义的 stchgp 结构的地址。 结构中的 st_blksize 字段指定要设置的块大小值。

SITOCTOP (续)
STIOCMD
成功打开设备时, STIOCMD 操作会向指定的磁带设备发出 SCSI 命令。

SCSI 状态字节和适配器状态字节通过包含 scsi_iocmd 结构地址的 arg 参数返回。 此结构在 /usr/include/sys/scsi_buf.h 文件中定义。 STIOCMD 操作在 scsi_iocmd 结构的 scsi_cdb 部分中接收 SCSI 命令,并将其发放到 USB 磁带设备。 如果 STIOCMD 操作失败,子程序将返回 -1 值,并将 errno 全局变量设置为非零值。 在此情况下,调用者必须对返回的状态字节进行求值,以确定操作失败的原因以及恢复操作。

将验证用户传递的 versioncommand_lengthtimeout_value 值,如果这些值无效,那么将返回错误值 EINVAL

如果传输量超过最大 I/O 传输量的 1 MB,子程序将返回 -1 值,并将 errno 全局变量设置为 EINVAL 值。

在检查条件下,将在 sc_passthru 结构中设置以下错误状态值:

    status_validity  = SC_SCSI_ERROR
    scsi_bus_status = SC_CHECK_CONDITION
    adap_set_flags will have SC_AUTOSENSE_DATA_VALID flag set.

以下示例是用于向 USB 磁带发出 STIOCMD 操作以发出 INQUIRY SCSI 命令的伪代码:

    struct scsi_iocmd cmd;
    char inq_data[255];
    char sense_data[255];
..
    fd = open(“/dev/rmt0”, O_RDWR);
..
    memset(&cmd, '\0', sizeof(struct sc_passthru));
    cmd.version = SCSI_VERSION_1;
    cmd.timeout_value = 30;
    cmd.command_length = 6;
    cmd.autosense_length = 255;
    cmd.autosense_buffer_ptr = &sense_data[0];
    cmd.data_length = 0xFF;
    cmd.buffer = inq_data;

   cmd.flags = B_READ;

   cmd.scsi_cdb[0] = SCSI_INQUIRY;
    cmd.scsi_cdb[1] = (0x00 | vpd);  /* Standard Inquiry - vpd=1 
                 for Extended Inquiry */
    cmd.scsi_cdb[2] = page_code;    /* Page Code - valid if vpd=1 */
    cmd.scsi_cdb[3] = 0x00;
    cmd.scsi_cdb[4] = 0xFF;
    cmd.scsi_cdb[5] = 0x00;

   if ((rc=ioctl(fd, STIOCMD, &cmd)) != 0){
         if (cmd.adap_set_flags & SC_AUTOSENSE_DATA_VALID) { 
        /* look at sense data */
         } /* end SC_AUTOSENSE_DATA_VALID */

         printf("STPASSTHRU: Ioctl FAIL errno %d\n",errno);
         printf("status_validity: %x, scsi_status: %x, adapter_status:%x\n", 
      cmd.status_validity, cmd.scsi_bus_status, cmd.adapter_status);
         printf("Residual: %x\n", cmd.residual);
         exit(-1);
     } else {
         printf("STPASSTHRU : Ioctl PASS\n");
         printf("status_validity: %x, scsi_status: %x, adapter_status:%x\n", 
      cmd.status_validity, cmd.scsi_bus_status, cmd.adapter_status);     }
STPASSTHRU sc_passthru 结构的 scsi_cdb 部分中执行 SCSI 命令,并将其发出到 USB 磁带驱动程序。 此操作类似于 STIOCMD ioctl 操作,唯一的例外是 sc_passthru 结构中提供了有关错误的更多信息的其他信息字段。

以下示例是用于向 USB 磁带发出 STPASSTHRU 操作以发出 INQUIRY SCSI 命令的伪代码:

    struct sc_passthru cmd;
    char inq_data[255];
    char sense_data[255];
..
    fd = open(“/dev/rmt0”, O_RDWR);
..
    memset(&cmd, '\0', sizeof(struct sc_passthru));
    cmd.version = SCSI_VERSION_1;
    cmd.timeout_value = 30;
    cmd.command_length = 6;
    cmd.autosense_length = 255;
    cmd.autosense_buffer_ptr = &sense_data[0];
    cmd.data_length = 0xFF;
    cmd.buffer = inq_data;

   cmd.flags = B_READ;

   cmd.scsi_cdb[0] = SCSI_INQUIRY;
    cmd.scsi_cdb[1] = (0x00 | vpd);  /* Standard Inquiry - vpd=1
                                 for Extended Inquiry */
    cmd.scsi_cdb[2] = page_code;      /* Page Code - valid if vpd=1 */
    cmd.scsi_cdb[3] = 0x00;
    cmd.scsi_cdb[4] = 0xFF;
    cmd.scsi_cdb[5] = 0x00;

   if ((rc=ioctl(fd, STPASSTHRU, &cmd)) != 0){
       if (cmd.adap_set_flags & SC_AUTOSENSE_DATA_VALID) {
             /* look at sense data */
         } /* end SC_AUTOSENSE_DATA_VALID */

         printf("STPASSTHRU: Ioctl FAIL errno %d\n",errno);
         printf("status_validity: %x, scsi_status: %x, adapter_status:%x\n", 
       cmd.status_validity, cmd.scsi_bus_status, cmd.adapter_status);
         printf("Residual: %x\n", cmd.residual);
         exit(-1);
     } else {
         printf("STPASSTHRU : Ioctl PASS\n");
         printf("status_validity: %x, scsi_status: %x, adapter_status:%x\n", 
       cmd.status_validity, cmd.scsi_bus_status, cmd.adapter_status);
     }