���Υڡ��� ���Υڡ��� �ܼ���

24. �ץ��������

���줬 C ����ˤ��ץ��������Ǥ����������¤��/��ǥ���׵ᤷ�� ��ǥ��������֤���ܤ���Ƥ��뤫�ɤ�������𤷤ޤ���

#define DEVICE "/dev/sgc"
/* ���� SCSI ���󥿡��ե�������ºݤ�ư�����Ƥߤ븫�ܥץ������ */
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <scsi/sg.h>

#define SCSI_OFF sizeof(struct sg_header)
static unsigned char cmd[SCSI_OFF + 18];      /* SCSI ���ޥ�� �Хåե� */
int fd;                               /* SCSI �ǥХ���/�ե����� �ǥ�������ץ� */

/* ���뤷�� SCSI ���ޥ�ɤ������ ���� SCSI ���󥿡��ե���������� */
static int handle_scsi_cmd(unsigned cmd_len,         /* ���ޥ��Ĺ */
                           unsigned in_size,         /* ���ϥǡ��������� */
                           unsigned char *i_buff,    /* ���ϥХåե� */
                           unsigned out_size,        /* ���ϥǡ��������� */
                           unsigned char *o_buff     /* ���ϥХåե� */
                           )
{
    int status = 0;
    struct sg_header *sg_hd;

    /* ���������� */
    if (!cmd_len) return -1;            /* cmd_len != 0 ��ɬ�� */
    if (!i_buff) return -1;             /* ���ϥХåե��� NULL �Ǥʤ����� */
#ifdef SG_BIG_BUFF
    if (SCSI_OFF + cmd_len + in_size > SG_BIG_BUFF) return -1;
    if (SCSI_OFF + out_size > SG_BIG_BUFF) return -1;
#else
    if (SCSI_OFF + cmd_len + in_size > 4096) return -1;
    if (SCSI_OFF + out_size > 4096) return -1;
#endif

    if (!o_buff) out_size = 0;

    /* ���� SCSI �ǥХ����إå��ι��� */
    sg_hd = (struct sg_header *) i_buff;
    sg_hd->reply_len   = SCSI_OFF + out_size;
    sg_hd->twelve_byte = cmd_len == 12;
    sg_hd->result = 0;
#if     0
    sg_hd->pack_len    = SCSI_OFF + cmd_len + in_size; /* ���� */
    sg_hd->pack_id;     /* ̤���� */
    sg_hd->other_flags; /* ̤���� */
#endif

    /* ���ޥ������ */
    status = write( fd, i_buff, SCSI_OFF + cmd_len + in_size );
    if ( status < 0 || status != SCSI_OFF + cmd_len + in_size ||
                       sg_hd->result ) {
        /* �ʤ�餫�Υ��顼��ȯ�� */
        fprintf( stderr, "write(generic) result = 0x%x cmd = 0x%x\n", 
                    sg_hd->result, i_buff[SCSI_OFF] );
        perror("");
        return status;
    }
    
    if (!o_buff) o_buff = i_buff;       /* �Хåե��Υݥ��󥿤�����å� */

    /* ��̤��� */
    status = read( fd, o_buff, SCSI_OFF + out_size);
    if ( status < 0 || status != SCSI_OFF + out_size || sg_hd->result ) {
        /* �ʤ�餫�Υ��顼��ȯ�� */
        fprintf( stderr, "read(generic) result = 0x%x cmd = 0x%x\n", 
                sg_hd->result, o_buff[SCSI_OFF] );
        fprintf( stderr, "read(generic) sense "
                "%x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x\n", 
                sg_hd->sense_buffer[0],         sg_hd->sense_buffer[1],
                sg_hd->sense_buffer[2],         sg_hd->sense_buffer[3],
                sg_hd->sense_buffer[4],         sg_hd->sense_buffer[5],
                sg_hd->sense_buffer[6],         sg_hd->sense_buffer[7],
                sg_hd->sense_buffer[8],         sg_hd->sense_buffer[9],
                sg_hd->sense_buffer[10],        sg_hd->sense_buffer[11],
                sg_hd->sense_buffer[12],        sg_hd->sense_buffer[13],
                sg_hd->sense_buffer[14],        sg_hd->sense_buffer[15]);
        if (status < 0)
            perror("");
    }
    /* �������٤���Τ������ä����ɤ�����ߤ� */
    if (status == SCSI_OFF + out_size) status = 0; /* �������ä� */

    return status;  /* 0 �ϥ��顼�ʤ����̣ */
}

