2 * Copyright (c) 2005 Christophe Varoqui
11 #include <sys/ioctl.h>
17 #include "../libmultipath/sg_include.h"
19 #define INQUIRY_CMDLEN 6
20 #define INQUIRY_CMD 0x12
21 #define MODE_SENSE_CMD 0x5a
22 #define MODE_SELECT_CMD 0x55
23 #define MODE_SEN_SEL_CMDLEN 10
24 #define SENSE_BUFF_LEN 32
25 #define SCSI_CHECK_CONDITION 0x2
26 #define SCSI_COMMAND_TERMINATED 0x22
27 #define SG_ERR_DRIVER_SENSE 0x08
28 #define RECOVERED_ERROR 0x01
31 #define CURRENT_PAGE_CODE_VALUES 0
32 #define CHANGEABLE_PAGE_CODE_VALUES 1
34 #define MSG_RDAC_UP "rdac checker reports path is up"
35 #define MSG_RDAC_DOWN "rdac checker reports path is down"
36 #define MSG_RDAC_GHOST "rdac checker reports path is ghost"
38 struct control_mode_page {
39 unsigned char header[8];
40 unsigned char page_code;
41 unsigned char page_len;
42 unsigned char dontcare0[3];
43 unsigned char tas_bit;
44 unsigned char dontcare1[6];
47 struct rdac_checker_context {
51 int libcheck_init (struct checker * c)
53 unsigned char cmd[MODE_SEN_SEL_CMDLEN];
54 unsigned char sense_b[SENSE_BUFF_LEN];
55 struct sg_io_hdr io_hdr;
56 struct control_mode_page current, changeable;
59 memset(cmd, 0, MODE_SEN_SEL_CMDLEN);
60 cmd[0] = MODE_SENSE_CMD;
61 cmd[1] = 0x08; /* DBD bit on */
62 cmd[2] = 0xA + (CURRENT_PAGE_CODE_VALUES << 6);
63 cmd[8] = (sizeof(struct control_mode_page) & 0xff);
65 memset(&io_hdr, 0, sizeof(struct sg_io_hdr));
66 memset(sense_b, 0, SENSE_BUFF_LEN);
67 memset(¤t, 0, sizeof(struct control_mode_page));
69 io_hdr.interface_id = 'S';
70 io_hdr.cmd_len = MODE_SEN_SEL_CMDLEN;
71 io_hdr.mx_sb_len = sizeof(sense_b);
72 io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
73 io_hdr.dxfer_len = (sizeof(struct control_mode_page) & 0xff);
74 io_hdr.dxferp = ¤t;
77 io_hdr.timeout = c->timeout;
79 if (ioctl(c->fd, SG_IO, &io_hdr) < 0)
82 /* check the TAS bit to see if it is already set */
83 if ((current.tas_bit >> 6) & 0x1) {
88 /* get the changeble values */
89 cmd[2] = 0xA + (CHANGEABLE_PAGE_CODE_VALUES << 6);
90 io_hdr.dxferp = &changeable;
91 memset(&changeable, 0, sizeof(struct control_mode_page));
93 if (ioctl(c->fd, SG_IO, &io_hdr) < 0)
96 /* if TAS bit is not settable exit */
97 if (((changeable.tas_bit >> 6) & 0x1) == 0)
100 /* Now go ahead and set it */
101 memset(cmd, 0, MODE_SEN_SEL_CMDLEN);
102 cmd[0] = MODE_SELECT_CMD;
103 cmd[1] = 0x1; /* set SP bit on */
104 cmd[8] = (sizeof(struct control_mode_page) & 0xff);
106 /* use the same buffer as current, only set the tas bit */
107 current.page_code = 0xA;
108 current.page_len = 0xA;
109 current.tas_bit |= (1 << 6);
111 io_hdr.dxfer_direction = SG_DXFER_TO_DEV;
112 io_hdr.dxferp = ¤t;
114 if (ioctl(c->fd, SG_IO, &io_hdr) < 0)
121 condlog(3, "rdac checker failed to set TAS bit");
125 void libcheck_free (struct checker * c)
131 do_inq(int sg_fd, unsigned int pg_op, void *resp, int mx_resp_len,
132 unsigned int timeout)
134 unsigned char inqCmdBlk[INQUIRY_CMDLEN] = { INQUIRY_CMD, 1, 0, 0, 0, 0 };
135 unsigned char sense_b[SENSE_BUFF_LEN];
136 struct sg_io_hdr io_hdr;
140 inqCmdBlk[2] = (unsigned char) pg_op;
141 inqCmdBlk[4] = (unsigned char) (mx_resp_len & 0xff);
142 memset(&io_hdr, 0, sizeof (struct sg_io_hdr));
143 memset(sense_b, 0, SENSE_BUFF_LEN);
145 io_hdr.interface_id = 'S';
146 io_hdr.cmd_len = sizeof (inqCmdBlk);
147 io_hdr.mx_sb_len = sizeof (sense_b);
148 io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
149 io_hdr.dxfer_len = mx_resp_len;
150 io_hdr.dxferp = resp;
151 io_hdr.cmdp = inqCmdBlk;
152 io_hdr.sbp = sense_b;
153 io_hdr.timeout = timeout;
155 if (ioctl(sg_fd, SG_IO, &io_hdr) < 0)
158 /* treat SG_ERR here to get rid of sg_err.[ch] */
159 io_hdr.status &= 0x7e;
160 if ((0 == io_hdr.status) && (0 == io_hdr.host_status) &&
161 (0 == io_hdr.driver_status))
164 /* check if we need to retry this error */
165 if (io_hdr.info & SG_INFO_OK_MASK) {
166 switch (io_hdr.host_status) {
170 case DID_TRANSPORT_DISRUPTED:
171 /* Transport error, retry */
180 if ((SCSI_CHECK_CONDITION == io_hdr.status) ||
181 (SCSI_COMMAND_TERMINATED == io_hdr.status) ||
182 (SG_ERR_DRIVER_SENSE == (0xf & io_hdr.driver_status))) {
183 if (io_hdr.sbp && (io_hdr.sb_len_wr > 2)) {
185 unsigned char * sense_buffer = io_hdr.sbp;
186 if (sense_buffer[0] & 0x2)
187 sense_key = sense_buffer[1] & 0xf;
189 sense_key = sense_buffer[2] & 0xf;
190 if (RECOVERED_ERROR == sense_key)
197 struct volume_access_inq
203 char asym_access_state_cur;
204 char vendor_specific_cur;
209 libcheck_check (struct checker * c)
211 struct volume_access_inq inq;
214 memset(&inq, 0, sizeof(struct volume_access_inq));
215 if (0 != do_inq(c->fd, 0xC9, &inq, sizeof(struct volume_access_inq),
219 } else if (((inq.PQ_PDT & 0xE0) == 0x20) || (inq.PQ_PDT & 0x7f)) {
220 /* LUN not connected*/
225 /* check if controller is in service mode */
226 if ((inq.avtcvp & 0x10) &&
227 ((inq.asym_access_state_cur & 0x0F) == 0x3) &&
228 (inq.vendor_specific_cur == 0x7)) {
233 /* If owner set or ioship mode is enabled return PATH_UP always */
234 if ((inq.avtcvp & 0x1) || ((inq.avtcvp >> 5) & 0x1))
242 MSG(c, MSG_RDAC_DOWN);
248 MSG(c, MSG_RDAC_GHOST);