multipathd: fix reservation_key check
[multipath-tools/.git] / libmultipath / checkers / rdac.c
1 /*
2  * Copyright (c) 2005 Christophe Varoqui
3  */
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <string.h>
7 #include <sys/types.h>
8 #include <sys/stat.h>
9 #include <unistd.h>
10 #include <fcntl.h>
11 #include <sys/ioctl.h>
12 #include <errno.h>
13
14 #include "checkers.h"
15 #include "debug.h"
16
17 #include "../libmultipath/sg_include.h"
18
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
29
30
31 #define CURRENT_PAGE_CODE_VALUES        0
32 #define CHANGEABLE_PAGE_CODE_VALUES     1
33
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"
37 #define MSG_RDAC_DOWN_TYPE(STR) MSG_RDAC_DOWN": "STR
38
39 #define RTPG_UNAVAILABLE        0x3
40 #define RTPG_OFFLINE            0xE
41 #define RTPG_TRANSITIONING      0xF
42
43 #define RTPG_UNAVAIL_NON_RESPONSIVE     0x2
44 #define RTPG_UNAVAIL_IN_RESET           0x3
45 #define RTPG_UNAVAIL_CFW_DL1            0x4
46 #define RTPG_UNAVAIL_CFW_DL2            0x5
47 #define RTPG_UNAVAIL_QUIESCED           0x6
48 #define RTPG_UNAVAIL_SERVICE_MODE       0x7
49
50 struct control_mode_page {
51         unsigned char header[8];
52         unsigned char page_code;
53         unsigned char page_len;
54         unsigned char dontcare0[3];
55         unsigned char tas_bit;
56         unsigned char dontcare1[6];
57 };
58
59 struct rdac_checker_context {
60         void * dummy;
61 };
62
63 int libcheck_init (struct checker * c)
64 {
65         unsigned char cmd[MODE_SEN_SEL_CMDLEN];
66         unsigned char sense_b[SENSE_BUFF_LEN];
67         struct sg_io_hdr io_hdr;
68         struct control_mode_page current, changeable;
69         int set = 0;
70
71         memset(cmd, 0, MODE_SEN_SEL_CMDLEN);
72         cmd[0] = MODE_SENSE_CMD;
73         cmd[1] = 0x08; /* DBD bit on */
74         cmd[2] = 0xA + (CURRENT_PAGE_CODE_VALUES << 6);
75         cmd[8] = (sizeof(struct control_mode_page) &  0xff);
76
77         memset(&io_hdr, 0, sizeof(struct sg_io_hdr));
78         memset(sense_b, 0, SENSE_BUFF_LEN);
79         memset(&current, 0, sizeof(struct control_mode_page));
80
81         io_hdr.interface_id = 'S';
82         io_hdr.cmd_len = MODE_SEN_SEL_CMDLEN;
83         io_hdr.mx_sb_len = sizeof(sense_b);
84         io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
85         io_hdr.dxfer_len = (sizeof(struct control_mode_page) &  0xff);
86         io_hdr.dxferp = &current;
87         io_hdr.cmdp = cmd;
88         io_hdr.sbp = sense_b;
89         io_hdr.timeout = c->timeout * 1000;
90
91         if (ioctl(c->fd, SG_IO, &io_hdr) < 0)
92                 goto out;
93
94         /* check the TAS bit to see if it is already set */
95         if ((current.tas_bit >> 6) & 0x1) {
96                 set = 1;
97                 goto out;
98         }
99
100         /* get the changeble values */
101         cmd[2] = 0xA + (CHANGEABLE_PAGE_CODE_VALUES << 6);
102         io_hdr.dxferp = &changeable;
103         memset(&changeable, 0, sizeof(struct control_mode_page));
104
105         if (ioctl(c->fd, SG_IO, &io_hdr) < 0)
106                 goto out;
107
108         /* if TAS bit is not settable exit */
109         if (((changeable.tas_bit >> 6) & 0x1) == 0)
110                 goto out;
111
112         /* Now go ahead and set it */
113         memset(cmd, 0, MODE_SEN_SEL_CMDLEN);
114         cmd[0] = MODE_SELECT_CMD;
115         cmd[1] = 0x1; /* set SP bit on */
116         cmd[8] = (sizeof(struct control_mode_page) &  0xff);
117
118         /* use the same buffer as current, only set the tas bit */
119         current.page_code = 0xA;
120         current.page_len = 0xA;
121         current.tas_bit |= (1 << 6);
122
123         io_hdr.dxfer_direction = SG_DXFER_TO_DEV;
124         io_hdr.dxferp = &current;
125
126         if (ioctl(c->fd, SG_IO, &io_hdr) < 0)
127                 goto out;
128
129         /* Success */
130         set = 1;
131 out:
132         if (set == 0)
133                 condlog(3, "rdac checker failed to set TAS bit");
134         return 0;
135 }
136
137 void libcheck_free (struct checker * c)
138 {
139         return;
140 }
141
142 void libcheck_repair (struct checker * c)
143 {
144         return;
145 }
146
147 static int
148 do_inq(int sg_fd, unsigned int pg_op, void *resp, int mx_resp_len,
149        unsigned int timeout)
150 {
151         unsigned char inqCmdBlk[INQUIRY_CMDLEN] = { INQUIRY_CMD, 1, 0, 0, 0, 0 };
152         unsigned char sense_b[SENSE_BUFF_LEN];
153         struct sg_io_hdr io_hdr;
154         int retry_rdac = 5;
155
156 retry:
157         inqCmdBlk[2] = (unsigned char) pg_op;
158         inqCmdBlk[4] = (unsigned char) (mx_resp_len & 0xff);
159         memset(&io_hdr, 0, sizeof (struct sg_io_hdr));
160         memset(sense_b, 0, SENSE_BUFF_LEN);
161
162         io_hdr.interface_id = 'S';
163         io_hdr.cmd_len = sizeof (inqCmdBlk);
164         io_hdr.mx_sb_len = sizeof (sense_b);
165         io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
166         io_hdr.dxfer_len = mx_resp_len;
167         io_hdr.dxferp = resp;
168         io_hdr.cmdp = inqCmdBlk;
169         io_hdr.sbp = sense_b;
170         io_hdr.timeout = timeout * 1000;
171
172         if (ioctl(sg_fd, SG_IO, &io_hdr) < 0)
173                 return 1;
174
175         /* treat SG_ERR here to get rid of sg_err.[ch] */
176         io_hdr.status &= 0x7e;
177         if ((0 == io_hdr.status) && (0 == io_hdr.host_status) &&
178             (0 == io_hdr.driver_status))
179                 return 0;
180
181         /* check if we need to retry this error */
182         if (io_hdr.info & SG_INFO_OK_MASK) {
183                 switch (io_hdr.host_status) {
184                 case DID_BUS_BUSY:
185                 case DID_ERROR:
186                 case DID_SOFT_ERROR:
187                 case DID_TRANSPORT_DISRUPTED:
188                         /* Transport error, retry */
189                         if (--retry_rdac)
190                                 goto retry;
191                         break;
192                 default:
193                         break;
194                 }
195         }
196
197         if ((SCSI_CHECK_CONDITION == io_hdr.status) ||
198             (SCSI_COMMAND_TERMINATED == io_hdr.status) ||
199             (SG_ERR_DRIVER_SENSE == (0xf & io_hdr.driver_status))) {
200                 if (io_hdr.sbp && (io_hdr.sb_len_wr > 2)) {
201                         int sense_key;
202                         unsigned char * sense_buffer = io_hdr.sbp;
203                         if (sense_buffer[0] & 0x2)
204                                 sense_key = sense_buffer[1] & 0xf;
205                         else
206                                 sense_key = sense_buffer[2] & 0xf;
207                         if (RECOVERED_ERROR == sense_key)
208                                 return 0;
209                 }
210         }
211         return 1;
212 }
213
214 struct volume_access_inq
215 {
216         char PQ_PDT;
217         char dontcare0[7];
218         char avtcvp;
219         char vol_ppp;
220         char aas_cur;
221         char vendor_specific_cur;
222         char aas_alt;
223         char vendor_specific_alt;
224         char dontcare1[34];
225 };
226
227 const char
228 *checker_msg_string(struct volume_access_inq *inq)
229 {
230         /* lun not connected */
231         if (((inq->PQ_PDT & 0xE0) == 0x20) || (inq->PQ_PDT & 0x7f))
232                 return MSG_RDAC_DOWN_TYPE("lun not connected");
233
234         /* if no tpg data is available, give the generic path down message */
235         if (!(inq->avtcvp & 0x10))
236                 return MSG_RDAC_DOWN;
237
238         /* controller is booting up */
239         if (((inq->aas_cur & 0x0F) == RTPG_TRANSITIONING) &&
240                 (inq->aas_alt & 0x0F) != RTPG_TRANSITIONING)
241                 return MSG_RDAC_DOWN_TYPE("ctlr is in startup sequence");
242
243         /* if not unavailable, give generic message */
244         if ((inq->aas_cur & 0x0F) != RTPG_UNAVAILABLE)
245                 return MSG_RDAC_DOWN;
246
247         /* target port group unavailable */
248         switch (inq->vendor_specific_cur) {
249         case RTPG_UNAVAIL_NON_RESPONSIVE:
250                 return MSG_RDAC_DOWN_TYPE("non-responsive to queries");
251         case RTPG_UNAVAIL_IN_RESET:
252                 return MSG_RDAC_DOWN_TYPE("ctlr held in reset");
253         case RTPG_UNAVAIL_CFW_DL1:
254         case RTPG_UNAVAIL_CFW_DL2:
255                 return MSG_RDAC_DOWN_TYPE("ctlr firmware downloading");
256         case RTPG_UNAVAIL_QUIESCED:
257                 return MSG_RDAC_DOWN_TYPE("ctlr quiesced by admin request");
258         case RTPG_UNAVAIL_SERVICE_MODE:
259                 return MSG_RDAC_DOWN_TYPE("ctlr is in service mode");
260         default:
261                 return MSG_RDAC_DOWN_TYPE("ctlr is unavailable");
262         }
263 }
264
265 int libcheck_check(struct checker * c)
266 {
267         struct volume_access_inq inq;
268         int ret, inqfail;
269
270         inqfail = 0;
271         memset(&inq, 0, sizeof(struct volume_access_inq));
272         if (0 != do_inq(c->fd, 0xC9, &inq, sizeof(struct volume_access_inq),
273                         c->timeout)) {
274                 ret = PATH_DOWN;
275                 inqfail = 1;
276                 goto done;
277         } else if (((inq.PQ_PDT & 0xE0) == 0x20) || (inq.PQ_PDT & 0x7f)) {
278                 /* LUN not connected*/
279                 ret = PATH_DOWN;
280                 goto done;
281         }
282
283         /* If TPGDE bit set, evaluate TPG information */
284         if ((inq.avtcvp & 0x10)) {
285                 switch (inq.aas_cur & 0x0F) {
286                 /* Never use the path if it reports unavailable */
287                 case RTPG_UNAVAILABLE:
288                         ret = PATH_DOWN;
289                         goto done;
290                 /*
291                  * If both controllers report transitioning, it
292                  * means mode select or STPG is being processed.
293                  *
294                  * If this controller alone is transitioning, it's
295                  * booting and we shouldn't use it yet.
296                  */
297                 case RTPG_TRANSITIONING:
298                         if ((inq.aas_alt & 0xF) != RTPG_TRANSITIONING) {
299                                 ret = PATH_DOWN;
300                                 goto done;
301                         }
302                         break;
303                 }
304         }
305
306         /* If owner set or ioship mode is enabled return PATH_UP always */
307         if ((inq.avtcvp & 0x1) || ((inq.avtcvp >> 5) & 0x1))
308                 ret = PATH_UP;
309         else
310                 ret = PATH_GHOST;
311
312 done:
313         switch (ret) {
314         case PATH_DOWN:
315                 MSG(c, "%s", (inqfail) ? MSG_RDAC_DOWN_TYPE("inquiry failed") :
316                         checker_msg_string(&inq));
317                 break;
318         case PATH_UP:
319                 MSG(c, MSG_RDAC_UP);
320                 break;
321         case PATH_GHOST:
322                 MSG(c, MSG_RDAC_GHOST);
323                 break;
324         }
325
326         return ret;
327 }