#define INQUIRY_CMD     0x12
#define INQUIRY_CMDLEN  6
#define INQUIRY_REPLY_LEN 96
#define INQUIRY_VENDOR  8       /* �����ǡ�����Υ٥��̾�Υ��ե��å� */

/* �٥���Υ֥��ɤȥ�ǥ���׵� */
static unsigned char *Inquiry ( void )
{
  static unsigned char Inqbuffer[ SCSI_OFF + INQUIRY_REPLY_LEN ];
  unsigned char cmdblk [ INQUIRY_CMDLEN ] = 
      { INQUIRY_CMD,  /* command */
                  0,  /* lun/reserved */
                  0,  /* page code */
                  0,  /* reserved */
  INQUIRY_REPLY_LEN,  /* allocation length */
                  0 };/* reserved/flag/link */

  memcpy( cmd + SCSI_OFF, cmdblk, sizeof(cmdblk) );

  /*
   * +------------------+
   * | struct sg_header | <- cmd
   * +------------------+
   * | copy of cmdblk   | <- cmd + SCSI_OFF
   * +------------------+
   */

  if (handle_scsi_cmd(sizeof(cmdblk), 0, cmd, 
                      sizeof(Inqbuffer) - SCSI_OFF, Inqbuffer )) {
      fprintf( stderr, "Inquiry failed\n" );
      exit(2);
  }
  return (Inqbuffer + SCSI_OFF);
}

#define TESTUNITREADY_CMD 0
#define TESTUNITREADY_CMDLEN 6

#define ADD_SENSECODE 12
#define ADD_SC_QUALIFIER 13
#define NO_MEDIA_SC 0x3a
#define NO_MEDIA_SCQ 0x00
int TestForMedium ( void )
{
  /* READY ���֤��׵� */
  static unsigned char cmdblk [TESTUNITREADY_CMDLEN] = {
      TESTUNITREADY_CMD, /* command */
                      0, /* lun/reserved */
                      0, /* reserved */
                      0, /* reserved */
                      0, /* reserved */
                      0};/* reserved */

  memcpy( cmd + SCSI_OFF, cmdblk, sizeof(cmdblk) );

  /*
   * +------------------+
   * | struct sg_header | <- cmd
   * +------------------+
   * | copy of cmdblk   | <- cmd + SCSI_OFF
   * +------------------+
   */

  if (handle_scsi_cmd(sizeof(cmdblk), 0, cmd, 
                            0, NULL)) {
      fprintf (stderr, "Test unit ready failed\n");
      exit(2);
  }

  return 
   *(((struct sg_header*)cmd)->sense_buffer +ADD_SENSECODE) !=
                                                        NO_MEDIA_SC ||
   *(((struct sg_header*)cmd)->sense_buffer +ADD_SC_QUALIFIER) !=
                                                        NO_MEDIA_SCQ;
}

void main( void )
{
  fd = open(DEVICE, O_RDWR);
  if (fd < 0) {
    fprintf( stderr, "Need read/write permissions for "DEVICE".\n" );
    exit(1);
  }

  /* Inquiry �η�̤ΰ����Υե�����ɤ�ɽ�� */
  printf( "%s\n", Inquiry() + INQUIRY_VENDOR );

  /* ��ǥ�������ܤ���Ƥ��뤫�ɤ�����ߤ� */
  if (!TestForMedium()) {
    printf("device is unloaded\n");
  } else {
    printf("device is loaded\n");
  }
}

���Υڡ��� ���Υڡ��� �ܼ���