Search
j0ke.net Open Build Service
>
Projects
>
GFS
>
multipath-tools
> multipath-tools-cciss-support
Sign Up
|
Log In
Username
Password
Cancel
Overview
Repositories
Revisions
Requests
Users
Advanced
Attributes
Meta
File multipath-tools-cciss-support of Package multipath-tools
From 007751175c0396f27b2990fce4a371b134e6e982 Mon Sep 17 00:00:00 2001 From: Hannes Reinecke <hare@suse.de> Date: Fri, 9 Nov 2007 14:22:34 +0100 Subject: [PATCH] cciss support Implement cciss support for the upcoming 'Spitfire' MSA array. Signed-off-by: Hannes Reinecke <hare@suse.de> --- libcheckers/Makefile | 2 +- libcheckers/cciss.h | 142 ++++++++++++++++++++++++++++++++++++++++++++++ libcheckers/cciss_tur.c | 137 ++++++++++++++++++++++++++++++++++++++++++++ libcheckers/checkers.c | 13 ++++ libcheckers/checkers.h | 1 + libmultipath/blacklist.c | 6 -- libmultipath/discovery.c | 93 ++++++++++++++++++++++++++++-- libmultipath/hwtable.c | 16 +++++ libmultipath/structs.h | 1 + 9 files changed, 399 insertions(+), 12 deletions(-) create mode 100644 libcheckers/cciss.h create mode 100644 libcheckers/cciss_tur.c diff --git a/libcheckers/Makefile b/libcheckers/Makefile index 6340a68..c216fa8 100644 --- a/libcheckers/Makefile +++ b/libcheckers/Makefile @@ -6,7 +6,7 @@ BUILD = glibc include ../Makefile.inc -OBJS = libsg.o checkers.o readsector0.o tur.o directio.o emc_clariion.o hp_sw.o rdac.o +OBJS = libsg.o checkers.o readsector0.o tur.o directio.o emc_clariion.o hp_sw.o rdac.o cciss_tur.o all: $(BUILD) diff --git a/libcheckers/cciss.h b/libcheckers/cciss.h new file mode 100644 index 0000000..f6a37d8 --- /dev/null +++ b/libcheckers/cciss.h @@ -0,0 +1,142 @@ +#ifndef CCISS_H +#define CCISS_H + +#include <linux/types.h> +#include <linux/ioctl.h> + +#define CCISS_IOC_MAGIC 'B' + +/* + * transfer direction + */ +#define XFER_NONE 0x00 +#define XFER_WRITE 0x01 +#define XFER_READ 0x02 +#define XFER_RSVD 0x03 + +/* + * task attribute + */ +#define ATTR_UNTAGGED 0x00 +#define ATTR_SIMPLE 0x04 +#define ATTR_HEADOFQUEUE 0x05 +#define ATTR_ORDERED 0x06 +#define ATTR_ACA 0x07 + +/* + * cdb type + */ +#define TYPE_CMD 0x00 +#define TYPE_MSG 0x01 + +#define SENSEINFOBYTES 32 + +/* + * Type defs used in the following structs + */ +#define BYTE __u8 +#define WORD __u16 +#define HWORD __u16 +#define DWORD __u32 + +#pragma pack(1) + +//Command List Structure +typedef union _SCSI3Addr_struct { + struct { + BYTE Dev; + BYTE Bus:6; + BYTE Mode:2; // b00 + } PeripDev; + struct { + BYTE DevLSB; + BYTE DevMSB:6; + BYTE Mode:2; // b01 + } LogDev; + struct { + BYTE Dev:5; + BYTE Bus:3; + BYTE Targ:6; + BYTE Mode:2; // b10 + } LogUnit; +} SCSI3Addr_struct; + +typedef struct _PhysDevAddr_struct { + DWORD TargetId:24; + DWORD Bus:6; + DWORD Mode:2; + SCSI3Addr_struct Target[2]; //2 level target device addr +} PhysDevAddr_struct; + +typedef struct _LogDevAddr_struct { + DWORD VolId:30; + DWORD Mode:2; + BYTE reserved[4]; +} LogDevAddr_struct; + +typedef union _LUNAddr_struct { + BYTE LunAddrBytes[8]; + SCSI3Addr_struct SCSI3Lun[4]; + PhysDevAddr_struct PhysDev; + LogDevAddr_struct LogDev; +} LUNAddr_struct; + +typedef struct _RequestBlock_struct { + BYTE CDBLen; + struct { + BYTE Type:3; + BYTE Attribute:3; + BYTE Direction:2; + } Type; + HWORD Timeout; + BYTE CDB[16]; +} RequestBlock_struct; + +typedef union _MoreErrInfo_struct{ + struct { + BYTE Reserved[3]; + BYTE Type; + DWORD ErrorInfo; + }Common_Info; + struct{ + BYTE Reserved[2]; + BYTE offense_size;//size of offending entry + BYTE offense_num; //byte # of offense 0-base + DWORD offense_value; + }Invalid_Cmd; +}MoreErrInfo_struct; + +typedef struct _ErrorInfo_struct { + BYTE ScsiStatus; + BYTE SenseLen; + HWORD CommandStatus; + DWORD ResidualCnt; + MoreErrInfo_struct MoreErrInfo; + BYTE SenseInfo[SENSEINFOBYTES]; +} ErrorInfo_struct; + +#pragma pack() + +typedef struct _IOCTL_Command_struct { + LUNAddr_struct LUN_info; + RequestBlock_struct Request; + ErrorInfo_struct error_info; + WORD buf_size; /* size in bytes of the buf */ + BYTE *buf; +} IOCTL_Command_struct; + +typedef struct _LogvolInfo_struct{ + __u32 LunID; + int num_opens; /* number of opens on the logical volume */ + int num_parts; /* number of partitions configured on logvol */ +} LogvolInfo_struct; + +#define CCISS_PASSTHRU _IOWR(CCISS_IOC_MAGIC, 11, IOCTL_Command_struct) +#define CCISS_GETLUNINFO _IOR(CCISS_IOC_MAGIC, 17, LogvolInfo_struct) + +int cciss_init( struct checker *); +void cciss_free (struct checker * c); +int cciss_tur( struct checker *); + +#endif + diff --git a/libcheckers/cciss_tur.c b/libcheckers/cciss_tur.c new file mode 100644 index 0000000..d0b0771 --- /dev/null +++ b/libcheckers/cciss_tur.c @@ -0,0 +1,137 @@ +/* + ***************************************************************************** + * * + * (C) Copyright 2007 Hewlett-Packard Development Company, L.P * + * * + * This program is free software; you can redistribute it and/or modify it * + * under the terms of the GNU General Public License as published by the Free* + * Software Foundation; either version 2 of the License, or (at your option)* + * any later version. * + * * + * This program is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY* + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * + * for more details. * + * * + * You should have received a copy of the GNU General Public License along * + * with this program; if not, write to the Free Software Foundation, Inc., * + * 675 Mass Ave, Cambridge, MA 02139, USA. * + * * + * The copy of the GNU General Public License is available at * + * /opt/hp/HPDMmultipath-tool directoy * + * * + ***************************************************************************** +*/ + +/* + * This program originally derived from and inspired by + * Christophe Varoqui's tur.c, part of libchecker. + */ + + +#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 "cciss.h" + +#define TUR_CMD_LEN 6 +#define HEAVY_CHECK_COUNT 10 + +#define MSG_CCISS_TUR_UP "cciss_tur checker reports path is up" +#define MSG_CCISS_TUR_DOWN "cciss_tur checker reports path is down" + +struct cciss_tur_checker_context { + void * dummy; +}; + +int cciss_init (struct checker * c) +{ + return 0; +} + +void cciss_free (struct checker * c) +{ + return; +} + +extern int +cciss_tur (struct checker * c) +{ + int rc; + int ret; + unsigned int lun = 0; + struct cciss_tur_checker_context * ctxt = NULL; + LogvolInfo_struct lvi; // logical "volume" info + IOCTL_Command_struct cic; // cciss ioctl command + + if ((c->fd) <= 0) { + MSG(c,"no usable fd"); + ret = -1; + goto out; + } + + rc = ioctl(c->fd, CCISS_GETLUNINFO, &lvi); + if ( rc != 0) { + perror("Error: "); + fprintf(stderr, "cciss TUR failed in CCISS_GETLUNINFO: %s\n", + strerror(errno)); + MSG(c,MSG_CCISS_TUR_DOWN); + ret = PATH_DOWN; + goto out; + } else { + lun = lvi.LunID; + } + + memset(&cic, 0, sizeof(cic)); + cic.LUN_info.LogDev.VolId = lun & 0x3FFFFFFF; + cic.LUN_info.LogDev.Mode = 0x01; /* logical volume addressing */ + cic.Request.CDBLen = 6; /* need to try just 2 bytes here */ + cic.Request.Type.Type = TYPE_CMD; // It is a command. + cic.Request.Type.Attribute = ATTR_SIMPLE; + cic.Request.Type.Direction = XFER_NONE; + cic.Request.Timeout = 0; + + cic.Request.CDB[0] = 0; + cic.Request.CDB[1] = 0; + cic.Request.CDB[2] = 0; + cic.Request.CDB[3] = 0; + cic.Request.CDB[4] = 0; + cic.Request.CDB[5] = 0; + + rc = ioctl(c->fd, CCISS_PASSTHRU, &cic); + if (rc < 0) { + fprintf(stderr, "cciss TUR failed: %s\n", + strerror(errno)); + MSG(c,MSG_CCISS_TUR_DOWN); + ret = PATH_DOWN; + goto out; + } + + if ((cic.error_info.CommandStatus | cic.error_info.ScsiStatus )) { + MSG(c,MSG_CCISS_TUR_DOWN); + ret = PATH_DOWN; + goto out; + } + + MSG(c,MSG_CCISS_TUR_UP); + + ret = PATH_UP; +out: + /* + * caller told us he doesn't want to keep the context : + * free it + */ + if (!c->context) + free(ctxt); + + return(ret); +} diff --git a/libcheckers/checkers.c b/libcheckers/checkers.c index f07d537..fd27d3f 100644 --- a/libcheckers/checkers.c +++ b/libcheckers/checkers.c @@ -9,6 +9,7 @@ #include "emc_clariion.h" #include "rdac.h" #include "readsector0.h" +#include "cciss.h" static struct checker checkers[] = { { @@ -71,6 +72,18 @@ static struct checker checkers[] = { .init = readsector0_init, .free = readsector0_free }, + + { + .fd = 0, + .sync = 1, + .name = CCISS_TUR, + .message = "", + .context = NULL, + .check = cciss_tur, + .init = cciss_init, + .free = cciss_free + }, + {0, 1, 0, "", "", NULL, NULL, NULL, NULL}, }; diff --git a/libcheckers/checkers.h b/libcheckers/checkers.h index 3ce643b..283bcc1 100644 --- a/libcheckers/checkers.h +++ b/libcheckers/checkers.h @@ -58,6 +58,7 @@ #define RDAC "rdac" #define EMC_CLARIION "emc_clariion" #define READSECTOR0 "readsector0" +#define CCISS_TUR "cciss_tur" #define DEFAULT_CHECKER DIRECTIO diff --git a/libmultipath/blacklist.c b/libmultipath/blacklist.c index 5a7c1ec..6587f60 100644 --- a/libmultipath/blacklist.c +++ b/libmultipath/blacklist.c @@ -114,12 +114,6 @@ setup_default_blist (struct config * conf) return 1; if (store_ble(conf->blist_devnode, str, ORIGIN_DEFAULT)) return 1; - - str = STRDUP("^cciss!c[0-9]d[0-9]*"); - if (!str) - return 1; - if (store_ble(conf->blist_devnode, str, ORIGIN_DEFAULT)) - return 1; str = STRDUP("^dcssblk[0-9]*"); if (!str) diff --git a/libmultipath/discovery.c b/libmultipath/discovery.c index 74311a8..9045d1d 100644 --- a/libmultipath/discovery.c +++ b/libmultipath/discovery.c @@ -69,9 +69,11 @@ path_discover (vector pathvec, struct config * conf, char * devname, int flag) condlog(0, "path too small"); return 1; } - - if (!filepresent(path)) + + if (strncmp(devname,"cciss",5) && !filepresent(path)) { + condlog(4, "path %s not present", path); return 0; + } pp = find_path_by_dev(pathvec, devname); @@ -216,12 +218,18 @@ out: static int opennode (char * dev, int mode) { - char devpath[FILE_NAME_SIZE]; + char devpath[FILE_NAME_SIZE], *ptr; if (safe_sprintf(devpath, "%s/%s", conf->udev_dir, dev)) { condlog(0, "devpath too small"); return -1; } + /* Translate '!' into '/' */ + ptr = devpath; + while ((ptr = strchr(ptr, '!'))) { + *ptr = '/'; + ptr++; + } if (wait_for_file(devpath)) { condlog(3, "failed to open %s", devpath); @@ -356,6 +364,27 @@ get_serial (char * str, int maxlen, int fd) } static int +get_inq (char * vendor, char * product, char * rev, int fd) +{ + int len = 0; + char buff[MX_ALLOC_LEN + 1] = {0}; + + if (fd < 0) + return 1; + + if (0 == do_inq(fd, 0, 0, 0, buff, MX_ALLOC_LEN, 0)) { + memcpy(vendor, buff + 8, 8); + vendor[8] = '\0'; + memcpy(product, buff + 16, 16); + product[16] = '\0'; + memcpy(rev, buff + 32, 4); + rev[4] = '\0'; + return 0; + } + return 1; +} + +static int sysfs_get_bus (char * sysfs_path, struct path * pp) { struct sysfs_device *sdev; @@ -400,6 +429,8 @@ sysfs_get_bus (char * sysfs_path, struct path * pp) pp->bus = SYSFS_BUS_IDE; else if (!strncmp(sdev->bus, "ccw", 3)) pp->bus = SYSFS_BUS_CCW; + else if (!strncmp(pp->dev,"cciss", 5)) + pp->bus = SYSFS_BUS_CCISS; else return 1; @@ -550,6 +581,30 @@ ccw_sysfs_pathinfo (struct path * pp) } static int +cciss_sysfs_pathinfo (struct path * pp) +{ + char attr_path[FILE_NAME_SIZE]; + + /* + * host / bus / target / lun + */ + basename(pp->dev, attr_path); + pp->sg_id.lun = 0; + pp->sg_id.channel = 0; + sscanf(attr_path, "cciss!c%id%i", + &pp->sg_id.host_no, + &pp->sg_id.scsi_id); + condlog(3, "%s: h:b:t:l = %i:%i:%i:%i", + pp->dev, + pp->sg_id.host_no, + pp->sg_id.channel, + pp->sg_id.scsi_id, + pp->sg_id.lun); + + return 0; +} + +static int common_sysfs_pathinfo (struct path * pp) { if (sysfs_get_bus(sysfs_path, pp)) @@ -585,6 +640,9 @@ sysfs_pathinfo(struct path * pp) } else if (pp->bus == SYSFS_BUS_CCW) { if (ccw_sysfs_pathinfo(pp)) return 1; + } else if (pp->bus == SYSFS_BUS_CCISS) { + if (cciss_sysfs_pathinfo(pp)) + return 1; } return 0; } @@ -601,6 +659,24 @@ scsi_ioctl_pathinfo (struct path * pp, int mask) } static int +cciss_ioctl_pathinfo (struct path * pp, int mask) +{ + if (mask & DI_SYSFS) { + get_inq(pp->vendor_id, pp->product_id, pp->rev, pp->fd); + condlog(3, "%s: vendor = %s", pp->dev, pp->vendor_id); + condlog(3, "%s: product = %s", pp->dev, pp->product_id); + condlog(3, "%s: revision = %s", pp->dev, pp->rev); + /* + * set the hwe configlet pointer + */ + pp->hwe = find_hwe(conf->hwtable, pp->vendor_id, + pp->product_id, pp->rev); + } + + return 0; +} + +static int get_state (struct path * pp) { struct checker * c = &pp->checker; @@ -688,16 +764,23 @@ pathinfo (struct path *pp, vector hwtable, int mask) if (pp->fd < 0) pp->fd = opennode(pp->dev, O_RDONLY); - if (pp->fd < 0) + if (pp->fd < 0) { + condlog(4, "Couldn't open node for %s: %s", + pp->dev, strerror(errno)); goto blank; + } if (pp->bus == SYSFS_BUS_SCSI && scsi_ioctl_pathinfo(pp, mask)) goto blank; + if (pp->bus == SYSFS_BUS_CCISS && + cciss_ioctl_pathinfo(pp, mask)) + goto blank; + if (mask & DI_CHECKER && get_state(pp)) goto blank; - + /* * Retrieve path priority for even PATH_DOWN paths if it has never * been successfully obtained before. diff --git a/libmultipath/hwtable.c b/libmultipath/hwtable.c index 924299c..49b38e2 100644 --- a/libmultipath/hwtable.c +++ b/libmultipath/hwtable.c @@ -153,6 +153,22 @@ static struct hwentry default_hw[] = { .minio = DEFAULT_MINIO, .checker_name = TUR, }, + { + /* HP Smart Array */ + .vendor = "HP", + .product = "LOGICAL VOLUME.*", + .getuid = "scsi_id -n -g -u -s /block/%n", + .getprio = NULL, + .features = DEFAULT_FEATURES, + .hwhandler = DEFAULT_HWHANDLER, + .selector = DEFAULT_SELECTOR, + .pgpolicy = MULTIBUS, + .pgfailback = FAILBACK_UNDEF, + .rr_weight = RR_WEIGHT_NONE, + .no_path_retry = NO_PATH_RETRY_UNDEF, + .minio = DEFAULT_MINIO, + .checker_name = CCISS_TUR, + }, /* * DDN controller family * diff --git a/libmultipath/structs.h b/libmultipath/structs.h index 77dd4af..7cab7ac 100644 --- a/libmultipath/structs.h +++ b/libmultipath/structs.h @@ -43,6 +43,7 @@ enum sysfs_buses { SYSFS_BUS_SCSI, SYSFS_BUS_IDE, SYSFS_BUS_CCW, + SYSFS_BUS_CCISS, }; enum pathstates { -- 1.5.0.4.GIT