[build] legacy files update
[platform/upstream/multipath-tools.git] / libcheckers / hp_sw.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 "path_state.h"
15 #include "checkers.h"
16
17 #include "../libmultipath/sg_include.h"
18
19 #define TUR_CMD_LEN             6
20 #define INQUIRY_CMDLEN          6
21 #define INQUIRY_CMD             0x12
22 #define SENSE_BUFF_LEN          32
23 #define DEF_TIMEOUT             60000
24 #define SCSI_CHECK_CONDITION    0x2
25 #define SCSI_COMMAND_TERMINATED 0x22
26 #define SG_ERR_DRIVER_SENSE     0x08
27 #define RECOVERED_ERROR         0x01
28 #define MX_ALLOC_LEN            255
29 #define HEAVY_CHECK_COUNT       10
30
31 #define MSG_HP_SW_UP    "hp_sw checker reports path is up"
32 #define MSG_HP_SW_DOWN  "hp_sw checker reports path is down"
33 #define MSG_HP_SW_GHOST "hp_sw checker reports path is ghost"
34
35 struct sw_checker_context {
36         int run_count;
37 };
38
39 static int
40 do_inq(int sg_fd, int cmddt, int evpd, unsigned int pg_op,
41        void *resp, int mx_resp_len, int noisy)
42 {
43         unsigned char inqCmdBlk[INQUIRY_CMDLEN] =
44             { INQUIRY_CMD, 0, 0, 0, 0, 0 };
45         unsigned char sense_b[SENSE_BUFF_LEN];
46         struct sg_io_hdr io_hdr;
47                                                                                                                  
48         if (cmddt)
49                 inqCmdBlk[1] |= 2;
50         if (evpd)
51                 inqCmdBlk[1] |= 1;
52         inqCmdBlk[2] = (unsigned char) pg_op;
53         inqCmdBlk[3] = (unsigned char)((mx_resp_len >> 8) & 0xff);
54         inqCmdBlk[4] = (unsigned char) (mx_resp_len & 0xff);
55         memset(&io_hdr, 0, sizeof (struct sg_io_hdr));
56         io_hdr.interface_id = 'S';
57         io_hdr.cmd_len = sizeof (inqCmdBlk);
58         io_hdr.mx_sb_len = sizeof (sense_b);
59         io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
60         io_hdr.dxfer_len = mx_resp_len;
61         io_hdr.dxferp = resp;
62         io_hdr.cmdp = inqCmdBlk;
63         io_hdr.sbp = sense_b;
64         io_hdr.timeout = DEF_TIMEOUT;
65  
66         if (ioctl(sg_fd, SG_IO, &io_hdr) < 0)
67                 return 1;
68  
69         /* treat SG_ERR here to get rid of sg_err.[ch] */
70         io_hdr.status &= 0x7e;
71         if ((0 == io_hdr.status) && (0 == io_hdr.host_status) &&
72             (0 == io_hdr.driver_status))
73                 return 0;
74         if ((SCSI_CHECK_CONDITION == io_hdr.status) ||
75             (SCSI_COMMAND_TERMINATED == io_hdr.status) ||
76             (SG_ERR_DRIVER_SENSE == (0xf & io_hdr.driver_status))) {
77                 if (io_hdr.sbp && (io_hdr.sb_len_wr > 2)) {
78                         int sense_key;
79                         unsigned char * sense_buffer = io_hdr.sbp;
80                         if (sense_buffer[0] & 0x2)
81                                 sense_key = sense_buffer[1] & 0xf;
82                         else
83                                 sense_key = sense_buffer[2] & 0xf;
84                         if(RECOVERED_ERROR == sense_key)
85                                 return 0;
86                 }
87         }
88         return 1;
89 }
90
91 static int
92 do_tur (int fd)
93 {
94         unsigned char turCmdBlk[TUR_CMD_LEN] = { 0x00, 0, 0, 0, 0, 0 };
95         struct sg_io_hdr io_hdr;
96         unsigned char sense_buffer[32];
97
98         memset(&io_hdr, 0, sizeof (struct sg_io_hdr));
99         io_hdr.interface_id = 'S';
100         io_hdr.cmd_len = sizeof (turCmdBlk);
101         io_hdr.mx_sb_len = sizeof (sense_buffer);
102         io_hdr.dxfer_direction = SG_DXFER_NONE;
103         io_hdr.cmdp = turCmdBlk;
104         io_hdr.sbp = sense_buffer;
105         io_hdr.timeout = 20000;
106         io_hdr.pack_id = 0;
107
108         if (ioctl(fd, SG_IO, &io_hdr) < 0)
109                 return 1;
110
111         if (io_hdr.info & SG_INFO_OK_MASK)
112                 return 1;
113
114         return 0;
115 }
116
117 extern int
118 hp_sw (int fd, char *msg, void **context)
119 {
120         char buff[MX_ALLOC_LEN];
121         struct sw_checker_context * ctxt = NULL;
122         int ret;
123
124         /*
125          * caller passed in a context : use its address
126          */
127         if (context)
128                 ctxt = (struct sw_checker_context *) (*context);
129
130         /*
131          * passed in context is uninitialized or volatile context :
132          * initialize it
133          */
134         if (!ctxt) {
135                 ctxt = malloc(sizeof(struct sw_checker_context));
136                 memset(ctxt, 0, sizeof(struct sw_checker_context));
137
138                 if (!ctxt) {
139                         MSG("cannot allocate context");
140                         return -1;
141                 }
142                 if (context)
143                         *context = ctxt;
144         }
145         ctxt->run_count++;
146
147         if ((ctxt->run_count % HEAVY_CHECK_COUNT) == 0) {
148                 ctxt->run_count = 0;
149                 /* do stuff */
150         }
151         if (fd <= 0) {
152                 MSG("no usable fd");
153                 ret = -1;
154                 goto out;
155         }
156         
157         if (0 != do_inq(fd, 0, 1, 0x80, buff, MX_ALLOC_LEN, 0)) {
158                 MSG(MSG_HP_SW_DOWN);
159                 ret = PATH_DOWN;
160                 goto out;
161         }
162
163         if (do_tur(fd)) {
164                 MSG(MSG_HP_SW_GHOST);
165                 ret = PATH_GHOST;
166         } else {
167                 MSG(MSG_HP_SW_UP);
168                 ret = PATH_UP;
169         }
170
171 out:
172         /*
173          * caller told us he doesn't want to keep the context :
174          * free it
175          */
176         if (!context)
177                 free(ctxt);
178
179         return(ret);
180 }