#include <errno.h>
#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;
}