b50ac0c5f767a07b91eb440d8e16399662f0bbca
[multipath-tools/.git] / libmultipath / checkers / 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 "checkers.h"
15
16 #include "../libmultipath/sg_include.h"
17
18 #define TUR_CMD_LEN             6
19 #define INQUIRY_CMDLEN          6
20 #define INQUIRY_CMD             0x12
21 #define SENSE_BUFF_LEN          32
22 #define SCSI_CHECK_CONDITION    0x2
23 #define SCSI_COMMAND_TERMINATED 0x22
24 #define SG_ERR_DRIVER_SENSE     0x08
25 #define RECOVERED_ERROR         0x01
26 #define MX_ALLOC_LEN            255
27 #define HEAVY_CHECK_COUNT       10
28
29 #define MSG_HP_SW_UP    "hp_sw checker reports path is up"
30 #define MSG_HP_SW_DOWN  "hp_sw checker reports path is down"
31 #define MSG_HP_SW_GHOST "hp_sw checker reports path is ghost"
32
33 struct sw_checker_context {
34         void * dummy;
35 };
36
37 int libcheck_init (struct checker * c)
38 {
39         return 0;
40 }
41
42 void libcheck_free (struct checker * c)
43 {
44         return;
45 }
46
47 static int
48 do_inq(int sg_fd, int cmddt, int evpd, unsigned int pg_op,
49        void *resp, int mx_resp_len, int noisy, unsigned int timeout)
50 {
51         unsigned char inqCmdBlk[INQUIRY_CMDLEN] =
52                 { INQUIRY_CMD, 0, 0, 0, 0, 0 };
53         unsigned char sense_b[SENSE_BUFF_LEN];
54         struct sg_io_hdr io_hdr;
55
56         if (cmddt)
57                 inqCmdBlk[1] |= 2;
58         if (evpd)
59                 inqCmdBlk[1] |= 1;
60         inqCmdBlk[2] = (unsigned char) pg_op;
61         inqCmdBlk[3] = (unsigned char)((mx_resp_len >> 8) & 0xff);
62         inqCmdBlk[4] = (unsigned char) (mx_resp_len & 0xff);
63         memset(&io_hdr, 0, sizeof (struct sg_io_hdr));
64         memset(sense_b, 0, SENSE_BUFF_LEN);
65         io_hdr.interface_id = 'S';
66         io_hdr.cmd_len = sizeof (inqCmdBlk);
67         io_hdr.mx_sb_len = sizeof (sense_b);
68         io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
69         io_hdr.dxfer_len = mx_resp_len;
70         io_hdr.dxferp = resp;
71         io_hdr.cmdp = inqCmdBlk;
72         io_hdr.sbp = sense_b;
73         io_hdr.timeout = timeout;
74
75         if (ioctl(sg_fd, SG_IO, &io_hdr) < 0)
76                 return 1;
77
78         /* treat SG_ERR here to get rid of sg_err.[ch] */
79         io_hdr.status &= 0x7e;
80         if ((0 == io_hdr.status) && (0 == io_hdr.host_status) &&
81             (0 == io_hdr.driver_status))
82                 return 0;
83         if ((SCSI_CHECK_CONDITION == io_hdr.status) ||
84             (SCSI_COMMAND_TERMINATED == io_hdr.status) ||
85             (SG_ERR_DRIVER_SENSE == (0xf & io_hdr.driver_status))) {
86                 if (io_hdr.sbp && (io_hdr.sb_len_wr > 2)) {
87                         int sense_key;
88                         unsigned char * sense_buffer = io_hdr.sbp;
89                         if (sense_buffer[0] & 0x2)
90                                 sense_key = sense_buffer[1] & 0xf;
91                         else
92                                 sense_key = sense_buffer[2] & 0xf;
93                         if(RECOVERED_ERROR == sense_key)
94                                 return 0;
95                 }
96         }
97         return 1;
98 }
99
100 static int
101 do_tur (int fd, unsigned int timeout)
102 {
103         unsigned char turCmdBlk[TUR_CMD_LEN] = { 0x00, 0, 0, 0, 0, 0 };
104         struct sg_io_hdr io_hdr;
105         unsigned char sense_buffer[32];
106
107         memset(&io_hdr, 0, sizeof (struct sg_io_hdr));
108         io_hdr.interface_id = 'S';
109         io_hdr.cmd_len = sizeof (turCmdBlk);
110         io_hdr.mx_sb_len = sizeof (sense_buffer);
111         io_hdr.dxfer_direction = SG_DXFER_NONE;
112         io_hdr.cmdp = turCmdBlk;
113         io_hdr.sbp = sense_buffer;
114         io_hdr.timeout = timeout;
115         io_hdr.pack_id = 0;
116
117         if (ioctl(fd, SG_IO, &io_hdr) < 0)
118                 return 1;
119
120         if (io_hdr.info & SG_INFO_OK_MASK)
121                 return 1;
122
123         return 0;
124 }
125
126 extern int
127 libcheck_check (struct checker * c)
128 {
129         char buff[MX_ALLOC_LEN];
130
131         if (0 != do_inq(c->fd, 0, 1, 0x80, buff, MX_ALLOC_LEN, 0, c->timeout)) {
132                 MSG(c, MSG_HP_SW_DOWN);
133                 return PATH_DOWN;
134         }
135
136         if (do_tur(c->fd, c->timeout)) {
137                 MSG(c, MSG_HP_SW_GHOST);
138                 return PATH_GHOST;
139         }
140         MSG(c, MSG_HP_SW_UP);
141         return PATH_UP;
142 }