Commit b484e436 authored by patmans@us.ibm.com's avatar patmans@us.ibm.com Committed by Greg KH
Browse files

[PATCH] update udev scsi_id to scsi_id 0.4

This patch syncs the scsi_id in the udev tree to version 0.4.
parent 1373b381
2004-feb-25:
* scsi_id.8: Add verbage about usage with udev, and running via
hotplug.
2004-feb-25:
* scsi_id.c, scsi_id.8: Disable support for -e (all output to
stderr) as it cannot be used in any useful way, and the -c
(device specific callout) as the code is incomplete and has no
users.
2004-feb-25:
* scsi_id.c: Don't print errno for NULL return from
sysfs_get_classdev_device.
2004-feb-23:
* scsi_id.c: Get rid of dead/leftover code that checked
if we are on a scsi bus.
2004-feb-23:
* scsi_serial.c, scsi_id.c: Use ":" consistently in output messages.
2004-feb-23:
* scsi_serial.c: Add missing new lines for some error messages.
2004-feb-23:
* scsi_serial.c: open O_NONBLOCK so we handle tape drives without
tapes loaded.
2004-feb-20:
* scsi_id.h, scsi_id.c: Remove hacks based on KLIBC define to get
around problems when building with udev (udev libsysfs files
were rearranged).
2004-feb-19:
* scsi_id.h, scsi_id.c, scsi_serial.c: As done in udev code, support
partitions via looking for a parent of the target path. Uses
libsysfs functions to do most of the work, and includes changing
a lot of variables to be struct sysfs_device instead of
sysfs_class_device.
2004-feb-19:
* Makefile: Version 0.4
2004-jan-15:
* Makefile: Version 0.3
......
......@@ -14,7 +14,7 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
SCSI_ID_VERSION=0.3
SCSI_ID_VERSION=0.4
prefix =
etcdir = ${prefix}/etc
......
- add information about the config file to the man page
- Document that config file options override command line options, or fix
the code. This means a '-b' in the config file disables any -g on the
command line.
- change so non-KLIBC builds under udev don't use /usr/include/sysfs,
but instead use the sysfs included with udev (needs udev change and/or
sysfsutils changes).
- Add code to check that SCSI commands get back enough data for their
intended usage, mainly callers of scsi_inquiry().
- do something with callout code - remove or change to a tag?
This needs an implementation of a device specific callout or device
specific code (called via some special "tag" or such) before it can be
completed. Someone with such hardware to send in a patch.
- Document the config file in the man page
#! /bin/sh
# This script generates and sends to stdout a set of udev.rules for use
# with all scsi block devices on your system. It creates a udev key NAME
# with prefix defaulting to "disk-", and appends the current kernel name
# and the udev kernel number (the partition number, empty for the entire
# disk).
#
# Managing these is probably better done via a gui interface.
#
# You can edit and append the output to your /etc/udev/udev.rules file.
# You probably want to to change names to be non-kernel defaults, so as to
# avoid confusion if a configuration change modifies /sys/block/sd*
# naming.
#
# /etc/scsi_id.config must be properly configured. If you are using this
# script, you probably want a single line enabling scsi_id for all
# devices as follows:
#
# options=-g
#
# The above assumes you will not attach block devices that do not
# properly support the page codes used by scsi_id, this is especially true
# of many USB mass storage devices (mainly flash card readers).
#
prefix=disk-
scsi_id=/sbin/scsi_id
dump_ids()
{
cd ${sysfs_dir}/block
for b in sd*
do
echo -n "$b "
$scsi_id -s /block/$b
if [ $? != 0 ]
then
echo $0 failed for device $b >&2
exit 1
fi
done
}
sysfs_dir=$(mount | awk '$5 == "sysfs" {print $3}')
c=$(ls /${sysfs_dir}/block/sd* 2>/dev/null | wc -l)
if [ $c = 0 ]
then
echo $0 no block devices present >&2
exit 1
fi
echo "#"
echo "# Start of autogenerated scsi_id rules. Edit the NAME portions of these"
echo "# rules to your liking."
echo "#"
first_line=yes
dump_ids | while read in
do
set $in
name=$1
shift
id="$*"
if [ $first_line = "yes" ]
then
first_line=no
echo "BUS=\"scsi\", PROGRAM=\"${scsi_id}\", RESULT=\"${id}\", NAME=\"${prefix}${name}%n\""
echo
echo "# Further RESULT keys use the result of the last PROGRAM rule."
echo "# Be careful not to add any rules containing PROGRAM key between here"
echo "# and the end of this section"
echo
else
# No PROGRAM, so just use the last result of PROGRAM. The
# following is the same as the above without the PROGRAM
# key.
echo "BUS=\"scsi\", RESULT=\"${id}\", NAME=\"${prefix}${name}%n\""
fi
done
echo "#"
echo "# End of autogenerated scsi_id rules"
echo "#"
Version 0.3 of scsi_id is available at:
Version 0.4 of scsi_id is available at:
http://www-124.ibm.com/storageio/scsi_id/scsi_id-0.3.tar.gz
http://www-124.ibm.com/storageio/scsi_id/scsi_id-0.4.tar.gz
scsi_id is a program to generate a SCSI unique identifier for a given SCSI
scsi_id is a program to generate a unique identifier for a given SCSI
device.
It is primarily for use with udev callout config entries. It can also be
used for automatic multi-path configuration or device mapper configuration.
It is primarily for use with the udev callout key. It could also be used
for automatic multi-path configuration or device mapper configuration.
Version 0.3 requires:
Version 0.4 requires:
- Linux kernel 2.6
- libsysfs 0.4.0
Major changes since the last release:
- Changes to work with libsysfs 0.4.0
- Support block device partitions
All changes:
- Added a script to auto-generate udev rules. The script is not
installed but is part of the tarball.
- fix "prefix" usage for path to scsi_id.config
Detailed changes:
- install the sample scsi_id.config file.
- Add man page verbage about usage with udev, and running via
hotplug
- Use DESTDIR in all install/uninstall rules, per problem reported
by Svetoslav Slavtchev.
- Disable support for -e (all output to stderr) as it cannot be
used in any useful way, and the -c (device specific callout) as
the code is incomplete and has no users.
- Fix to work with current sysfs 0.4, based on patch from Dan
Stekloff, but uses sysfs_read_attribute_value instead of
sysfs_get_value_from_attributes.
- Don't print errno for NULL return from sysfs_get_classdev_device.
- SYSFS_BUS_DIR was replaced with SYSFS_BUS_NAME.
- Get rid of dead/leftover code that checked if we are on a scsi
bus.
- Must now use sysfs_open_class_device_path instead of the
previous sysfs_open_class_device.
- ":" consistently in output messages.
- patch from Olaf Hering <olh@suse.de> remove DEBUG and
add --fno-builtin
- Add missing new lines for some error messages.
- open O_NONBLOCK so we handle tape drives without tapes loaded.
- Remove hacks based on KLIBC define to get around problems when
building with udev (udev libsysfs files were rearranged).
- As done in udev code, support partitions via looking for a
parent of the target path. Uses libsysfs functions to do most of
the work, and includes changing a lot of variables to be struct
sysfs_device instead of sysfs_class_device.
......@@ -50,9 +50,13 @@ identifier starts with the NAA value of 6):
.fi
.P
.SH OPTIONS
.TP
.BI subsystem
When called with only a single argument without a leading \-, runs in a hotplug
mode, and expects the environment variable DEVPATH to specify the
corresponding sysfs device. See section below on usage with \fBudev\fP.
.TP
.BI \-b
The default behaviour - treat the device as black listed, and do nothing
unless a white listed device is found in the scsi_id config-file.
......@@ -63,11 +67,6 @@ of determining and creating a device node based on a sysfs dev
entry as done for the \fB-s\fP, send SG_IO commands to
\fBdevice\fP, such as \fB/dev/sdc\fP.
.TP
.BI \-e
Send all output to standard error even if
.B scsi_id
is running in hotplug mode.
.TP
.BI \-f "\| config-file"
Read configuration and black/white list entries from
.B config-file
......@@ -90,7 +89,7 @@ Use SCSI INQUIRY VPD page code 0x80 or 0x83. The default behaviour is to
query the available VPD pages, and use page 0x83 if found, else page 0x80
if found, else nothing.
.TP
.BI \-s "\|sysfs-device"
.BI \-s "\| sysfs-device"
Generate an id for the
.B sysfs-device.
The sysfs mount point must not be included. For example, use /block/sd,
......@@ -102,6 +101,37 @@ Generate verbose debugging output.
.BI \-V
Display version number and exit.
.RE
.SH USAGE WITH UDEV
If \fBscsi_id\fP is invoked with one argument without a leading \-, it
assumes it is called for a hotplug event, and looks for the sysfs device
in the DEVPATH environment variable.
This mode is used when run via the \fBudev\fP PROGRAM key. Passing any
arguments or options as part of the PROGRAM rule breaks this assumption,
and the results will likely not be as expected.
When in this mode, all errors and warnings are sent via syslog.
To determine the specific value needed in a RESULT key, use the -s option,
for example:
.sp
.nf
/sbin/scsi_id -s /block/sda
.fi
.P
An example \fBudev\fP rule using \fBscsi_id\fP, that will name a block
device and any partitions for the device matching the \fBscsi_id\fP output
of 312345:
.sp
.nf
BUS="scsi", PROGRAM="/sbin/scsi_id", RESULT="312345", NAME="disk%n"
.fi
.P
.SH "FILES"
.nf
.ft B
......@@ -110,8 +140,7 @@ Display version number and exit.
.fi
.LP
.SH "SEE ALSO"
.BR udev (8)
, especially the CALLOUT method.
.BR udev (8), hotplug (8)
.SH AUTHORS
Developed by Patrick Mansfield <patmans@us.ibm.com> based on SCSI ID
source included in earlier linux 2.5 kernels, sg_utils source, and SCSI
......
......@@ -33,7 +33,6 @@
#include <ctype.h>
#include <sys/stat.h>
#include <sysfs/libsysfs.h>
#include "scsi_id_version.h"
#include "scsi_id.h"
......@@ -48,11 +47,16 @@
#define TMP_DIR "/tmp"
#define TMP_PREFIX "scsi"
static const char short_options[] = "bc:d:ef:gip:s:vV";
/*
* XXX Note the 'e' (send output to stderr in all cases), and 'c' (callout)
* options are not supported, but other code is still left in place for
* now.
*/
static const char short_options[] = "bd:f:gip:s:vV";
/*
* Just duplicate per dev options.
*/
static const char dev_short_options[] = "bc:gp:";
static const char dev_short_options[] = "bgp:";
char sysfs_mnt_path[SYSFS_PATH_MAX];
......@@ -107,55 +111,6 @@ int sysfs_get_attr(const char *devpath, const char *attr, char *value,
return sysfs_read_attribute_value(attr_path, value, SYSFS_NAME_LEN);
}
static int sysfs_get_actual_dev(const char *sysfs_path, char *dev, int len)
{
dprintf("%s\n", sysfs_path);
strncpy(dev, sysfs_path, len);
strncat(dev, "/device", len);
if (sysfs_get_link(dev, dev, len)) {
if (!hotplug_mode)
log_message(LOG_WARNING, "%s: %s\n", dev,
strerror(errno));
return -1;
}
return 0;
}
/*
* sysfs_is_bus: Given the sysfs_path to a device, return 1 if sysfs_path
* is on bus, 0 if not on bus, and < 0 on error
*/
static int sysfs_is_bus(const char *sysfs_path, const char *bus)
{
char bus_dev_name[SYSFS_PATH_MAX];
char bus_id[SYSFS_NAME_LEN];
struct stat stat_buf;
ino_t dev_inode;
dprintf("%s\n", sysfs_path);
if (sysfs_get_name_from_path(sysfs_path, bus_id, SYSFS_NAME_LEN))
return -1;
snprintf(bus_dev_name, MAX_NAME_LEN, "%s/%s/%s/%s/%s", sysfs_mnt_path,
SYSFS_BUS_NAME, bus, SYSFS_DEVICES_NAME, bus_id);
if (stat(sysfs_path, &stat_buf))
return -1;
dev_inode = stat_buf.st_ino;
if (stat(bus_dev_name, &stat_buf)) {
if (errno == ENOENT)
return 0;
else
return -1;
}
if (dev_inode == stat_buf.st_ino)
return 1;
else
return 0;
}
static int get_major_minor(const char *devpath, int *major, int *minor)
{
char dev_value[MAX_ATTR_LEN];
......@@ -168,7 +123,7 @@ static int get_major_minor(const char *devpath, int *major, int *minor)
* And if sysfsutils changes, check for ENOENT and handle
* it separately.
*/
log_message(LOG_DEBUG, "%s could not get dev attribute: %s\n",
log_message(LOG_DEBUG, "%s: could not get dev attribute: %s\n",
devpath, strerror(errno));
return -1;
}
......@@ -534,7 +489,7 @@ static int set_options(int argc, char **argv, const char *short_opts,
return 0;
}
static int per_dev_options(struct sysfs_class_device *scsi_dev, int *good_bad,
static int per_dev_options(struct sysfs_device *scsi_dev, int *good_bad,
int *page_code, char *callout)
{
int retval;
......@@ -628,9 +583,10 @@ static int scsi_id(const char *target_path, char *maj_min_dev)
{
int retval;
int dev_type = 0;
char full_dev_path[MAX_NAME_LEN];
char serial[MAX_SERIAL_LEN];
struct sysfs_class_device *scsi_dev; /* of scsi_device full_dev_path */
struct sysfs_class_device *class_dev; /* of target_path */
struct sysfs_class_device *class_dev_parent; /* for partitions */
struct sysfs_device *scsi_dev; /* the scsi_device */
int good_dev;
int page_code;
char callout[MAX_NAME_LEN];
......@@ -661,20 +617,48 @@ static int scsi_id(const char *target_path, char *maj_min_dev)
}
}
if (sysfs_get_actual_dev(target_path, full_dev_path, MAX_NAME_LEN))
class_dev = sysfs_open_class_device_path(target_path);
if (!class_dev) {
log_message(LOG_WARNING, "open class %s failed: %s\n",
target_path, strerror(errno));
return 1;
}
class_dev_parent = sysfs_get_classdev_parent(class_dev);
dprintf("class_dev 0x%p; class_dev_parent 0x%p\n", class_dev,
class_dev_parent);
if (class_dev_parent) {
scsi_dev = sysfs_get_classdev_device(class_dev_parent);
} else {
scsi_dev = sysfs_get_classdev_device(class_dev);
}
/*
* The close of scsi_dev will close class_dev or class_dev_parent.
*/
/*
* We assume we are called after the device is completely ready,
* so we don't have to loop here like udev. (And we are usually
* called via udev.)
*/
if (!scsi_dev) {
/*
* errno is not set if we can't find the device link, so
* don't print it out here.
*/
log_message(LOG_WARNING, "Cannot find sysfs device associated with %s\n",
target_path);
return 1;
}
dprintf("full_dev_path %s\n", full_dev_path);
/*
* Allow only scsi devices (those that have a matching device
* under /bus/scsi/devices).
* Allow only scsi devices.
*
* Other block devices can support SG IO, but only ide-cd does, so
* for now, don't bother with anything else.
*/
retval = sysfs_is_bus(full_dev_path, "scsi");
if (retval == 0) {
if (strcmp(scsi_dev->bus, "scsi") != 0) {
if (hotplug_mode)
/*
* Expected in some cases.
......@@ -684,14 +668,12 @@ static int scsi_id(const char *target_path, char *maj_min_dev)
log_message(LOG_WARNING, "%s is not a scsi device\n",
target_path);
return 1;
} else if (retval < 0) {
log_message(LOG_WARNING, "sysfs_is_bus failed: %s\n",
strerror(errno));
return 1;
}
/*
* mknod a temp dev to communicate with the device.
*
* XXX pass down class_dev or class_dev_parent.
*/
if (!dev_specified && create_tmp_dev(target_path, maj_min_dev,
dev_type)) {
......@@ -699,13 +681,6 @@ static int scsi_id(const char *target_path, char *maj_min_dev)
return 1;
}
scsi_dev = sysfs_open_class_device_path(full_dev_path);
if (!scsi_dev) {
log_message(LOG_WARNING, "open class %s failed: %s\n",
full_dev_path, strerror(errno));
return 1;
}
/*
* Get any per device (vendor + model) options from the config
* file.
......@@ -718,14 +693,7 @@ static int scsi_id(const char *target_path, char *maj_min_dev)
retval = 1;
} else if (callout[0] != '\0') {
/*
* exec vendor callout, pass it only the "name" to be used
* for error messages, and the dev to open.
*
* This won't work if we need to pass on the original
* command line (when not hotplug mode) since the option
* parsing and per dev parsing modify the argv's.
*
* XXX Not implemented yet. And not fully tested ;-)
* XXX Disabled for now ('c' is not in any options[]).
*/
retval = 1;
} else if (scsi_get_serial(scsi_dev, maj_min_dev, page_code,
......@@ -736,14 +704,14 @@ static int scsi_id(const char *target_path, char *maj_min_dev)
}
if (!retval) {
if (display_bus_id)
printf("%s ", scsi_dev->name);
printf("%s: ", scsi_dev->name);
printf("%s", serial);
if (!hotplug_mode)
printf("\n");
dprintf("%s\n", serial);
retval = 0;
}
sysfs_close_class_device(scsi_dev);
sysfs_close_device(scsi_dev);
if (!dev_specified)
unlink(maj_min_dev);
......
......@@ -47,9 +47,9 @@
extern int sysfs_get_attr(const char *devpath, const char *attr, char *value,
size_t bufsize);
extern int scsi_get_serial (struct sysfs_class_device *scsi_dev,
const char *devname, int page_code, char *serial,
int len);
extern int scsi_get_serial (struct sysfs_device *scsi_dev, const char
*devname, int page_code, char *serial, int
len);
extern void log_message (int level, const char *format, ...)
__attribute__ ((format (printf, 2, 3)));
......
......@@ -32,7 +32,6 @@
#include <syslog.h>
#include <scsi/sg.h>
#include <sysfs/libsysfs.h>
#include "scsi_id.h"
#include "scsi.h"
......@@ -70,12 +69,6 @@ static const struct scsi_id_search_values id_search_list[] = {
static const char hex_str[]="0123456789abcdef";
/*
* XXX maybe move all these to an sg_io.c file.
*
* From here ...
*/
/*
* Values returned in the result/status, only the ones used by the code
* are used here.
......@@ -160,8 +153,7 @@ static int sg_err_category3(struct sg_io_hdr *hp)
hp->sbp, hp->sb_len_wr);
}
static int scsi_dump_sense(struct sysfs_class_device *scsi_dev,
struct sg_io_hdr *io)
static int scsi_dump_sense(struct sysfs_device *scsi_dev, struct sg_io_hdr *io)
{
unsigned char *sense_buffer;
int s;
......@@ -257,7 +249,7 @@ static int scsi_dump_sense(struct sysfs_class_device *scsi_dev,
scsi_dev->name, sense_buffer[0],
sense_buffer[2]);
log_message(LOG_WARNING,
"%s: non-extended sense class %d code 0x%0x ",
"%s: non-extended sense class %d code 0x%0x\n",
scsi_dev->name, sense_class, code);
}
......@@ -277,7 +269,7 @@ static int scsi_dump_sense(struct sysfs_class_device *scsi_dev,
return -1;
}
static int scsi_dump(struct sysfs_class_device *scsi_dev, struct sg_io_hdr *io)
static int scsi_dump(struct sysfs_device *scsi_dev, struct sg_io_hdr *io)
{
if (!io->status && !io->host_status && !io->msg_status &&
!io->driver_status) {
......@@ -298,9 +290,9 @@ static int scsi_dump(struct sysfs_class_device *scsi_dev, struct sg_io_hdr *io)
return -1;
}
static int scsi_inquiry(struct sysfs_class_device *scsi_dev, int fd,
unsigned char evpd, unsigned char page, unsigned
char *buf, unsigned int buflen)
static int scsi_inquiry(struct sysfs_device *scsi_dev, int fd, unsigned
char evpd, unsigned char page, unsigned char *buf,
unsigned int buflen)
{
unsigned char inq_cmd[INQUIRY_CMDLEN] =
{ INQUIRY_CMD, evpd, page, 0, buflen, 0 };
......@@ -332,7 +324,7 @@ resend:
io_hdr.timeout = DEF_TIMEOUT;
if (ioctl(fd, SG_IO, &io_hdr) < 0) {
log_message(LOG_WARNING, "%s ioctl failed: %s\n",
log_message(LOG_WARNING, "%s: ioctl failed: %s\n",
scsi_dev->name, strerror(errno));
return -1;
}
......@@ -349,11 +341,6 @@ resend:
retval = scsi_dump(scsi_dev, &io_hdr);
}
/*
* XXX where is the length checked? That is, was our request
* buffer long enough?
*/
if (!retval) {
retval = buflen;
memcpy(buf, buffer, retval);
......@@ -369,13 +356,7 @@ resend:
return retval;
}
/*
* XXX maybe move all these to an sg_io.c file.
*
* Ending here.
*/