--- libmultipath/checkers/rdac.c | 92 ++++++++++++++++++++++++++++++++++++++- libmultipath/prioritizers/rdac.c | 4 + 2 files changed, 95 insertions(+), 1 deletion(-) Index: multipath-tools/libmultipath/checkers/rdac.c =================================================================== --- multipath-tools.orig/libmultipath/checkers/rdac.c +++ multipath-tools/libmultipath/checkers/rdac.c @@ -12,27 +12,113 @@ #include #include "checkers.h" +#include "debug.h" #include "../libmultipath/sg_include.h" #define INQUIRY_CMDLEN 6 #define INQUIRY_CMD 0x12 +#define MODE_SENSE_CMD 0x5a +#define MODE_SELECT_CMD 0x55 +#define MODE_SEN_SEL_CMDLEN 10 #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 CURRENT_PAGE_CODE_VALUES 0 +#define CHANGEABLE_PAGE_CODE_VALUES 1 + #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 control_mode_page { + unsigned char header[8]; + unsigned char page_code; + unsigned char page_len; + unsigned char dontcare0[3]; + unsigned char tas_bit; + unsigned char dontcare1[6]; +}; + struct rdac_checker_context { void * dummy; }; int libcheck_init (struct checker * c) { + unsigned char cmd[MODE_SEN_SEL_CMDLEN]; + unsigned char sense_b[SENSE_BUFF_LEN]; + struct sg_io_hdr io_hdr; + struct control_mode_page current, changeable; + int set = 0; + + memset(cmd, 0, MODE_SEN_SEL_CMDLEN); + cmd[0] = MODE_SENSE_CMD; + cmd[1] = 0x08; /* DBD bit on */ + cmd[2] = 0xA + (CURRENT_PAGE_CODE_VALUES << 6); + cmd[8] = (sizeof(struct control_mode_page) & 0xff); + + memset(&io_hdr, 0, sizeof(struct sg_io_hdr)); + memset(sense_b, 0, SENSE_BUFF_LEN); + memset(¤t, 0, sizeof(struct control_mode_page)); + + io_hdr.interface_id = 'S'; + io_hdr.cmd_len = MODE_SEN_SEL_CMDLEN; + io_hdr.mx_sb_len = sizeof(sense_b); + io_hdr.dxfer_direction = SG_DXFER_FROM_DEV; + io_hdr.dxfer_len = (sizeof(struct control_mode_page) & 0xff); + io_hdr.dxferp = ¤t; + io_hdr.cmdp = cmd; + io_hdr.sbp = sense_b; + io_hdr.timeout = c->timeout; + + if (ioctl(c->fd, SG_IO, &io_hdr) < 0) + goto out; + + /* check the TAS bit to see if it is already set */ + if ((current.tas_bit >> 6) & 0x1) { + set = 1; + goto out; + } + + /* get the changeble values */ + cmd[2] = 0xA + (CHANGEABLE_PAGE_CODE_VALUES << 6); + io_hdr.dxferp = &changeable; + memset(&changeable, 0, sizeof(struct control_mode_page)); + + if (ioctl(c->fd, SG_IO, &io_hdr) < 0) + goto out; + + /* if TAS bit is not settable exit */ + if (((changeable.tas_bit >> 6) & 0x1) == 0) + goto out; + + /* Now go ahead and set it */ + memset(cmd, 0, MODE_SEN_SEL_CMDLEN); + cmd[0] = MODE_SELECT_CMD; + cmd[1] = 0x1; /* set SP bit on */ + cmd[8] = (sizeof(struct control_mode_page) & 0xff); + + /* use the same buffer as current, only set the tas bit */ + current.page_code = 0xA; + current.page_len = 0xA; + current.tas_bit |= (1 << 6); + + io_hdr.dxfer_direction = SG_DXFER_TO_DEV; + io_hdr.dxferp = ¤t; + + if (ioctl(c->fd, SG_IO, &io_hdr) < 0) + goto out; + + /* Success */ + set = 1; +out: + if (set == 0) + condlog(0, "rdac checker failed to set TAS bit"); return 0; } @@ -132,7 +218,11 @@ libcheck_check (struct checker * c) goto done; } - ret = ((inq.avtcvp & 0x1) ? PATH_UP : PATH_GHOST); + /* If owner set or ioship mode is enabled return PATH_UP always */ + if ((inq.avtcvp & 0x1) || ((inq.avtcvp >> 5) & 0x1)) + ret = PATH_UP; + else + ret = PATH_GHOST; done: switch (ret) { Index: multipath-tools/libmultipath/prioritizers/rdac.c =================================================================== --- multipath-tools.orig/libmultipath/prioritizers/rdac.c +++ multipath-tools/libmultipath/prioritizers/rdac.c @@ -81,6 +81,10 @@ int rdac_prio(const char *dev, int fd) break; } + /* For ioship mode set the bit 3 (00001000) */ + if ((sense_buffer[8] >> 5) & 0x01) + ret |= 0x08; + out: return(ret); }