Logo Search packages:      
Sourcecode: dmraid version File versions  Download package

scsi.c

/*
 * Copyright (C) 2004,2005  Heinz Mauelshagen, Red Hat GmbH.
 *                          All rights reserved.
 *
 * See file LICENSE at the top of this source tree for license information.
 */

#include <string.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <mm/dbg_malloc.h>
#include <scsi/scsi_ioctl.h>

/* FIXME: sg header mess. */
#include <scsi/sg.h>
#include <scsi/scsi.h>

#include "dev-io.h"
#include "scsi.h"

/* Thx scsiinfo. */

/* Initialize SCSI inquiry command block (used both with SG and old ioctls). */
static void set_cmd(unsigned char *cmd, size_t len)
{
      cmd[0] = 0x12;    /* INQUIRY */
      cmd[1] = 1;
      cmd[2] = 0x80;    /* page code: SCSI serial */
      cmd[3] = 0;
      cmd[4] = (unsigned char) (len & 0xff);
      cmd[5] = 0;
}

/*
 * SCSI SG_IO ioctl to get serial number of a unit.
 */
static int sg_inquiry(int fd, unsigned char *response, size_t response_len)
{
      unsigned char cmd[6];
      struct sg_io_hdr io_hdr;

      set_cmd(cmd, response_len);

      /* Initialize generic (SG) SCSI ioctl header. */
      memset(&io_hdr, 0, sizeof(io_hdr));
      io_hdr.interface_id     = 'S';
      io_hdr.cmdp       = cmd;
      io_hdr.cmd_len          = sizeof(cmd);
      io_hdr.sbp        = NULL;
      io_hdr.mx_sb_len  = 0;
      io_hdr.dxfer_direction  = SG_DXFER_FROM_DEV;
      io_hdr.dxferp           = response;
      io_hdr.dxfer_len  = response_len;
      io_hdr.timeout          = 6000; /* [ms] */

      return ioctl(fd, SG_IO, &io_hdr) ? 0 : 1;
}

/*
 * Old SCSI ioctl as fallback to get serial number of a unit.
 */
static int old_inquiry(int fd, unsigned char *response, size_t response_len)
{
      unsigned int *i = (unsigned int*) response;

      i[0] = 0; /* input data length */
      i[1] = response_len; /* output buffer length */
      set_cmd((unsigned char*) &i[2], response_len); 

      return ioctl(fd, SCSI_IOCTL_SEND_COMMAND, response) ? 0 : 1;
}

/*
 * Retrieve SCSI serial number.
 */
#define     MAX_RESPONSE_LEN  255
int get_scsi_serial(struct lib_context *lc, int fd, struct dev_info *di,
                enum ioctl_type type)
{
      int ret = 0;
      size_t actual_len;
      unsigned char *response;
      /*
       * Define ioctl function and offset into response buffer of serial
       * string length field (serial string follows length field immediately)
       */
      struct {
            int (*ioctl_func)(int, unsigned char*, size_t);
            unsigned int start;
      } param[] = {
            { sg_inquiry ,  3 },
            { old_inquiry, 11 },
      }, *p = (SG == type) ? param : param + 1;

      if (!(response = dbg_malloc(MAX_RESPONSE_LEN)))
            return 0;

      actual_len = p->start + 1;
      if ((ret = (p->ioctl_func(fd, response, actual_len)))) {
            size_t serial_len = (size_t) response[p->start];

            if (serial_len > actual_len) {
                  actual_len += serial_len;
                  ret = p->ioctl_func(fd, response, actual_len);
            }

            ret = ret && (di->serial = dbg_strdup(remove_white_space(lc, (char*) &response[p->start + 1], serial_len)));
      }

      dbg_free(response);

      return ret;
}

Generated by  Doxygen 1.6.0   Back to index