9fbb1ff484410ce90a87bed89c604247083e730c
[multipath-tools/.git] / libmultipath / prioritizers / hp_sw.c
1 /*
2  * Path priority checker for HP active/standby controller
3  *
4  * Check the path state and sort them into groups.
5  * There is actually a preferred path in the controller;
6  * we should ask HP on how to retrieve that information.
7  */
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <unistd.h>
12 #include <sys/ioctl.h>
13 #include <errno.h>
14
15 #include <sg_include.h>
16 #include <debug.h>
17 #include <prio.h>
18 #include <structs.h>
19
20 #define TUR_CMD_LEN             6
21 #define SCSI_CHECK_CONDITION    0x2
22 #define SCSI_COMMAND_TERMINATED 0x22
23 #define SG_ERR_DRIVER_SENSE     0x08
24 #define RECOVERED_ERROR         0x01
25 #define NOT_READY               0x02
26 #define UNIT_ATTENTION          0x06
27
28 #define HP_PATH_ACTIVE          0x04
29 #define HP_PATH_STANDBY         0x02
30 #define HP_PATH_FAILED          0x00
31
32 #define pp_hp_sw_log(prio, fmt, args...) \
33         condlog(prio, "%s: hp_sw prio: " fmt, dev, ##args)
34
35 int hp_sw_prio(const char *dev, int fd, unsigned int timeout)
36 {
37         unsigned char turCmdBlk[TUR_CMD_LEN] = { 0x00, 0, 0, 0, 0, 0 };
38         unsigned char sb[128];
39         struct sg_io_hdr io_hdr;
40         int ret = HP_PATH_FAILED;
41
42         memset(&io_hdr, 0, sizeof (struct sg_io_hdr));
43         io_hdr.interface_id = 'S';
44         io_hdr.cmd_len = sizeof (turCmdBlk);
45         io_hdr.mx_sb_len = sizeof (sb);
46         io_hdr.dxfer_direction = SG_DXFER_NONE;
47         io_hdr.cmdp = turCmdBlk;
48         io_hdr.sbp = sb;
49         io_hdr.timeout = get_prio_timeout(timeout, 60000);
50         io_hdr.pack_id = 0;
51  retry:
52         if (ioctl(fd, SG_IO, &io_hdr) < 0) {
53                 pp_hp_sw_log(0, "sending tur command failed");
54                 goto out;
55         }
56         io_hdr.status &= 0x7e;
57         if ((0 == io_hdr.status) && (0 == io_hdr.host_status) &&
58             (0 == io_hdr.driver_status)) {
59                 /* Command completed normally, path is active */
60                 ret = HP_PATH_ACTIVE;
61         }
62
63         if ((SCSI_CHECK_CONDITION == io_hdr.status) ||
64             (SCSI_COMMAND_TERMINATED == io_hdr.status) ||
65             (SG_ERR_DRIVER_SENSE == (0xf & io_hdr.driver_status))) {
66                 if (io_hdr.sbp && (io_hdr.sb_len_wr > 2)) {
67                         int sense_key, asc, asq;
68                         unsigned char * sense_buffer = io_hdr.sbp;
69                         if (sense_buffer[0] & 0x2) {
70                                 sense_key = sense_buffer[1] & 0xf;
71                                 asc = sense_buffer[2];
72                                 asq = sense_buffer[3];
73                         } else {
74                                 sense_key = sense_buffer[2] & 0xf;
75                                 asc = sense_buffer[12];
76                                 asq = sense_buffer[13];
77                         }
78                         if(RECOVERED_ERROR == sense_key)
79                                 ret = HP_PATH_ACTIVE;
80                         if(NOT_READY == sense_key) {
81                                 if (asc == 0x04 && asq == 0x02) {
82                                         /* This is a standby path */
83                                         ret = HP_PATH_STANDBY;
84                                 }
85                         }
86                         if(UNIT_ATTENTION == sense_key) {
87                                 if (asc == 0x29) {
88                                         /* Retry for device reset */
89                                         goto retry;
90                                 }
91                         }
92                 }
93         }
94 out:
95         return(ret);
96 }
97
98 int getprio (struct path * pp, char * args, unsigned int timeout)
99 {
100         return hp_sw_prio(pp->dev, pp->fd, timeout);
101 }