目次

SCSIコマンドに関して

実装

SCSIコマンドには沢山あるが、大雑把に大別するとデバイスに記録されているデータをrwするコマンド(READ/WRITE)とデバイスを制御/診断するもの(INQUIRY/FORMAT/READ ATTRIBUTE)とかがあるっぽい。どんなのあるかの詳しくはwikiとか仕様書とかを参照ってことでw

コード例がLinuxのHowTo?にあるが、あれはSGドライバのVersion 3.0以前のdriverを 直接 read/writeしてデータブロックをやり取りするのものだが、3.0以降は SGドライバに SG_IOと言うioctl()が新設されており、こちらを利用して SCSIのデータブロックをrwするのが、現在のトレンドだとおもう、多分w

コード例

ってことで、例によって後は実装で HowTo?で提供されている handle_scsi_cmd()に対応する handle_scsi3_cmd()を作成してみた。

handle_scsi_cmd()

ここを参照

handle_scsi3_cmd()

いい加減に実装しているので使い易いか分らないが、自分で必要と考えていた INQUIRYとREAD ATTRIBUTEの供用として使えたので、まぁいいんだろう。
#define SG_VERSION3 30000
int handle_cmd_sg3(
  int fd, 
  unsigned char *cdb, 
  int cdblen,
  int dxfer,
  unsigned char *rbuf,
  int rbuflen
) {
  int ret, k, i;
  sg_io_hdr_t sg_hdr;
  sg_io_hdr_t *p = &sg_hdr;

  int senselen = 0xffff;
  unsigned char sense_buffer[senselen];

  // SG_IOが使えるかチェックする前置き
  if ( ioctl(fd, SG_GET_VERSION_NUM, &k) < 0 ||
    k < SG_VERSION3 ) {
    fprintf(stderr, 
      "unable to use this, bacause SG version is elder than %d\n", 
      SG_VERSION3);
    return -1;
  }

  memset(p, 0, sizeof(sg_io_hdr_t));
  p->interface_id = 'S';// required and fixed
  p->cmd_len = cdblen;
  p->cmdp = cdb;
  // p->iovec_count = 0; vec ioする場合

  p->dxfer_direction = dxfer;
  /*
    SG_DXFER_NONE      SCSI test unit ready command
    SG_DXFER_TO_DEV      SCSI WRITE command
    SG_DXFER_FROM_DEV    SCSI READ command
    SG_DXFER_TO_FROM_DEV  use only relevant to indirect I/O
    SG_DEXFER_UNKNOWN    misc. For vendor specific.
  */
  p->dxfer_len = rbuflen;
  p->dxferp = rbuf;

  p->mx_sb_len = sizeof(sense_buffer);
  p->sbp = sense_buffer;

  p->timeout = 10000;// timeout 10sec

  //p->flags = 0;
  //p->pack_id = 0;
  //p->usr_ptr = NULL;

  ret = ioctl(fd, SG_IO, p);
  if ( ret == -1 ) {
    fprintf(stderr, "ioctl(SG_IO) : %s[%d]\n", strerror(errno), errno);
    return -1;
  }

  // handling response
  if ( (p->info & SG_INFO_OK_MASK) != SG_INFO_OK ) {
    // failure case
    if ( p->sb_len_wr > 0 ) {
      fprintf(stderr, "SENSE DATA: ");
      for ( i = 0; i < p->sb_len_wr; i++ ) {
        printf("0x%02x ", sense_buffer[i]);
      }
      printf("\n");
    }

    if ( p->masked_status ) 
      printf("SCSI STATUS : 0x%x\n", p->status);
    if ( p->host_status ) 
      printf("HOST STATUS : 0x%x\n", p->host_status);
    if ( p->driver_status ) 
      printf("DRIVER STATUS : 0x%x\n", p->driver_status);
    return -1;
  } 

  return 0;
}

参考文献

Linuxの開発参考文献はonlineで必要なものは大体手に入る。

Last-modified: 2010-11-15 18:07:16