[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#20680: marked as done (hwtools: scsi-spin -- an additional program for hwtools...)



Your message dated Mon, 26 Apr 1999 14:48:58 +0200
with message-id <19990426144858.A30379@cibalia.gkvk.hr>
and subject line Closing
has caused the attached bug report to be marked as done.

This means that you claim that the problem has been dealt with.
If this is not the case it is now your responsibility to reopen the
bug report if necessary, and/or fix the problem forthwith.

(NB: If you are a system administrator and have no idea what I'm
talking about this indicates a serious mail system misconfiguration
somewhere.  Please contact me immediately.)

Ian Jackson
(administrator, Debian bugs database)

Received: (at submit) by bugs.debian.org; 4 Apr 1998 23:15:31 +0000
Received: (qmail 10668 invoked from network); 4 Apr 1998 23:15:31 -0000
Received: from mail.cs.utexas.edu (root@128.83.139.10)
  by debian.novare.net with SMTP; 4 Apr 1998 23:15:31 -0000
Received: from nevermore.csres.utexas.edu (dial-73-9.ots.utexas.edu [128.83.254.73])
	by mail.cs.utexas.edu (8.8.5/8.8.5) with ESMTP id RAA18084
	for <submit@bugs.debian.org>; Sat, 4 Apr 1998 17:15:16 -0600 (CST)
Received: from rlb by nevermore.csres.utexas.edu with local (Exim 1.891 #1)
	id 0yLc9a-00031J-00 (Debian); Sat, 4 Apr 1998 17:15:14 -0600
To: submit@bugs.debian.org
Subject: hwtools: scsi-spin -- an additional program for hwtools...
From: Rob Browning <rlb@cs.utexas.edu>
Date: 04 Apr 1998 17:15:14 -0600
Message-ID: <87u389tbzx.fsf@nevermore.csres.utexas.edu>
Lines: 250
X-Mailer: Gnus v5.6.2/Emacs 20.2


Package: hwtools
Version: 0.3-4
Severity: wishlist

Here's a small program I wrote called scsi-spin that lets you spin up
and down scsi drives.  I thought you might consider it for inclusion
in the debian hwtools package, and perhaps from there into the
upstream source somewhere.  Thanks...

This command is particularly useful if you've got noisy (or hot)
drives in a machine that you rarely need to access.  This is *not* the
same as the kernel patch that's floating around that will
automatically spin down the drive after some time.  scsi-spin is
completely manual, and spinning down a drive that's in use, especially
the one containing the scsi-spin binary, it probably a *really* bad
idea.

You can build it with GNU make, and this command:

  make CC=g++ CFLAGS="-g -Wall -O2 -I/usr/src/linux/include" scsi-spin

It doesn't really need g++, but I just wanted the extra type
checking...

And here's the source:

/*
  File: scsi-spin.c
  
  A simple program to manually spin up and down a scsi device.

  Copyright 1998 Rob Browning <rlb@cs.utexas.edu>

  This source is covered by the terms the GNU Public License.

  Some of the original code came from
    The Linux SCSI programming HOWTO
    Heiko Ei<DF>feldt heiko@colossus.escape.de
    v1.5, 7 May 1996

*/

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <getopt.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <scsi/sg.h>
#include <scsi/scsi.h>

#include <linux/major.h>
#include <sys/sysmacros.h>
#include <sys/stat.h>

static const int SCSI_CMD_SIZE = 18;
static const unsigned int scsi_off = sizeof(struct sg_header);
static unsigned char cmd[scsi_off + SCSI_CMD_SIZE]; /* SCSI command buffer */

/* process a complete SCSI cmd. Use the generic SCSI interface. */
static int handle_SCSI_cmd(const int fd,
                           const unsigned cmd_len,      /* command length */
                           const unsigned in_size,      /* input data size */
                           const unsigned char *i_buff, /* input buffer */
                           unsigned out_size,     /* output data size */
                           unsigned char *o_buff  /* output buffer */
                           ) {
  int status = 0;
  struct sg_header *sg_hd;
  
  /* safety checks */
  if (!cmd_len) return -1;            /* need a cmd_len != 0 */
  if (!i_buff) return -1;             /* need an input buffer != 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;      /* no output buffer, no output size */
  
  /* generic SCSI device header construction */
  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; /* not necessary */
  sg_hd->pack_id;     /* not used */
  sg_hd->other_flags; /* not used */
#endif
  
  /* send command */
  status = write( fd, i_buff, scsi_off + cmd_len + in_size );
  if ( status < 0 || status != scsi_off + cmd_len + in_size ||
       sg_hd->result ) {
    /* some error happened */
    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 = (char *) i_buff;       /* buffer pointer check */
  
  /* retrieve result */
  status = read( fd, o_buff, scsi_off + out_size);
  if ( status < 0 || status != scsi_off + out_size || sg_hd->result ) {
    /* some error happened */
    fprintf( stderr, "read(generic) status = 0x%x, result = 0x%x, "
             "cmd = 0x%x\n",
             status, 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("");
  }
  /* Look if we got what we expected to get */
  if (status == scsi_off + out_size) status = 0; /* got them all */
  
  return status;  /* 0 means no error */
}

#define START_STOP_CMDLEN  6

static void
scsi_spin(const int fd, const char desired_state) {
  unsigned char cmdblk [ START_STOP_CMDLEN ] =
  { START_STOP,  /* command */
    0,  /* lun(3 bits)/reserved(4 bits)/immed(1 bit) */
    0,  /* reserved */
    0,  /* reserved */
    desired_state ? 1 : 0,  /* reserved(6)/LoEj(1)/Start(1)*/
    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(fd, sizeof(cmdblk), 0, cmd, 0, NULL )) {
    fprintf( stderr, "Inquiry failed\n" );
    exit(2);
  }
}



static void
usage() {
  static char usage_string[] = 
    "usage: scsi-spin ( --up | --down ) device\n"
    "--up   spin up device.\n"
    "--up   spin down device.\n";

  fputs(usage_string, stderr);
}

int
main(int argc, char *argv[]) {
  int result = 0;
  int fd;
  int opt_up = 0;
  int opt_down = 0;
  struct option cmd_line_opts[] = {
    {"up", 0, &opt_up, 1},
    {"down", 0, &opt_down, 1},
    {0, 0, 0, 0},
  };
  
  char c;
  while((c = getopt_long(argc, argv, "", cmd_line_opts, NULL)) != EOF) {
    if(c == ':') {
      usage();
      exit(1);
    }
    if(c == '?') {
      usage();
      exit(1);
    }
  }

  if(opt_up && opt_down) {
    fputs("scsi-spin: specified both --up and --down.  "
          "Is this some kind of test?\n", stderr);
    usage();
    exit(1);
  }

  if(!(opt_up || opt_down)) {
    fputs("scsi-spin: must specify --up or --down.\n", stderr);
    usage();
    exit(1);
  }

  if(optind != (argc - 1)) {
    usage();
    exit(1);
  }

  fd = open(argv[optind], O_RDWR);
  if (fd < 0) {
    fprintf(stderr, "Failure opening %s\n", argv[optind]);
    exit(1);
  }

  {
    struct stat devstat;
    if(stat(argv[optind], &devstat) == -1) {
      fprintf(stderr, "stat on %s failed.\n", argv[optind]);
      close(fd);
      exit(1);
    }
    if(!S_ISCHR(devstat.st_rdev) ||
       major(devstat.st_rdev) != SCSI_GENERIC_MAJOR) {
      fprintf(stderr, "%s is not a generic SCSI device.\n", argv[optind]);
      close(fd);
      exit(1);
    }
  }

  if(opt_up)
    scsi_spin(fd, 1);
  else
    scsi_spin(fd, 0);

  close(fd);
  return result;
}

-- 
Rob Browning <rlb@cs.utexas.edu>
PGP fingerprint = E8 0E 0D 04 F5 21 A0 94  53 2B 97 F5 D6 4E 39 30


Reply to: