just like prioritizers.
A lot of files shuffling too.
BUILDDIRS = \
libmultipath \
libmultipath/prioritizers \
- libcheckers \
+ libmultipath/checkers \
multipath \
multipathd \
devmap_name \
exec_prefix = $(prefix)
bindir = $(exec_prefix)/sbin
libudevdir = ${prefix}/lib/udev
-checkersdir = $(TOPDIR)/libcheckers
multipathdir = $(TOPDIR)/libmultipath
mandir = $(prefix)/usr/share/man/man8
man5dir = $(prefix)/usr/share/man/man5
+++ /dev/null
-# Makefile
-#
-# Copyright (C) 2003 Christophe Varoqui, <christophe.varoqui@free.fr>
-#
-include ../Makefile.inc
-
-LIBS = libcheckers.so
-OBJS = libsg.o checkers.o readsector0.o tur.o directio.o emc_clariion.o hp_sw.o rdac.o
-
-all: $(LIBS)
-
-$(LIBS): $(OBJS)
- $(CC) $(SHARED_FLAGS) -o $@ $^
-
-install:
- $(INSTALL_PROGRAM) -o root -g root -m 755 $(LIBS) $(libdir)
-
-uninstall:
- rm -f $(libdir)/$(LIBS)
-
-clean:
- rm -f core *.a *.o *.gz *.so
+++ /dev/null
-#include <stdio.h>
-#include <string.h>
-
-#include "checkers.h"
-
-#include "directio.h"
-#include "tur.h"
-#include "hp_sw.h"
-#include "emc_clariion.h"
-#include "rdac.h"
-#include "readsector0.h"
-
-static struct checker checkers[] = {
- {
- .fd = 0,
- .sync = 1,
- .name = DIRECTIO,
- .message = "",
- .context = NULL,
- .check = directio,
- .init = directio_init,
- .free = directio_free
- },
- {
- .fd = 0,
- .sync = 1,
- .name = TUR,
- .message = "",
- .context = NULL,
- .check = tur,
- .init = tur_init,
- .free = tur_free
- },
- {
- .fd = 0,
- .sync = 1,
- .name = HP_SW,
- .message = "",
- .context = NULL,
- .check = hp_sw,
- .init = hp_sw_init,
- .free = hp_sw_free
- },
- {
- .fd = 0,
- .sync = 1,
- .name = EMC_CLARIION,
- .message = "",
- .context = NULL,
- .check = emc_clariion,
- .init = emc_clariion_init,
- .free = emc_clariion_free
- },
- {
- .fd = 0,
- .sync = 1,
- .name = RDAC,
- .message = "",
- .context = NULL,
- .check = rdac,
- .init = rdac_init,
- .free = rdac_free
- },
- {
- .fd = 0,
- .sync = 1,
- .name = READSECTOR0,
- .message = "",
- .context = NULL,
- .check = readsector0,
- .init = readsector0_init,
- .free = readsector0_free
- },
- {0, 1, 0, "", "", NULL, NULL, NULL, NULL},
-};
-
-void checker_set_fd (struct checker * c, int fd)
-{
- c->fd = fd;
-}
-
-void checker_set_sync (struct checker * c)
-{
- c->sync = 1;
-}
-
-void checker_set_async (struct checker * c)
-{
- c->sync = 0;
-}
-
-void checker_enable (struct checker * c)
-{
- c->disable = 0;
-}
-
-void checker_disable (struct checker * c)
-{
- c->disable = 1;
-}
-
-struct checker * checker_lookup (char * name)
-{
- struct checker * c = &checkers[0];
-
- while (c->check) {
- if (!strncmp(name, c->name, CHECKER_NAME_LEN))
- return c;
- c++;
- }
- return NULL;
-}
-
-int checker_init (struct checker * c, void ** mpctxt_addr)
-{
- c->mpcontext = mpctxt_addr;
- return c->init(c);
-}
-
-void checker_put (struct checker * c)
-{
- if (c->free)
- c->free(c);
- memset(c, 0x0, sizeof(struct checker));
-}
-
-int checker_check (struct checker * c)
-{
- int r;
-
- if (c->disable)
- return PATH_UNCHECKED;
- if (c->fd <= 0) {
- MSG(c, "no usable fd");
- return PATH_WILD;
- }
- r = c->check(c);
-
- return r;
-}
-
-int checker_selected (struct checker * c)
-{
- return (c->check) ? 1 : 0;
-}
-
-char * checker_name (struct checker * c)
-{
- return c->name;
-}
-
-char * checker_message (struct checker * c)
-{
- return c->message;
-}
-
-struct checker * checker_default (void)
-{
- return checker_lookup(DEFAULT_CHECKER);
-}
-
-void checker_get (struct checker * dst, struct checker * src)
-{
- dst->fd = src->fd;
- dst->sync = src->sync;
- strncpy(dst->name, src->name, CHECKER_NAME_LEN);
- strncpy(dst->message, src->message, CHECKER_MSG_LEN);
- dst->check = src->check;
- dst->init = src->init;
- dst->free = src->free;
-}
+++ /dev/null
-#ifndef _CHECKERS_H
-#define _CHECKERS_H
-
-/*
- *
- * Userspace (multipath/multipathd) path states
- *
- * PATH_WILD:
- * - Use: None of the checkers (returned if we don't have an fd)
- * - Description: Corner case where "fd <= 0" for path fd (see checker_check())
- *
- * PATH_UNCHECKED:
- * - Use: Only in directio checker
- * - Description: set when fcntl(F_GETFL) fails to return flags or O_DIRECT
- * not include in flags, or O_DIRECT read fails
- * - Notes:
- * - multipathd: uses it to skip over paths in sync_map_state()
- * - multipath: used in update_paths(); if state==PATH_UNCHECKED, call
- * pathinfo()
- *
- * PATH_DOWN:
- * - Use: All checkers (directio, emc_clariion, hp_sw, readsector0, tur)
- * - Description: Either a) SG_IO ioctl failed, or b) check condition on some
- * SG_IO ioctls that succeed (tur, readsector0 checkers); path is down and
- * you shouldn't try to send commands to it
- *
- * PATH_UP:
- * - Use: All checkers (directio, emc_clariion, hp_sw, readsector0, tur)
- * - Description: Path is up and I/O can be sent to it
- *
- * PATH_SHAKY:
- * - Use: Only emc_clariion
- * - Description: Indicates path not available for "normal" operations
- *
- * PATH_GHOST:
- * - Use: Only hp_sw
- * - Description: Indicates a "passive/standby" path on active/passive HP
- * arrays. These paths will return valid answers to certain SCSI commands
- * (tur, read_capacity, inquiry, start_stop), but will fail I/O commands.
- * The path needs an initialization command to be sent to it in order for
- * I/Os to succeed.
- *
- * PATH_PENDING:
- * - Use: All async checkers
- * - Description: Indicates a check IO is in flight.
- */
-#define PATH_WILD -1
-#define PATH_UNCHECKED 0
-#define PATH_DOWN 1
-#define PATH_UP 2
-#define PATH_SHAKY 3
-#define PATH_GHOST 4
-#define PATH_PENDING 5
-
-#define DIRECTIO "directio"
-#define TUR "tur"
-#define HP_SW "hp_sw"
-#define RDAC "rdac"
-#define EMC_CLARIION "emc_clariion"
-#define READSECTOR0 "readsector0"
-
-#define DEFAULT_CHECKER DIRECTIO
-
-/*
- * Overloaded storage response time can be very long.
- * SG_IO timouts after DEF_TIMEOUT milliseconds, and checkers interprets this
- * as a path failure. multipathd then proactively evicts the path from the DM
- * multipath table in this case.
- *
- * This generaly snow balls and ends up in full eviction and IO errors for end
- * users. Bad. This may also cause SCSI bus resets, causing disruption for all
- * local and external storage hardware users.
- *
- * Provision a long timeout. Longer than any real-world application would cope
- * with.
- */
-#define DEF_TIMEOUT 300000
-#define ASYNC_TIMEOUT_SEC 30
-
-/*
- * strings lengths
- */
-#define CHECKER_NAME_LEN 16
-#define CHECKER_MSG_LEN 256
-#define CHECKER_DEV_LEN 256
-
-struct checker {
- int fd;
- int sync;
- int disable;
- char name[CHECKER_NAME_LEN];
- char message[CHECKER_MSG_LEN]; /* comm with callers */
- void * context; /* store for persistent data */
- void ** mpcontext; /* store for persistent data
- shared multipath-wide */
- int (*check)(struct checker *);
- int (*init)(struct checker *); /* to allocate the context */
- void (*free)(struct checker *); /* to free the context */
-};
-
-#define MSG(c, fmt, args...) snprintf((c)->message, CHECKER_MSG_LEN, fmt, ##args);
-
-int checker_init (struct checker *, void **);
-void checker_put (struct checker *);
-void checker_reset (struct checker *);
-void checker_set_sync (struct checker *);
-void checker_set_async (struct checker *);
-void checker_set_fd (struct checker *, int);
-void checker_enable (struct checker *);
-void checker_disable (struct checker *);
-struct checker * checker_lookup (char *);
-int checker_check (struct checker *);
-int checker_selected (struct checker *);
-char * checker_name (struct checker *);
-char * checker_message (struct checker *);
-struct checker * checker_default (void);
-void checker_get (struct checker *, struct checker *);
-
-#endif /* _CHECKERS_H */
+++ /dev/null
-/*
- * Copyright (c) 2005 Hannes Reinecke, Suse
- */
-#define _GNU_SOURCE
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <linux/fs.h>
-#include <errno.h>
-#include <linux/kdev_t.h>
-#include <asm/unistd.h>
-#include <libaio.h>
-
-#include "checkers.h"
-#include "../libmultipath/debug.h"
-
-#define MSG_DIRECTIO_UNKNOWN "directio checker is not available"
-#define MSG_DIRECTIO_UP "directio checker reports path is up"
-#define MSG_DIRECTIO_DOWN "directio checker reports path is down"
-#define MSG_DIRECTIO_PENDING "directio checker is waiting on aio"
-
-#define LOG(prio, fmt, args...) condlog(prio, "directio: " fmt, ##args)
-
-struct directio_context {
- int running;
- int reset_flags;
- int blksize;
- unsigned char * buf;
- unsigned char * ptr;
- io_context_t ioctx;
- struct iocb io;
-};
-
-
-int directio_init (struct checker * c)
-{
- unsigned long pgsize = getpagesize();
- struct directio_context * ct;
- long flags;
-
- ct = malloc(sizeof(struct directio_context));
- if (!ct)
- return 1;
- memset(ct, 0, sizeof(struct directio_context));
-
- if (io_setup(1, &ct->ioctx) != 0) {
- condlog(1, "io_setup failed");
- free(ct);
- return 1;
- }
-
- if (ioctl(c->fd, BLKBSZGET, &ct->blksize) < 0) {
- MSG(c, "cannot get blocksize, set default");
- ct->blksize = 512;
- }
- if (ct->blksize > 4096) {
- /*
- * Sanity check for DASD; BSZGET is broken
- */
- ct->blksize = 4096;
- }
- if (!ct->blksize)
- goto out;
- ct->buf = (unsigned char *)malloc(ct->blksize + pgsize);
- if (!ct->buf)
- goto out;
-
- flags = fcntl(c->fd, F_GETFL);
- if (flags < 0)
- goto out;
- if (!(flags & O_DIRECT)) {
- flags |= O_DIRECT;
- if (fcntl(c->fd, F_SETFL, flags) < 0)
- goto out;
- ct->reset_flags = 1;
- }
-
- ct->ptr = (unsigned char *) (((unsigned long)ct->buf + pgsize - 1) &
- (~(pgsize - 1)));
-
- /* Sucessfully initialized, return the context. */
- c->context = (void *) ct;
- return 0;
-
-out:
- if (ct->buf)
- free(ct->buf);
- io_destroy(ct->ioctx);
- free(ct);
- return 1;
-}
-
-void directio_free (struct checker * c)
-{
- struct directio_context * ct = (struct directio_context *)c->context;
- long flags;
-
- if (!ct)
- return;
-
- if (ct->reset_flags) {
- if ((flags = fcntl(c->fd, F_GETFL)) >= 0) {
- flags &= ~O_DIRECT;
- /* No point in checking for errors */
- fcntl(c->fd, F_SETFL, flags);
- }
- }
-
- if (ct->buf)
- free(ct->buf);
- io_destroy(ct->ioctx);
- free(ct);
-}
-
-static int
-check_state(int fd, struct directio_context *ct, int sync)
-{
- struct timespec timeout = { .tv_nsec = 5 };
- struct io_event event;
- struct stat sb;
- int rc = PATH_UNCHECKED;
- long r;
-
- if (fstat(fd, &sb) == 0) {
- LOG(4, "called for %x", (unsigned) sb.st_rdev);
- }
- if (sync) {
- LOG(4, "called in synchronous mode");
- timeout.tv_sec = ASYNC_TIMEOUT_SEC;
- timeout.tv_nsec = 0;
- }
-
- if (!ct->running) {
- struct iocb *ios[1] = { &ct->io };
-
- LOG(3, "starting new request");
- memset(&ct->io, 0, sizeof(struct iocb));
- io_prep_pread(&ct->io, fd, ct->ptr, ct->blksize, 0);
- if (io_submit(ct->ioctx, 1, ios) != 1) {
- LOG(3, "io_submit error %i", errno);
- return PATH_UNCHECKED;
- }
- }
- ct->running++;
-
- r = io_getevents(ct->ioctx, 1L, 1L, &event, &timeout);
- LOG(3, "async io getevents returns %li (errno=%s)", r, strerror(errno));
-
- if (r < 1L) {
- if (ct->running > ASYNC_TIMEOUT_SEC || sync) {
- LOG(3, "abort check on timeout");
- rc = PATH_DOWN;
- } else
- rc = PATH_PENDING;
- } else {
- LOG(3, "io finished %lu/%lu", event.res, event.res2);
- ct->running = 0;
- rc = (event.res == ct->blksize) ? PATH_UP : PATH_DOWN;
- }
-
- return rc;
-}
-
-int directio (struct checker * c)
-{
- int ret;
- struct directio_context * ct = (struct directio_context *)c->context;
-
- if (!ct)
- return PATH_UNCHECKED;
-
- ret = check_state(c->fd, ct, c->sync);
-
- switch (ret)
- {
- case PATH_UNCHECKED:
- MSG(c, MSG_DIRECTIO_UNKNOWN);
- break;
- case PATH_DOWN:
- MSG(c, MSG_DIRECTIO_DOWN);
- break;
- case PATH_UP:
- MSG(c, MSG_DIRECTIO_UP);
- break;
- case PATH_PENDING:
- MSG(c, MSG_DIRECTIO_PENDING);
- break;
- default:
- break;
- }
- return ret;
-}
+++ /dev/null
-#ifndef _DIRECTIO_H
-#define _DIRECTIO_H
-
-int directio (struct checker *);
-int directio_init (struct checker *);
-void directio_free (struct checker *);
-
-#endif /* _DIRECTIO_H */
+++ /dev/null
-/*
- * Copyright (c) 2004, 2005 Lars Marowsky-Bree
- */
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <errno.h>
-
-#include "../libmultipath/sg_include.h"
-#include "libsg.h"
-#include "checkers.h"
-
-#define INQUIRY_CMD 0x12
-#define INQUIRY_CMDLEN 6
-#define HEAVY_CHECK_COUNT 10
-
-/*
- * Mechanism to track CLARiiON inactive snapshot LUs.
- * This is done so that we can fail passive paths
- * to an inactive snapshot LU even though since a
- * simple read test would return 02/04/03 instead
- * of 05/25/01 sensekey/ASC/ASCQ data.
- */
-#define IS_INACTIVE_SNAP(c) (c->mpcontext ? \
- ((struct emc_clariion_checker_LU_context *) \
- (*c->mpcontext))->inactive_snap \
- : 0)
-
-#define SET_INACTIVE_SNAP(c) if (c->mpcontext) \
- ((struct emc_clariion_checker_LU_context *)\
- (*c->mpcontext))->inactive_snap = 1
-
-#define CLR_INACTIVE_SNAP(c) if (c->mpcontext) \
- ((struct emc_clariion_checker_LU_context *)\
- (*c->mpcontext))->inactive_snap = 0
-
-struct emc_clariion_checker_path_context {
- char wwn[16];
- unsigned wwn_set;
-};
-
-struct emc_clariion_checker_LU_context {
- int inactive_snap;
-};
-
-extern void
-hexadecimal_to_ascii(char * wwn, char *wwnstr)
-{
- int i,j, nbl;
-
- for (i=0,j=0;i<16;i++) {
- wwnstr[j++] = ((nbl = ((wwn[i]&0xf0) >> 4)) <= 9) ?
- '0' + nbl : 'a' + (nbl - 10);
- wwnstr[j++] = ((nbl = (wwn[i]&0x0f)) <= 9) ?
- '0' + nbl : 'a' + (nbl - 10);
- }
- wwnstr[32]=0;
-}
-
-int emc_clariion_init (struct checker * c)
-{
- /*
- * Allocate and initialize the path specific context.
- */
- c->context = malloc(sizeof(struct emc_clariion_checker_path_context));
- if (!c->context)
- return 1;
- ((struct emc_clariion_checker_path_context *)c->context)->wwn_set = 0;
-
- /*
- * Allocate and initialize the multi-path global context.
- */
- if (c->mpcontext) {
- void * mpctxt = malloc(sizeof(int));
- *c->mpcontext = mpctxt;
- CLR_INACTIVE_SNAP(c);
- }
-
- return 0;
-}
-
-void emc_clariion_free (struct checker * c)
-{
- free(c->context);
-}
-
-int emc_clariion(struct checker * c)
-{
- unsigned char sense_buffer[128] = { 0, };
- unsigned char sb[SENSE_BUFF_LEN] = { 0, }, *sbb;
- unsigned char inqCmdBlk[INQUIRY_CMDLEN] = {INQUIRY_CMD, 1, 0xC0, 0,
- sizeof(sense_buffer), 0};
- struct sg_io_hdr io_hdr;
- struct emc_clariion_checker_path_context * ct =
- (struct emc_clariion_checker_path_context *)c->context;
- char wwnstr[33];
- int ret;
-
- memset(&io_hdr, 0, sizeof (struct sg_io_hdr));
- io_hdr.interface_id = 'S';
- io_hdr.cmd_len = sizeof (inqCmdBlk);
- io_hdr.mx_sb_len = sizeof (sb);
- io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
- io_hdr.dxfer_len = sizeof (sense_buffer);
- io_hdr.dxferp = sense_buffer;
- io_hdr.cmdp = inqCmdBlk;
- io_hdr.sbp = sb;
- io_hdr.timeout = DEF_TIMEOUT;
- io_hdr.pack_id = 0;
- if (ioctl(c->fd, SG_IO, &io_hdr) < 0) {
- MSG(c, "emc_clariion_checker: sending query command failed");
- return PATH_DOWN;
- }
- if (io_hdr.info & SG_INFO_OK_MASK) {
- MSG(c, "emc_clariion_checker: query command indicates error");
- return PATH_DOWN;
- }
- if (/* Verify the code page - right page & revision */
- sense_buffer[1] != 0xc0 || sense_buffer[9] != 0x00) {
- MSG(c, "emc_clariion_checker: Path unit report page in "
- "unknown format");
- return PATH_DOWN;
- }
-
- if ( /* Effective initiator type */
- sense_buffer[27] != 0x03
- /*
- * Failover mode should be set to 1 (PNR failover mode)
- * or 4 (ALUA failover mode).
- */
- || (((sense_buffer[28] & 0x07) != 0x04) &&
- ((sense_buffer[28] & 0x07) != 0x06))
- /* Arraycommpath should be set to 1 */
- || (sense_buffer[30] & 0x04) != 0x04) {
- MSG(c, "emc_clariion_checker: Path not correctly configured "
- "for failover");
- return PATH_DOWN;
- }
-
- if ( /* LUN operations should indicate normal operations */
- sense_buffer[48] != 0x00) {
- MSG(c, "emc_clariion_checker: Path not available for normal "
- "operations");
- return PATH_SHAKY;
- }
-
- if ( /* LUN should at least be bound somewhere and not be LUNZ */
- sense_buffer[4] == 0x00) {
- MSG(c, "emc_clariion_checker: Logical Unit is unbound "
- "or LUNZ");
- return PATH_DOWN;
- }
-
- /*
- * store the LUN WWN there and compare that it indeed did not
- * change in between, to protect against the path suddenly
- * pointing somewhere else.
- */
- if (ct->wwn_set) {
- if (memcmp(ct->wwn, &sense_buffer[10], 16) != 0) {
- MSG(c, "emc_clariion_checker: Logical Unit WWN "
- "has changed!");
- return PATH_DOWN;
- }
- } else {
- memcpy(ct->wwn, &sense_buffer[10], 16);
- ct->wwn_set = 1;
- }
-
- /*
- * Issue read on active path to determine if inactive snapshot.
- */
- if (sense_buffer[4] == 2) {/* if active path */
- unsigned char buf[4096];
-
- ret = sg_read(c->fd, &buf[0], sbb = &sb[0]);
- if (ret == PATH_DOWN) {
- hexadecimal_to_ascii(ct->wwn, wwnstr);
-
- /*
- * Check for inactive snapshot LU this way. Must
- * fail these.
- */
- if (((sbb[2]&0xf) == 5) && (sbb[12] == 0x25) &&
- (sbb[13]==1)) {
- /*
- * Do this so that we can fail even the
- * passive paths which will return
- * 02/04/03 not 05/25/01 on read.
- */
- SET_INACTIVE_SNAP(c);
- MSG(c, "emc_clariion_checker: Active "
- "path to inactive snapshot WWN %s.",
- wwnstr);
- } else
- MSG(c, "emc_clariion_checker: Read "
- "error for WWN %s. Sense data are "
- "0x%x/0x%x/0x%x.", wwnstr,
- sbb[2]&0xf, sbb[12], sbb[13]);
- } else {
- MSG(c, "emc_clariion_checker: Active path is "
- "healthy.");
- /*
- * Remove the path from the set of paths to inactive
- * snapshot LUs if it was in this list since the
- * snapshot is no longer inactive.
- */
- CLR_INACTIVE_SNAP(c);
- }
- } else {
- if (IS_INACTIVE_SNAP(c)) {
- hexadecimal_to_ascii(ct->wwn, wwnstr);
- MSG(c, "emc_clariion_checker: Passive "
- "path to inactive snapshot WWN %s.",
- wwnstr);
- ret = PATH_DOWN;
- } else {
- MSG(c,
- "emc_clariion_checker: Passive path is healthy.");
- ret = PATH_UP; /* not ghost */
- }
- }
-
- return ret;
-}
+++ /dev/null
-#ifndef _EMC_CLARIION_H
-#define _EMC_CLARIION_H
-
-int emc_clariion (struct checker *);
-int emc_clariion_init (struct checker *);
-void emc_clariion_free (struct checker *);
-
-#endif /* _EMC_CLARIION_H */
+++ /dev/null
-/*
- * Copyright (c) 2005 Christophe Varoqui
- */
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <errno.h>
-
-#include "checkers.h"
-
-#include "../libmultipath/sg_include.h"
-
-#define TUR_CMD_LEN 6
-#define INQUIRY_CMDLEN 6
-#define INQUIRY_CMD 0x12
-#define SENSE_BUFF_LEN 32
-#define SCSI_CHECK_CONDITION 0x2
-#define SCSI_COMMAND_TERMINATED 0x22
-#define SG_ERR_DRIVER_SENSE 0x08
-#define RECOVERED_ERROR 0x01
-#define MX_ALLOC_LEN 255
-#define HEAVY_CHECK_COUNT 10
-
-#define MSG_HP_SW_UP "hp_sw checker reports path is up"
-#define MSG_HP_SW_DOWN "hp_sw checker reports path is down"
-#define MSG_HP_SW_GHOST "hp_sw checker reports path is ghost"
-
-struct sw_checker_context {
- void * dummy;
-};
-
-int hp_sw_init (struct checker * c)
-{
- return 0;
-}
-
-void hp_sw_free (struct checker * c)
-{
- return;
-}
-
-static int
-do_inq(int sg_fd, int cmddt, int evpd, unsigned int pg_op,
- void *resp, int mx_resp_len, int noisy)
-{
- unsigned char inqCmdBlk[INQUIRY_CMDLEN] =
- { INQUIRY_CMD, 0, 0, 0, 0, 0 };
- unsigned char sense_b[SENSE_BUFF_LEN];
- struct sg_io_hdr io_hdr;
-
- if (cmddt)
- inqCmdBlk[1] |= 2;
- if (evpd)
- inqCmdBlk[1] |= 1;
- inqCmdBlk[2] = (unsigned char) pg_op;
- inqCmdBlk[3] = (unsigned char)((mx_resp_len >> 8) & 0xff);
- inqCmdBlk[4] = (unsigned char) (mx_resp_len & 0xff);
- memset(&io_hdr, 0, sizeof (struct sg_io_hdr));
- io_hdr.interface_id = 'S';
- io_hdr.cmd_len = sizeof (inqCmdBlk);
- io_hdr.mx_sb_len = sizeof (sense_b);
- io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
- io_hdr.dxfer_len = mx_resp_len;
- io_hdr.dxferp = resp;
- io_hdr.cmdp = inqCmdBlk;
- io_hdr.sbp = sense_b;
- io_hdr.timeout = DEF_TIMEOUT;
-
- if (ioctl(sg_fd, SG_IO, &io_hdr) < 0)
- return 1;
-
- /* treat SG_ERR here to get rid of sg_err.[ch] */
- io_hdr.status &= 0x7e;
- if ((0 == io_hdr.status) && (0 == io_hdr.host_status) &&
- (0 == io_hdr.driver_status))
- return 0;
- if ((SCSI_CHECK_CONDITION == io_hdr.status) ||
- (SCSI_COMMAND_TERMINATED == io_hdr.status) ||
- (SG_ERR_DRIVER_SENSE == (0xf & io_hdr.driver_status))) {
- if (io_hdr.sbp && (io_hdr.sb_len_wr > 2)) {
- int sense_key;
- unsigned char * sense_buffer = io_hdr.sbp;
- if (sense_buffer[0] & 0x2)
- sense_key = sense_buffer[1] & 0xf;
- else
- sense_key = sense_buffer[2] & 0xf;
- if(RECOVERED_ERROR == sense_key)
- return 0;
- }
- }
- return 1;
-}
-
-static int
-do_tur (int fd)
-{
- unsigned char turCmdBlk[TUR_CMD_LEN] = { 0x00, 0, 0, 0, 0, 0 };
- struct sg_io_hdr io_hdr;
- unsigned char sense_buffer[32];
-
- memset(&io_hdr, 0, sizeof (struct sg_io_hdr));
- io_hdr.interface_id = 'S';
- io_hdr.cmd_len = sizeof (turCmdBlk);
- io_hdr.mx_sb_len = sizeof (sense_buffer);
- io_hdr.dxfer_direction = SG_DXFER_NONE;
- io_hdr.cmdp = turCmdBlk;
- io_hdr.sbp = sense_buffer;
- io_hdr.timeout = DEF_TIMEOUT;
- io_hdr.pack_id = 0;
-
- if (ioctl(fd, SG_IO, &io_hdr) < 0)
- return 1;
-
- if (io_hdr.info & SG_INFO_OK_MASK)
- return 1;
-
- return 0;
-}
-
-extern int
-hp_sw (struct checker * c)
-{
- char buff[MX_ALLOC_LEN];
-
- if (0 != do_inq(c->fd, 0, 1, 0x80, buff, MX_ALLOC_LEN, 0)) {
- MSG(c, MSG_HP_SW_DOWN);
- return PATH_DOWN;
- }
-
- if (do_tur(c->fd)) {
- MSG(c, MSG_HP_SW_GHOST);
- return PATH_GHOST;
- }
- MSG(c, MSG_HP_SW_UP);
- return PATH_UP;
-}
+++ /dev/null
-#ifndef _HP_SW_H
-#define _HP_SW_H
-
-int hp_sw (struct checker *);
-int hp_sw_init (struct checker *);
-void hp_sw_free (struct checker *);
-
-#endif /* _HP_SW_H */
+++ /dev/null
-/*
- * Copyright (c) 2004, 2005 Christophe Varoqui
- */
-#include <string.h>
-#include <sys/ioctl.h>
-#include <errno.h>
-#include <sys/stat.h>
-
-#include "checkers.h"
-#include "libsg.h"
-#include "../libmultipath/sg_include.h"
-
-int
-sg_read (int sg_fd, unsigned char * buff, unsigned char * senseBuff)
-{
- /* defaults */
- int blocks = 1;
- long long start_block = 0;
- int bs = 512;
- int cdbsz = 10;
- int * diop = NULL;
-
- unsigned char rdCmd[cdbsz];
- unsigned char *sbb = senseBuff;
- struct sg_io_hdr io_hdr;
- int res;
- int rd_opcode[] = {0x8, 0x28, 0xa8, 0x88};
- int sz_ind;
- struct stat filestatus;
- int retry_count = 3;
-
- if (fstat(sg_fd, &filestatus) != 0)
- return PATH_DOWN;
- bs = (filestatus.st_blksize > 4096)? 4096: filestatus.st_blksize;
- memset(rdCmd, 0, cdbsz);
- sz_ind = 1;
- rdCmd[0] = rd_opcode[sz_ind];
- rdCmd[2] = (unsigned char)((start_block >> 24) & 0xff);
- rdCmd[3] = (unsigned char)((start_block >> 16) & 0xff);
- rdCmd[4] = (unsigned char)((start_block >> 8) & 0xff);
- rdCmd[5] = (unsigned char)(start_block & 0xff);
- rdCmd[7] = (unsigned char)((blocks >> 8) & 0xff);
- rdCmd[8] = (unsigned char)(blocks & 0xff);
-
- memset(&io_hdr, 0, sizeof(struct sg_io_hdr));
- io_hdr.interface_id = 'S';
- io_hdr.cmd_len = cdbsz;
- io_hdr.cmdp = rdCmd;
- io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
- io_hdr.dxfer_len = bs * blocks;
- io_hdr.dxferp = buff;
- io_hdr.mx_sb_len = SENSE_BUFF_LEN;
- io_hdr.sbp = senseBuff;
- io_hdr.timeout = DEF_TIMEOUT;
- io_hdr.pack_id = (int)start_block;
- if (diop && *diop)
- io_hdr.flags |= SG_FLAG_DIRECT_IO;
-
-retry:
- memset(senseBuff, 0, SENSE_BUFF_LEN);
- while (((res = ioctl(sg_fd, SG_IO, &io_hdr)) < 0) && (EINTR == errno));
-
- if (res < 0) {
- if (ENOMEM == errno) {
- return PATH_UP;
- }
- return PATH_DOWN;
- }
-
- if ((0 == io_hdr.status) &&
- (0 == io_hdr.host_status) &&
- (0 == io_hdr.driver_status)) {
- return PATH_UP;
- } else {
- /*
- * Retry if UNIT_ATTENTION check condition.
- */
- if ((sbb[2]&0xf) == 6) {
- if (--retry_count)
- goto retry;
- }
- return PATH_DOWN;
- }
-}
+++ /dev/null
-#ifndef _LIBSG_H
-#define _LIBSG_H
-
-#define SENSE_BUFF_LEN 32
-
-int sg_read (int sg_fd, unsigned char * buff, unsigned char * senseBuff);
-
-#endif /* _LIBSG_H */
+++ /dev/null
-/*
- * Copyright (c) 2005 Christophe Varoqui
- */
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <errno.h>
-
-#include "checkers.h"
-
-#include "../libmultipath/sg_include.h"
-
-#define INQUIRY_CMDLEN 6
-#define INQUIRY_CMD 0x12
-#define SENSE_BUFF_LEN 32
-#define RDAC_DEF_TIMEOUT 60000
-#define SCSI_CHECK_CONDITION 0x2
-#define SCSI_COMMAND_TERMINATED 0x22
-#define SG_ERR_DRIVER_SENSE 0x08
-#define RECOVERED_ERROR 0x01
-
-#define MSG_RDAC_UP "rdac checker reports path is up"
-#define MSG_RDAC_DOWN "rdac checker reports path is down"
-#define MSG_RDAC_GHOST "rdac checker reports path is ghost"
-
-struct rdac_checker_context {
- void * dummy;
-};
-
-int rdac_init (struct checker * c)
-{
- return 0;
-}
-
-void rdac_free (struct checker * c)
-{
- return;
-}
-
-static int
-do_inq(int sg_fd, unsigned int pg_op, void *resp, int mx_resp_len)
-{
- unsigned char inqCmdBlk[INQUIRY_CMDLEN] = { INQUIRY_CMD, 1, 0, 0, 0, 0 };
- unsigned char sense_b[SENSE_BUFF_LEN];
- struct sg_io_hdr io_hdr;
-
- inqCmdBlk[2] = (unsigned char) pg_op;
- inqCmdBlk[4] = (unsigned char) (mx_resp_len & 0xff);
- memset(&io_hdr, 0, sizeof (struct sg_io_hdr));
-
- io_hdr.interface_id = 'S';
- io_hdr.cmd_len = sizeof (inqCmdBlk);
- io_hdr.mx_sb_len = sizeof (sense_b);
- io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
- io_hdr.dxfer_len = mx_resp_len;
- io_hdr.dxferp = resp;
- io_hdr.cmdp = inqCmdBlk;
- io_hdr.sbp = sense_b;
- io_hdr.timeout = RDAC_DEF_TIMEOUT;
-
- if (ioctl(sg_fd, SG_IO, &io_hdr) < 0)
- return 1;
-
- /* treat SG_ERR here to get rid of sg_err.[ch] */
- io_hdr.status &= 0x7e;
- if ((0 == io_hdr.status) && (0 == io_hdr.host_status) &&
- (0 == io_hdr.driver_status))
- return 0;
- if ((SCSI_CHECK_CONDITION == io_hdr.status) ||
- (SCSI_COMMAND_TERMINATED == io_hdr.status) ||
- (SG_ERR_DRIVER_SENSE == (0xf & io_hdr.driver_status))) {
- if (io_hdr.sbp && (io_hdr.sb_len_wr > 2)) {
- int sense_key;
- unsigned char * sense_buffer = io_hdr.sbp;
- if (sense_buffer[0] & 0x2)
- sense_key = sense_buffer[1] & 0xf;
- else
- sense_key = sense_buffer[2] & 0xf;
- if (RECOVERED_ERROR == sense_key)
- return 0;
- }
- }
- return 1;
-}
-
-struct volume_access_inq
-{
- char dontcare0[8];
- char avtcvp;
- char dontcare1[39];
-};
-
-extern int
-rdac(struct checker * c)
-{
- struct volume_access_inq inq;
-
- if (0 != do_inq(c->fd, 0xC9, &inq, sizeof(struct volume_access_inq))) {
- MSG(c, MSG_RDAC_DOWN);
- return PATH_DOWN;
- }
-
- return ((inq.avtcvp & 0x1) ? PATH_UP : PATH_GHOST);
-}
+++ /dev/null
-#ifndef _RDAC_H
-#define _RDAC_H
-
-int rdac(struct checker *);
-int rdac_init(struct checker *);
-void rdac_free(struct checker *);
-
-#endif /* _RDAC_H */
+++ /dev/null
-/*
- * Copyright (c) 2004, 2005 Christophe Varoqui
- */
-#include <stdio.h>
-
-#include "checkers.h"
-#include "libsg.h"
-
-#define MSG_READSECTOR0_UP "readsector0 checker reports path is up"
-#define MSG_READSECTOR0_DOWN "readsector0 checker reports path is down"
-
-struct readsector0_checker_context {
- void * dummy;
-};
-
-int readsector0_init (struct checker * c)
-{
- return 0;
-}
-
-void readsector0_free (struct checker * c)
-{
- return;
-}
-
-extern int
-readsector0 (struct checker * c)
-{
- unsigned char buf[4096];
- unsigned char sbuf[SENSE_BUFF_LEN];
- int ret;
-
- ret = sg_read(c->fd, &buf[0], &sbuf[0]);
-
- switch (ret)
- {
- case PATH_DOWN:
- MSG(c, MSG_READSECTOR0_DOWN);
- break;
- case PATH_UP:
- MSG(c, MSG_READSECTOR0_UP);
- break;
- default:
- break;
- }
- return ret;
-}
+++ /dev/null
-#ifndef _READSECTOR0_H
-#define _READSECTOR0_H
-
-int readsector0 (struct checker *);
-int readsector0_init (struct checker *);
-void readsector0_free (struct checker *);
-
-#endif /* _READSECTOR0_H */
+++ /dev/null
-/*
- * Some code borrowed from sg-utils.
- *
- * Copyright (c) 2004 Christophe Varoqui
- */
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <errno.h>
-
-#include "checkers.h"
-
-#include "../libmultipath/sg_include.h"
-
-#define TUR_CMD_LEN 6
-#define HEAVY_CHECK_COUNT 10
-
-#define MSG_TUR_UP "tur checker reports path is up"
-#define MSG_TUR_DOWN "tur checker reports path is down"
-
-struct tur_checker_context {
- void * dummy;
-};
-
-int tur_init (struct checker * c)
-{
- return 0;
-}
-
-void tur_free (struct checker * c)
-{
- return;
-}
-
-extern int
-tur (struct checker * c)
-{
- struct sg_io_hdr io_hdr;
- unsigned char turCmdBlk[TUR_CMD_LEN] = { 0x00, 0, 0, 0, 0, 0 };
- unsigned char sense_buffer[32];
-
- memset(&io_hdr, 0, sizeof (struct sg_io_hdr));
- io_hdr.interface_id = 'S';
- io_hdr.cmd_len = sizeof (turCmdBlk);
- io_hdr.mx_sb_len = sizeof (sense_buffer);
- io_hdr.dxfer_direction = SG_DXFER_NONE;
- io_hdr.cmdp = turCmdBlk;
- io_hdr.sbp = sense_buffer;
- io_hdr.timeout = DEF_TIMEOUT;
- io_hdr.pack_id = 0;
- if (ioctl(c->fd, SG_IO, &io_hdr) < 0) {
- MSG(c, MSG_TUR_DOWN);
- return PATH_DOWN;
- }
- if (io_hdr.info & SG_INFO_OK_MASK) {
- MSG(c, MSG_TUR_DOWN);
- return PATH_DOWN;
- }
- MSG(c, MSG_TUR_UP);
- return PATH_UP;
-}
+++ /dev/null
-#ifndef _TUR_H
-#define _TUR_H
-
-int tur (struct checker *);
-int tur_init (struct checker *);
-void tur_free (struct checker *);
-
-#endif /* _TUR_H */
include ../Makefile.inc
LIBS = libmultipath.so
-CFLAGS += -I$(checkersdir)
OBJS = memory.o parser.o vector.o devmapper.o callout.o \
hwtable.o blacklist.o util.o dmparser.o config.o \
structs.o discovery.o propsel.o dict.o \
pgpolicies.o debug.o regex.o defaults.o uevent.o \
switchgroup.o uxsock.o print.o alias.o log_pthread.o \
- log.o configure.o structs_vec.o sysfs.o prio.o
+ log.o configure.o structs_vec.o sysfs.o prio.o checkers.o
#ifeq ($(strip $(DAEMON)),1)
OBJS += lock.o waiter.o
* Copyright (c) 2004, 2005 Christophe Varoqui
*/
#include <stdio.h>
-#include <checkers.h>
+#include "checkers.h"
#include "memory.h"
#include "vector.h"
#include "util.h"
#include <sys/wait.h>
#include <errno.h>
-#include <checkers.h>
-
+#include "checkers.h"
#include "vector.h"
#include "structs.h"
#include "debug.h"
--- /dev/null
+#include <stdio.h>
+#include <string.h>
+#include <stddef.h>
+#include <dlfcn.h>
+
+#include "debug.h"
+#include "checkers.h"
+
+static LIST_HEAD(checkers);
+
+int init_checkers (void)
+{
+ INIT_LIST_HEAD(&checkers);
+ if (!add_checker(DEFAULT_CHECKER))
+ return 1;
+ return 0;
+}
+
+struct checker * alloc_checker (void)
+{
+ return zalloc(sizeof(struct checker));
+}
+
+void free_checker (struct checker * c)
+{
+ free(c);
+}
+
+void cleanup_checkers (void)
+{
+ struct checker * checker_loop;
+ struct checker * checker_temp;
+
+ list_for_each_entry_safe(checker_loop, checker_temp, &checkers, node) {
+ list_del(&checker_loop->node);
+ free(checker_loop);
+ }
+}
+
+struct checker * checker_lookup (char * name)
+{
+ struct checker * c;
+
+ list_for_each_entry(c, &checkers, node) {
+ if (!strncmp(name, c->name, CHECKER_NAME_LEN))
+ return c;
+ }
+ c = add_checker(name);
+ if (c)
+ return c;
+ return checker_default();
+}
+
+struct checker * add_checker (char * name)
+{
+ char libname[LIB_CHECKER_NAMELEN];
+ void * handle;
+ struct checker * c;
+ char *errstr;
+
+ c = alloc_checker();
+ if (!c)
+ return NULL;
+ snprintf(libname, LIB_CHECKER_NAMELEN, "libcheck%s.so", name);
+ condlog(3, "loading %s checker", libname);
+ handle = dlopen(libname, RTLD_NOW);
+ errstr = dlerror();
+ if (errstr != NULL)
+ condlog(0, "A dynamic linking error occurred: (%s)", errstr);
+ if (!handle)
+ goto out;
+
+ c->check = (int (*)(struct checker *)) dlsym(handle, "libcheck_check");
+ errstr = dlerror();
+ if (errstr != NULL)
+ condlog(0, "A dynamic linking error occurred: (%s)", errstr);
+ if (!c->check)
+ goto out;
+
+ c->init = (int (*)(struct checker *)) dlsym(handle, "libcheck_init");
+ errstr = dlerror();
+ if (errstr != NULL)
+ condlog(0, "A dynamic linking error occurred: (%s)", errstr);
+ if (!c->init)
+ goto out;
+
+ c->free = (void (*)(struct checker *)) dlsym(handle, "libcheck_free");
+ errstr = dlerror();
+ if (errstr != NULL)
+ condlog(0, "A dynamic linking error occurred: (%s)", errstr);
+ if (!c->free)
+ goto out;
+
+ snprintf(c->name, CHECKER_NAME_LEN, "%s", name);
+ c->fd = 0;
+ c->sync = 1;
+ list_add(&c->node, &checkers);
+ return c;
+out:
+ free_checker(c);
+ return NULL;
+}
+
+void checker_set_fd (struct checker * c, int fd)
+{
+ c->fd = fd;
+}
+
+void checker_set_sync (struct checker * c)
+{
+ c->sync = 1;
+}
+
+void checker_set_async (struct checker * c)
+{
+ c->sync = 0;
+}
+
+void checker_enable (struct checker * c)
+{
+ c->disable = 0;
+}
+
+void checker_disable (struct checker * c)
+{
+ c->disable = 1;
+}
+
+int checker_init (struct checker * c, void ** mpctxt_addr)
+{
+ c->mpcontext = mpctxt_addr;
+ return c->init(c);
+}
+
+void checker_put (struct checker * c)
+{
+ if (c->free)
+ c->free(c);
+ memset(c, 0x0, sizeof(struct checker));
+}
+
+int checker_check (struct checker * c)
+{
+ int r;
+
+ if (c->disable)
+ return PATH_UNCHECKED;
+ if (c->fd <= 0) {
+ MSG(c, "no usable fd");
+ return PATH_WILD;
+ }
+ r = c->check(c);
+
+ return r;
+}
+
+int checker_selected (struct checker * c)
+{
+ return (c->check) ? 1 : 0;
+}
+
+char * checker_name (struct checker * c)
+{
+ return c->name;
+}
+
+char * checker_message (struct checker * c)
+{
+ return c->message;
+}
+
+struct checker * checker_default (void)
+{
+ return checker_lookup(DEFAULT_CHECKER);
+}
+
+void checker_get (struct checker * dst, struct checker * src)
+{
+ dst->fd = src->fd;
+ dst->sync = src->sync;
+ strncpy(dst->name, src->name, CHECKER_NAME_LEN);
+ strncpy(dst->message, src->message, CHECKER_MSG_LEN);
+ dst->check = src->check;
+ dst->init = src->init;
+ dst->free = src->free;
+}
--- /dev/null
+#ifndef _CHECKERS_H
+#define _CHECKERS_H
+
+#include "list.h"
+#include "memory.h"
+
+/*
+ *
+ * Userspace (multipath/multipathd) path states
+ *
+ * PATH_WILD:
+ * - Use: None of the checkers (returned if we don't have an fd)
+ * - Description: Corner case where "fd <= 0" for path fd (see checker_check())
+ *
+ * PATH_UNCHECKED:
+ * - Use: Only in directio checker
+ * - Description: set when fcntl(F_GETFL) fails to return flags or O_DIRECT
+ * not include in flags, or O_DIRECT read fails
+ * - Notes:
+ * - multipathd: uses it to skip over paths in sync_map_state()
+ * - multipath: used in update_paths(); if state==PATH_UNCHECKED, call
+ * pathinfo()
+ *
+ * PATH_DOWN:
+ * - Use: All checkers (directio, emc_clariion, hp_sw, readsector0, tur)
+ * - Description: Either a) SG_IO ioctl failed, or b) check condition on some
+ * SG_IO ioctls that succeed (tur, readsector0 checkers); path is down and
+ * you shouldn't try to send commands to it
+ *
+ * PATH_UP:
+ * - Use: All checkers (directio, emc_clariion, hp_sw, readsector0, tur)
+ * - Description: Path is up and I/O can be sent to it
+ *
+ * PATH_SHAKY:
+ * - Use: Only emc_clariion
+ * - Description: Indicates path not available for "normal" operations
+ *
+ * PATH_GHOST:
+ * - Use: Only hp_sw
+ * - Description: Indicates a "passive/standby" path on active/passive HP
+ * arrays. These paths will return valid answers to certain SCSI commands
+ * (tur, read_capacity, inquiry, start_stop), but will fail I/O commands.
+ * The path needs an initialization command to be sent to it in order for
+ * I/Os to succeed.
+ *
+ * PATH_PENDING:
+ * - Use: All async checkers
+ * - Description: Indicates a check IO is in flight.
+ */
+#define PATH_WILD -1
+#define PATH_UNCHECKED 0
+#define PATH_DOWN 1
+#define PATH_UP 2
+#define PATH_SHAKY 3
+#define PATH_GHOST 4
+#define PATH_PENDING 5
+
+#define DIRECTIO "directio"
+#define TUR "tur"
+#define HP_SW "hp_sw"
+#define RDAC "rdac"
+#define EMC_CLARIION "emc_clariion"
+#define READSECTOR0 "readsector0"
+
+#define DEFAULT_CHECKER DIRECTIO
+
+/*
+ * Overloaded storage response time can be very long.
+ * SG_IO timouts after DEF_TIMEOUT milliseconds, and checkers interprets this
+ * as a path failure. multipathd then proactively evicts the path from the DM
+ * multipath table in this case.
+ *
+ * This generaly snow balls and ends up in full eviction and IO errors for end
+ * users. Bad. This may also cause SCSI bus resets, causing disruption for all
+ * local and external storage hardware users.
+ *
+ * Provision a long timeout. Longer than any real-world application would cope
+ * with.
+ */
+#define DEF_TIMEOUT 300000
+#define ASYNC_TIMEOUT_SEC 30
+
+/*
+ * strings lengths
+ */
+#define CHECKER_NAME_LEN 16
+#define CHECKER_MSG_LEN 256
+#define CHECKER_DEV_LEN 256
+#define LIB_CHECKER_NAMELEN 256
+
+struct checker {
+ struct list_head node;
+ int fd;
+ int sync;
+ int disable;
+ char name[CHECKER_NAME_LEN];
+ char message[CHECKER_MSG_LEN]; /* comm with callers */
+ void * context; /* store for persistent data */
+ void ** mpcontext; /* store for persistent data
+ shared multipath-wide */
+ int (*check)(struct checker *);
+ int (*init)(struct checker *); /* to allocate the context */
+ void (*free)(struct checker *); /* to free the context */
+};
+
+#define MSG(c, fmt, args...) snprintf((c)->message, CHECKER_MSG_LEN, fmt, ##args);
+
+int init_checkers (void);
+struct checker * add_checker (char *);
+struct checker * checker_lookup (char *);
+int checker_init (struct checker *, void **);
+void checker_put (struct checker *);
+void checker_reset (struct checker *);
+void checker_set_sync (struct checker *);
+void checker_set_async (struct checker *);
+void checker_set_fd (struct checker *, int);
+void checker_enable (struct checker *);
+void checker_disable (struct checker *);
+struct checker * checker_lookup (char *);
+int checker_check (struct checker *);
+int checker_selected (struct checker *);
+char * checker_name (struct checker *);
+char * checker_message (struct checker *);
+struct checker * checker_default (void);
+void checker_get (struct checker *, struct checker *);
+
+#endif /* _CHECKERS_H */
--- /dev/null
+# Makefile
+#
+# Copyright (C) 2003 Christophe Varoqui, <christophe.varoqui@free.fr>
+#
+include ../../Makefile.inc
+
+LIBS= \
+ libcheckreadsector0.so \
+ libchecktur.so \
+ libcheckdirectio.so \
+ libcheckemc_clariion.so \
+ libcheckhp_sw.so \
+ libcheckrdac.so
+
+CFLAGS += -I..
+
+all: $(LIBS)
+
+libcheck%.so: libsg.o %.o
+ $(CC) $(SHARED_FLAGS) -o $@ $^
+
+install:
+ $(INSTALL_PROGRAM) -o root -g root -m 755 $(LIBS) $(libdir)
+
+uninstall:
+ rm -f $(libdir)/$(LIBS)
+
+clean:
+ rm -f core *.a *.o *.gz *.so
--- /dev/null
+/*
+ * Copyright (c) 2005 Hannes Reinecke, Suse
+ */
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <linux/fs.h>
+#include <errno.h>
+#include <linux/kdev_t.h>
+#include <asm/unistd.h>
+#include <libaio.h>
+
+#include "checkers.h"
+#include "../libmultipath/debug.h"
+
+#define MSG_DIRECTIO_UNKNOWN "directio checker is not available"
+#define MSG_DIRECTIO_UP "directio checker reports path is up"
+#define MSG_DIRECTIO_DOWN "directio checker reports path is down"
+#define MSG_DIRECTIO_PENDING "directio checker is waiting on aio"
+
+#define LOG(prio, fmt, args...) condlog(prio, "directio: " fmt, ##args)
+
+struct directio_context {
+ int running;
+ int reset_flags;
+ int blksize;
+ unsigned char * buf;
+ unsigned char * ptr;
+ io_context_t ioctx;
+ struct iocb io;
+};
+
+
+int libcheck_init (struct checker * c)
+{
+ unsigned long pgsize = getpagesize();
+ struct directio_context * ct;
+ long flags;
+
+ ct = malloc(sizeof(struct directio_context));
+ if (!ct)
+ return 1;
+ memset(ct, 0, sizeof(struct directio_context));
+
+ if (io_setup(1, &ct->ioctx) != 0) {
+ condlog(1, "io_setup failed");
+ free(ct);
+ return 1;
+ }
+
+ if (ioctl(c->fd, BLKBSZGET, &ct->blksize) < 0) {
+ MSG(c, "cannot get blocksize, set default");
+ ct->blksize = 512;
+ }
+ if (ct->blksize > 4096) {
+ /*
+ * Sanity check for DASD; BSZGET is broken
+ */
+ ct->blksize = 4096;
+ }
+ if (!ct->blksize)
+ goto out;
+ ct->buf = (unsigned char *)malloc(ct->blksize + pgsize);
+ if (!ct->buf)
+ goto out;
+
+ flags = fcntl(c->fd, F_GETFL);
+ if (flags < 0)
+ goto out;
+ if (!(flags & O_DIRECT)) {
+ flags |= O_DIRECT;
+ if (fcntl(c->fd, F_SETFL, flags) < 0)
+ goto out;
+ ct->reset_flags = 1;
+ }
+
+ ct->ptr = (unsigned char *) (((unsigned long)ct->buf + pgsize - 1) &
+ (~(pgsize - 1)));
+
+ /* Sucessfully initialized, return the context. */
+ c->context = (void *) ct;
+ return 0;
+
+out:
+ if (ct->buf)
+ free(ct->buf);
+ io_destroy(ct->ioctx);
+ free(ct);
+ return 1;
+}
+
+void libcheck_free (struct checker * c)
+{
+ struct directio_context * ct = (struct directio_context *)c->context;
+ long flags;
+
+ if (!ct)
+ return;
+
+ if (ct->reset_flags) {
+ if ((flags = fcntl(c->fd, F_GETFL)) >= 0) {
+ flags &= ~O_DIRECT;
+ /* No point in checking for errors */
+ fcntl(c->fd, F_SETFL, flags);
+ }
+ }
+
+ if (ct->buf)
+ free(ct->buf);
+ io_destroy(ct->ioctx);
+ free(ct);
+}
+
+static int
+check_state(int fd, struct directio_context *ct, int sync)
+{
+ struct timespec timeout = { .tv_nsec = 5 };
+ struct io_event event;
+ struct stat sb;
+ int rc = PATH_UNCHECKED;
+ long r;
+
+ if (fstat(fd, &sb) == 0) {
+ LOG(4, "called for %x", (unsigned) sb.st_rdev);
+ }
+ if (sync) {
+ LOG(4, "called in synchronous mode");
+ timeout.tv_sec = ASYNC_TIMEOUT_SEC;
+ timeout.tv_nsec = 0;
+ }
+
+ if (!ct->running) {
+ struct iocb *ios[1] = { &ct->io };
+
+ LOG(3, "starting new request");
+ memset(&ct->io, 0, sizeof(struct iocb));
+ io_prep_pread(&ct->io, fd, ct->ptr, ct->blksize, 0);
+ if (io_submit(ct->ioctx, 1, ios) != 1) {
+ LOG(3, "io_submit error %i", errno);
+ return PATH_UNCHECKED;
+ }
+ }
+ ct->running++;
+
+ r = io_getevents(ct->ioctx, 1L, 1L, &event, &timeout);
+ LOG(3, "async io getevents returns %li (errno=%s)", r, strerror(errno));
+
+ if (r < 1L) {
+ if (ct->running > ASYNC_TIMEOUT_SEC || sync) {
+ LOG(3, "abort check on timeout");
+ rc = PATH_DOWN;
+ } else
+ rc = PATH_PENDING;
+ } else {
+ LOG(3, "io finished %lu/%lu", event.res, event.res2);
+ ct->running = 0;
+ rc = (event.res == ct->blksize) ? PATH_UP : PATH_DOWN;
+ }
+
+ return rc;
+}
+
+int libcheck_check (struct checker * c)
+{
+ int ret;
+ struct directio_context * ct = (struct directio_context *)c->context;
+
+ if (!ct)
+ return PATH_UNCHECKED;
+
+ ret = check_state(c->fd, ct, c->sync);
+
+ switch (ret)
+ {
+ case PATH_UNCHECKED:
+ MSG(c, MSG_DIRECTIO_UNKNOWN);
+ break;
+ case PATH_DOWN:
+ MSG(c, MSG_DIRECTIO_DOWN);
+ break;
+ case PATH_UP:
+ MSG(c, MSG_DIRECTIO_UP);
+ break;
+ case PATH_PENDING:
+ MSG(c, MSG_DIRECTIO_PENDING);
+ break;
+ default:
+ break;
+ }
+ return ret;
+}
--- /dev/null
+#ifndef _DIRECTIO_H
+#define _DIRECTIO_H
+
+int directio (struct checker *);
+int directio_init (struct checker *);
+void directio_free (struct checker *);
+
+#endif /* _DIRECTIO_H */
--- /dev/null
+/*
+ * Copyright (c) 2004, 2005 Lars Marowsky-Bree
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+
+#include "../libmultipath/sg_include.h"
+#include "libsg.h"
+#include "checkers.h"
+
+#define INQUIRY_CMD 0x12
+#define INQUIRY_CMDLEN 6
+#define HEAVY_CHECK_COUNT 10
+
+/*
+ * Mechanism to track CLARiiON inactive snapshot LUs.
+ * This is done so that we can fail passive paths
+ * to an inactive snapshot LU even though since a
+ * simple read test would return 02/04/03 instead
+ * of 05/25/01 sensekey/ASC/ASCQ data.
+ */
+#define IS_INACTIVE_SNAP(c) (c->mpcontext ? \
+ ((struct emc_clariion_checker_LU_context *) \
+ (*c->mpcontext))->inactive_snap \
+ : 0)
+
+#define SET_INACTIVE_SNAP(c) if (c->mpcontext) \
+ ((struct emc_clariion_checker_LU_context *)\
+ (*c->mpcontext))->inactive_snap = 1
+
+#define CLR_INACTIVE_SNAP(c) if (c->mpcontext) \
+ ((struct emc_clariion_checker_LU_context *)\
+ (*c->mpcontext))->inactive_snap = 0
+
+struct emc_clariion_checker_path_context {
+ char wwn[16];
+ unsigned wwn_set;
+};
+
+struct emc_clariion_checker_LU_context {
+ int inactive_snap;
+};
+
+extern void
+hexadecimal_to_ascii(char * wwn, char *wwnstr)
+{
+ int i,j, nbl;
+
+ for (i=0,j=0;i<16;i++) {
+ wwnstr[j++] = ((nbl = ((wwn[i]&0xf0) >> 4)) <= 9) ?
+ '0' + nbl : 'a' + (nbl - 10);
+ wwnstr[j++] = ((nbl = (wwn[i]&0x0f)) <= 9) ?
+ '0' + nbl : 'a' + (nbl - 10);
+ }
+ wwnstr[32]=0;
+}
+
+int libcheck_init (struct checker * c)
+{
+ /*
+ * Allocate and initialize the path specific context.
+ */
+ c->context = malloc(sizeof(struct emc_clariion_checker_path_context));
+ if (!c->context)
+ return 1;
+ ((struct emc_clariion_checker_path_context *)c->context)->wwn_set = 0;
+
+ /*
+ * Allocate and initialize the multi-path global context.
+ */
+ if (c->mpcontext) {
+ void * mpctxt = malloc(sizeof(int));
+ *c->mpcontext = mpctxt;
+ CLR_INACTIVE_SNAP(c);
+ }
+
+ return 0;
+}
+
+void libcheck_free (struct checker * c)
+{
+ free(c->context);
+}
+
+int libcheck_check (struct checker * c)
+{
+ unsigned char sense_buffer[128] = { 0, };
+ unsigned char sb[SENSE_BUFF_LEN] = { 0, }, *sbb;
+ unsigned char inqCmdBlk[INQUIRY_CMDLEN] = {INQUIRY_CMD, 1, 0xC0, 0,
+ sizeof(sense_buffer), 0};
+ struct sg_io_hdr io_hdr;
+ struct emc_clariion_checker_path_context * ct =
+ (struct emc_clariion_checker_path_context *)c->context;
+ char wwnstr[33];
+ int ret;
+
+ memset(&io_hdr, 0, sizeof (struct sg_io_hdr));
+ io_hdr.interface_id = 'S';
+ io_hdr.cmd_len = sizeof (inqCmdBlk);
+ io_hdr.mx_sb_len = sizeof (sb);
+ io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
+ io_hdr.dxfer_len = sizeof (sense_buffer);
+ io_hdr.dxferp = sense_buffer;
+ io_hdr.cmdp = inqCmdBlk;
+ io_hdr.sbp = sb;
+ io_hdr.timeout = DEF_TIMEOUT;
+ io_hdr.pack_id = 0;
+ if (ioctl(c->fd, SG_IO, &io_hdr) < 0) {
+ MSG(c, "emc_clariion_checker: sending query command failed");
+ return PATH_DOWN;
+ }
+ if (io_hdr.info & SG_INFO_OK_MASK) {
+ MSG(c, "emc_clariion_checker: query command indicates error");
+ return PATH_DOWN;
+ }
+ if (/* Verify the code page - right page & revision */
+ sense_buffer[1] != 0xc0 || sense_buffer[9] != 0x00) {
+ MSG(c, "emc_clariion_checker: Path unit report page in "
+ "unknown format");
+ return PATH_DOWN;
+ }
+
+ if ( /* Effective initiator type */
+ sense_buffer[27] != 0x03
+ /*
+ * Failover mode should be set to 1 (PNR failover mode)
+ * or 4 (ALUA failover mode).
+ */
+ || (((sense_buffer[28] & 0x07) != 0x04) &&
+ ((sense_buffer[28] & 0x07) != 0x06))
+ /* Arraycommpath should be set to 1 */
+ || (sense_buffer[30] & 0x04) != 0x04) {
+ MSG(c, "emc_clariion_checker: Path not correctly configured "
+ "for failover");
+ return PATH_DOWN;
+ }
+
+ if ( /* LUN operations should indicate normal operations */
+ sense_buffer[48] != 0x00) {
+ MSG(c, "emc_clariion_checker: Path not available for normal "
+ "operations");
+ return PATH_SHAKY;
+ }
+
+ if ( /* LUN should at least be bound somewhere and not be LUNZ */
+ sense_buffer[4] == 0x00) {
+ MSG(c, "emc_clariion_checker: Logical Unit is unbound "
+ "or LUNZ");
+ return PATH_DOWN;
+ }
+
+ /*
+ * store the LUN WWN there and compare that it indeed did not
+ * change in between, to protect against the path suddenly
+ * pointing somewhere else.
+ */
+ if (ct->wwn_set) {
+ if (memcmp(ct->wwn, &sense_buffer[10], 16) != 0) {
+ MSG(c, "emc_clariion_checker: Logical Unit WWN "
+ "has changed!");
+ return PATH_DOWN;
+ }
+ } else {
+ memcpy(ct->wwn, &sense_buffer[10], 16);
+ ct->wwn_set = 1;
+ }
+
+ /*
+ * Issue read on active path to determine if inactive snapshot.
+ */
+ if (sense_buffer[4] == 2) {/* if active path */
+ unsigned char buf[4096];
+
+ ret = sg_read(c->fd, &buf[0], sbb = &sb[0]);
+ if (ret == PATH_DOWN) {
+ hexadecimal_to_ascii(ct->wwn, wwnstr);
+
+ /*
+ * Check for inactive snapshot LU this way. Must
+ * fail these.
+ */
+ if (((sbb[2]&0xf) == 5) && (sbb[12] == 0x25) &&
+ (sbb[13]==1)) {
+ /*
+ * Do this so that we can fail even the
+ * passive paths which will return
+ * 02/04/03 not 05/25/01 on read.
+ */
+ SET_INACTIVE_SNAP(c);
+ MSG(c, "emc_clariion_checker: Active "
+ "path to inactive snapshot WWN %s.",
+ wwnstr);
+ } else
+ MSG(c, "emc_clariion_checker: Read "
+ "error for WWN %s. Sense data are "
+ "0x%x/0x%x/0x%x.", wwnstr,
+ sbb[2]&0xf, sbb[12], sbb[13]);
+ } else {
+ MSG(c, "emc_clariion_checker: Active path is "
+ "healthy.");
+ /*
+ * Remove the path from the set of paths to inactive
+ * snapshot LUs if it was in this list since the
+ * snapshot is no longer inactive.
+ */
+ CLR_INACTIVE_SNAP(c);
+ }
+ } else {
+ if (IS_INACTIVE_SNAP(c)) {
+ hexadecimal_to_ascii(ct->wwn, wwnstr);
+ MSG(c, "emc_clariion_checker: Passive "
+ "path to inactive snapshot WWN %s.",
+ wwnstr);
+ ret = PATH_DOWN;
+ } else {
+ MSG(c,
+ "emc_clariion_checker: Passive path is healthy.");
+ ret = PATH_UP; /* not ghost */
+ }
+ }
+
+ return ret;
+}
--- /dev/null
+#ifndef _EMC_CLARIION_H
+#define _EMC_CLARIION_H
+
+int emc_clariion (struct checker *);
+int emc_clariion_init (struct checker *);
+void emc_clariion_free (struct checker *);
+
+#endif /* _EMC_CLARIION_H */
--- /dev/null
+/*
+ * Copyright (c) 2005 Christophe Varoqui
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+
+#include "checkers.h"
+
+#include "../libmultipath/sg_include.h"
+
+#define TUR_CMD_LEN 6
+#define INQUIRY_CMDLEN 6
+#define INQUIRY_CMD 0x12
+#define SENSE_BUFF_LEN 32
+#define SCSI_CHECK_CONDITION 0x2
+#define SCSI_COMMAND_TERMINATED 0x22
+#define SG_ERR_DRIVER_SENSE 0x08
+#define RECOVERED_ERROR 0x01
+#define MX_ALLOC_LEN 255
+#define HEAVY_CHECK_COUNT 10
+
+#define MSG_HP_SW_UP "hp_sw checker reports path is up"
+#define MSG_HP_SW_DOWN "hp_sw checker reports path is down"
+#define MSG_HP_SW_GHOST "hp_sw checker reports path is ghost"
+
+struct sw_checker_context {
+ void * dummy;
+};
+
+int libcheck_init (struct checker * c)
+{
+ return 0;
+}
+
+void libcheck_free (struct checker * c)
+{
+ return;
+}
+
+static int
+do_inq(int sg_fd, int cmddt, int evpd, unsigned int pg_op,
+ void *resp, int mx_resp_len, int noisy)
+{
+ unsigned char inqCmdBlk[INQUIRY_CMDLEN] =
+ { INQUIRY_CMD, 0, 0, 0, 0, 0 };
+ unsigned char sense_b[SENSE_BUFF_LEN];
+ struct sg_io_hdr io_hdr;
+
+ if (cmddt)
+ inqCmdBlk[1] |= 2;
+ if (evpd)
+ inqCmdBlk[1] |= 1;
+ inqCmdBlk[2] = (unsigned char) pg_op;
+ inqCmdBlk[3] = (unsigned char)((mx_resp_len >> 8) & 0xff);
+ inqCmdBlk[4] = (unsigned char) (mx_resp_len & 0xff);
+ memset(&io_hdr, 0, sizeof (struct sg_io_hdr));
+ io_hdr.interface_id = 'S';
+ io_hdr.cmd_len = sizeof (inqCmdBlk);
+ io_hdr.mx_sb_len = sizeof (sense_b);
+ io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
+ io_hdr.dxfer_len = mx_resp_len;
+ io_hdr.dxferp = resp;
+ io_hdr.cmdp = inqCmdBlk;
+ io_hdr.sbp = sense_b;
+ io_hdr.timeout = DEF_TIMEOUT;
+
+ if (ioctl(sg_fd, SG_IO, &io_hdr) < 0)
+ return 1;
+
+ /* treat SG_ERR here to get rid of sg_err.[ch] */
+ io_hdr.status &= 0x7e;
+ if ((0 == io_hdr.status) && (0 == io_hdr.host_status) &&
+ (0 == io_hdr.driver_status))
+ return 0;
+ if ((SCSI_CHECK_CONDITION == io_hdr.status) ||
+ (SCSI_COMMAND_TERMINATED == io_hdr.status) ||
+ (SG_ERR_DRIVER_SENSE == (0xf & io_hdr.driver_status))) {
+ if (io_hdr.sbp && (io_hdr.sb_len_wr > 2)) {
+ int sense_key;
+ unsigned char * sense_buffer = io_hdr.sbp;
+ if (sense_buffer[0] & 0x2)
+ sense_key = sense_buffer[1] & 0xf;
+ else
+ sense_key = sense_buffer[2] & 0xf;
+ if(RECOVERED_ERROR == sense_key)
+ return 0;
+ }
+ }
+ return 1;
+}
+
+static int
+do_tur (int fd)
+{
+ unsigned char turCmdBlk[TUR_CMD_LEN] = { 0x00, 0, 0, 0, 0, 0 };
+ struct sg_io_hdr io_hdr;
+ unsigned char sense_buffer[32];
+
+ memset(&io_hdr, 0, sizeof (struct sg_io_hdr));
+ io_hdr.interface_id = 'S';
+ io_hdr.cmd_len = sizeof (turCmdBlk);
+ io_hdr.mx_sb_len = sizeof (sense_buffer);
+ io_hdr.dxfer_direction = SG_DXFER_NONE;
+ io_hdr.cmdp = turCmdBlk;
+ io_hdr.sbp = sense_buffer;
+ io_hdr.timeout = DEF_TIMEOUT;
+ io_hdr.pack_id = 0;
+
+ if (ioctl(fd, SG_IO, &io_hdr) < 0)
+ return 1;
+
+ if (io_hdr.info & SG_INFO_OK_MASK)
+ return 1;
+
+ return 0;
+}
+
+extern int
+libcheck_check (struct checker * c)
+{
+ char buff[MX_ALLOC_LEN];
+
+ if (0 != do_inq(c->fd, 0, 1, 0x80, buff, MX_ALLOC_LEN, 0)) {
+ MSG(c, MSG_HP_SW_DOWN);
+ return PATH_DOWN;
+ }
+
+ if (do_tur(c->fd)) {
+ MSG(c, MSG_HP_SW_GHOST);
+ return PATH_GHOST;
+ }
+ MSG(c, MSG_HP_SW_UP);
+ return PATH_UP;
+}
--- /dev/null
+#ifndef _HP_SW_H
+#define _HP_SW_H
+
+int hp_sw (struct checker *);
+int hp_sw_init (struct checker *);
+void hp_sw_free (struct checker *);
+
+#endif /* _HP_SW_H */
--- /dev/null
+/*
+ * Copyright (c) 2004, 2005 Christophe Varoqui
+ */
+#include <string.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+#include <sys/stat.h>
+
+#include "checkers.h"
+#include "libsg.h"
+#include "../libmultipath/sg_include.h"
+
+int
+sg_read (int sg_fd, unsigned char * buff, unsigned char * senseBuff)
+{
+ /* defaults */
+ int blocks = 1;
+ long long start_block = 0;
+ int bs = 512;
+ int cdbsz = 10;
+ int * diop = NULL;
+
+ unsigned char rdCmd[cdbsz];
+ unsigned char *sbb = senseBuff;
+ struct sg_io_hdr io_hdr;
+ int res;
+ int rd_opcode[] = {0x8, 0x28, 0xa8, 0x88};
+ int sz_ind;
+ struct stat filestatus;
+ int retry_count = 3;
+
+ if (fstat(sg_fd, &filestatus) != 0)
+ return PATH_DOWN;
+ bs = (filestatus.st_blksize > 4096)? 4096: filestatus.st_blksize;
+ memset(rdCmd, 0, cdbsz);
+ sz_ind = 1;
+ rdCmd[0] = rd_opcode[sz_ind];
+ rdCmd[2] = (unsigned char)((start_block >> 24) & 0xff);
+ rdCmd[3] = (unsigned char)((start_block >> 16) & 0xff);
+ rdCmd[4] = (unsigned char)((start_block >> 8) & 0xff);
+ rdCmd[5] = (unsigned char)(start_block & 0xff);
+ rdCmd[7] = (unsigned char)((blocks >> 8) & 0xff);
+ rdCmd[8] = (unsigned char)(blocks & 0xff);
+
+ memset(&io_hdr, 0, sizeof(struct sg_io_hdr));
+ io_hdr.interface_id = 'S';
+ io_hdr.cmd_len = cdbsz;
+ io_hdr.cmdp = rdCmd;
+ io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
+ io_hdr.dxfer_len = bs * blocks;
+ io_hdr.dxferp = buff;
+ io_hdr.mx_sb_len = SENSE_BUFF_LEN;
+ io_hdr.sbp = senseBuff;
+ io_hdr.timeout = DEF_TIMEOUT;
+ io_hdr.pack_id = (int)start_block;
+ if (diop && *diop)
+ io_hdr.flags |= SG_FLAG_DIRECT_IO;
+
+retry:
+ memset(senseBuff, 0, SENSE_BUFF_LEN);
+ while (((res = ioctl(sg_fd, SG_IO, &io_hdr)) < 0) && (EINTR == errno));
+
+ if (res < 0) {
+ if (ENOMEM == errno) {
+ return PATH_UP;
+ }
+ return PATH_DOWN;
+ }
+
+ if ((0 == io_hdr.status) &&
+ (0 == io_hdr.host_status) &&
+ (0 == io_hdr.driver_status)) {
+ return PATH_UP;
+ } else {
+ /*
+ * Retry if UNIT_ATTENTION check condition.
+ */
+ if ((sbb[2]&0xf) == 6) {
+ if (--retry_count)
+ goto retry;
+ }
+ return PATH_DOWN;
+ }
+}
--- /dev/null
+#ifndef _LIBSG_H
+#define _LIBSG_H
+
+#define SENSE_BUFF_LEN 32
+
+int sg_read (int sg_fd, unsigned char * buff, unsigned char * senseBuff);
+
+#endif /* _LIBSG_H */
--- /dev/null
+/*
+ * Copyright (c) 2005 Christophe Varoqui
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+
+#include "checkers.h"
+
+#include "../libmultipath/sg_include.h"
+
+#define INQUIRY_CMDLEN 6
+#define INQUIRY_CMD 0x12
+#define SENSE_BUFF_LEN 32
+#define RDAC_DEF_TIMEOUT 60000
+#define SCSI_CHECK_CONDITION 0x2
+#define SCSI_COMMAND_TERMINATED 0x22
+#define SG_ERR_DRIVER_SENSE 0x08
+#define RECOVERED_ERROR 0x01
+
+#define MSG_RDAC_UP "rdac checker reports path is up"
+#define MSG_RDAC_DOWN "rdac checker reports path is down"
+#define MSG_RDAC_GHOST "rdac checker reports path is ghost"
+
+struct rdac_checker_context {
+ void * dummy;
+};
+
+int libcheck_init (struct checker * c)
+{
+ return 0;
+}
+
+void libcheck_free (struct checker * c)
+{
+ return;
+}
+
+static int
+do_inq(int sg_fd, unsigned int pg_op, void *resp, int mx_resp_len)
+{
+ unsigned char inqCmdBlk[INQUIRY_CMDLEN] = { INQUIRY_CMD, 1, 0, 0, 0, 0 };
+ unsigned char sense_b[SENSE_BUFF_LEN];
+ struct sg_io_hdr io_hdr;
+
+ inqCmdBlk[2] = (unsigned char) pg_op;
+ inqCmdBlk[4] = (unsigned char) (mx_resp_len & 0xff);
+ memset(&io_hdr, 0, sizeof (struct sg_io_hdr));
+
+ io_hdr.interface_id = 'S';
+ io_hdr.cmd_len = sizeof (inqCmdBlk);
+ io_hdr.mx_sb_len = sizeof (sense_b);
+ io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
+ io_hdr.dxfer_len = mx_resp_len;
+ io_hdr.dxferp = resp;
+ io_hdr.cmdp = inqCmdBlk;
+ io_hdr.sbp = sense_b;
+ io_hdr.timeout = RDAC_DEF_TIMEOUT;
+
+ if (ioctl(sg_fd, SG_IO, &io_hdr) < 0)
+ return 1;
+
+ /* treat SG_ERR here to get rid of sg_err.[ch] */
+ io_hdr.status &= 0x7e;
+ if ((0 == io_hdr.status) && (0 == io_hdr.host_status) &&
+ (0 == io_hdr.driver_status))
+ return 0;
+ if ((SCSI_CHECK_CONDITION == io_hdr.status) ||
+ (SCSI_COMMAND_TERMINATED == io_hdr.status) ||
+ (SG_ERR_DRIVER_SENSE == (0xf & io_hdr.driver_status))) {
+ if (io_hdr.sbp && (io_hdr.sb_len_wr > 2)) {
+ int sense_key;
+ unsigned char * sense_buffer = io_hdr.sbp;
+ if (sense_buffer[0] & 0x2)
+ sense_key = sense_buffer[1] & 0xf;
+ else
+ sense_key = sense_buffer[2] & 0xf;
+ if (RECOVERED_ERROR == sense_key)
+ return 0;
+ }
+ }
+ return 1;
+}
+
+struct volume_access_inq
+{
+ char dontcare0[8];
+ char avtcvp;
+ char dontcare1[39];
+};
+
+extern int
+libcheck_check (struct checker * c)
+{
+ struct volume_access_inq inq;
+
+ if (0 != do_inq(c->fd, 0xC9, &inq, sizeof(struct volume_access_inq))) {
+ MSG(c, MSG_RDAC_DOWN);
+ return PATH_DOWN;
+ }
+
+ return ((inq.avtcvp & 0x1) ? PATH_UP : PATH_GHOST);
+}
--- /dev/null
+#ifndef _RDAC_H
+#define _RDAC_H
+
+int rdac(struct checker *);
+int rdac_init(struct checker *);
+void rdac_free(struct checker *);
+
+#endif /* _RDAC_H */
--- /dev/null
+/*
+ * Copyright (c) 2004, 2005 Christophe Varoqui
+ */
+#include <stdio.h>
+
+#include "checkers.h"
+#include "libsg.h"
+
+#define MSG_READSECTOR0_UP "readsector0 checker reports path is up"
+#define MSG_READSECTOR0_DOWN "readsector0 checker reports path is down"
+
+struct readsector0_checker_context {
+ void * dummy;
+};
+
+int libcheck_init (struct checker * c)
+{
+ return 0;
+}
+
+void libcheck_free (struct checker * c)
+{
+ return;
+}
+
+int libcheck_check (struct checker * c)
+{
+ unsigned char buf[4096];
+ unsigned char sbuf[SENSE_BUFF_LEN];
+ int ret;
+
+ ret = sg_read(c->fd, &buf[0], &sbuf[0]);
+
+ switch (ret)
+ {
+ case PATH_DOWN:
+ MSG(c, MSG_READSECTOR0_DOWN);
+ break;
+ case PATH_UP:
+ MSG(c, MSG_READSECTOR0_UP);
+ break;
+ default:
+ break;
+ }
+ return ret;
+}
--- /dev/null
+#ifndef _READSECTOR0_H
+#define _READSECTOR0_H
+
+int readsector0 (struct checker *);
+int readsector0_init (struct checker *);
+void readsector0_free (struct checker *);
+
+#endif /* _READSECTOR0_H */
--- /dev/null
+/*
+ * Some code borrowed from sg-utils.
+ *
+ * Copyright (c) 2004 Christophe Varoqui
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+
+#include "checkers.h"
+
+#include "../libmultipath/sg_include.h"
+
+#define TUR_CMD_LEN 6
+#define HEAVY_CHECK_COUNT 10
+
+#define MSG_TUR_UP "tur checker reports path is up"
+#define MSG_TUR_DOWN "tur checker reports path is down"
+
+struct tur_checker_context {
+ void * dummy;
+};
+
+int libcheck_init (struct checker * c)
+{
+ return 0;
+}
+
+void libcheck_free (struct checker * c)
+{
+ return;
+}
+
+extern int
+libcheck_check (struct checker * c)
+{
+ struct sg_io_hdr io_hdr;
+ unsigned char turCmdBlk[TUR_CMD_LEN] = { 0x00, 0, 0, 0, 0, 0 };
+ unsigned char sense_buffer[32];
+
+ memset(&io_hdr, 0, sizeof (struct sg_io_hdr));
+ io_hdr.interface_id = 'S';
+ io_hdr.cmd_len = sizeof (turCmdBlk);
+ io_hdr.mx_sb_len = sizeof (sense_buffer);
+ io_hdr.dxfer_direction = SG_DXFER_NONE;
+ io_hdr.cmdp = turCmdBlk;
+ io_hdr.sbp = sense_buffer;
+ io_hdr.timeout = DEF_TIMEOUT;
+ io_hdr.pack_id = 0;
+ if (ioctl(c->fd, SG_IO, &io_hdr) < 0) {
+ MSG(c, MSG_TUR_DOWN);
+ return PATH_DOWN;
+ }
+ if (io_hdr.info & SG_INFO_OK_MASK) {
+ MSG(c, MSG_TUR_DOWN);
+ return PATH_DOWN;
+ }
+ MSG(c, MSG_TUR_UP);
+ return PATH_UP;
+}
--- /dev/null
+#ifndef _TUR_H
+#define _TUR_H
+
+int tur (struct checker *);
+int tur_init (struct checker *);
+void tur_free (struct checker *);
+
+#endif /* _TUR_H */
#include <stdio.h>
#include <string.h>
-#include <checkers.h>
-
+#include "checkers.h"
#include "memory.h"
#include "util.h"
#include "debug.h"
#include <errno.h>
#include <libdevmapper.h>
-#include <checkers.h>
-
+#include "checkers.h"
#include "vector.h"
#include "memory.h"
#include "devmapper.h"
#include <unistd.h>
#include <errno.h>
-#include <checkers.h>
-
+#include "checkers.h"
#include "vector.h"
#include "structs.h"
#include "debug.h"
* Copyright (c) 2005 Benjamin Marzinski, Redhat
* Copyright (c) 2005 Kiyoshi Ueda, NEC
*/
-#include <checkers.h>
-
+#include "checkers.h"
#include "vector.h"
#include "hwtable.h"
#include "structs.h"
#include <dirent.h>
#include <errno.h>
-#include <checkers.h>
-
+#include "checkers.h"
#include "vector.h"
#include "memory.h"
#include "util.h"
#include <stdlib.h>
#include <string.h>
-#include <checkers.h>
-
+#include "checkers.h"
#include "vector.h"
#include "memory.h"
#include "structs.h"
#include <stdio.h>
-#include <checkers.h>
-
+#include "checkers.h"
#include "vector.h"
#include "defaults.h"
#include "structs.h"
#include <stdlib.h>
#include <string.h>
-#include <checkers.h>
-
+#include "checkers.h"
#include "util.h"
#include "memory.h"
#include "vector.h"
#include <sys/stat.h>
#include <dirent.h>
-#include <checkers.h>
-
+#include "checkers.h"
#include "vector.h"
#include "structs.h"
#include "structs_vec.h"
/*
* knowing about path struct gives flexibility to prioritizers
*/
-#include "../libcheckers/checkers.h"
+#include "checkers.h"
#include "vector.h"
#include "structs.h"
#include "list.h"
*/
#include <stdio.h>
-#include <checkers.h>
-
+#include "checkers.h"
#include "memory.h"
#include "vector.h"
#include "structs.h"
#include <unistd.h>
#include <libdevmapper.h>
-#include <checkers.h>
-
+#include "checkers.h"
#include "memory.h"
#include "vector.h"
#include "util.h"
#include <string.h>
#include <unistd.h>
-#include <checkers.h>
-
+#include "checkers.h"
#include "vector.h"
#include "defaults.h"
#include "debug.h"
* Copyright (c) 2005 Christophe Varoqui
* Copyright (c) 2005 Edward Goggin, EMC
*/
-#include <checkers.h>
-
+#include "checkers.h"
#include "vector.h"
#include "structs.h"
#include "switchgroup.h"
OBJS = main.o
-CFLAGS += -I$(multipathdir) -I$(checkersdir)
+CFLAGS += -I$(multipathdir) -Wl,-rpath,$(libdir)
LDFLAGS += -laio -ldevmapper -lpthread \
- -lmultipath -L$(multipathdir) \
- -lcheckers -L$(checkersdir) \
+ -lmultipath -L$(multipathdir)
EXEC = multipath
all: $(EXEC)
$(EXEC): $(OBJS)
- $(CC) $(OBJS) -o $(EXEC) $(LDFLAGS)
+ $(CC) $(CFLAGS) $(OBJS) -o $(EXEC) $(LDFLAGS)
$(GZIP) $(EXEC).8 > $(EXEC).8.gz
$(GZIP) $(EXEC).conf.5 > $(EXEC).conf.5.gz
if (dm_prereq(DEFAULT_TARGET))
exit(1);
+ if (init_checkers()) {
+ condlog(0, "failed to initialize checkers");
+ exit(1);
+ }
if (init_prio()) {
condlog(0, "failed to initialize prioritizers");
exit(1);
#
# basic flags setting
#
-CFLAGS += -DDAEMON -I$(multipathdir) -I$(checkersdir)
+CFLAGS += -DDAEMON -I$(multipathdir) -Wl,-rpath,$(libdir)
LDFLAGS += -lpthread -ldevmapper -lreadline -lncurses -laio \
- -lmultipath -L$(multipathdir) \
- -lcheckers -L$(checkersdir)
+ -lmultipath -L$(multipathdir)
#
# debuging stuff
condlog(2, "--------start up--------");
condlog(2, "read " DEFAULT_CONFIGFILE);
+ if (init_checkers()) {
+ condlog(0, "failed to initialize checkers");
+ exit(1);
+ }
if (init_prio()) {
condlog(0, "failed to initialize prioritizers");
exit(1);