alua: Handle LBA_DEPENDENT state
[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
19 #define TUR_CMD_LEN             6
20 #define SCSI_CHECK_CONDITION    0x2
21 #define SCSI_COMMAND_TERMINATED 0x22
22 #define SG_ERR_DRIVER_SENSE     0x08
23 #define RECOVERED_ERROR         0x01
24 #define NOT_READY               0x02
25 #define UNIT_ATTENTION          0x06
26
27 #define HP_PATH_ACTIVE          0x04
28 #define HP_PATH_STANDBY         0x02
29 #define HP_PATH_FAILED          0x00
30
31 #define pp_hp_sw_log(prio, fmt, args...) \
32         condlog(prio, "%s: hp_sw prio: " fmt, dev, ##args)
33
34 int hp_sw_prio(const char *dev, int fd)
35 {
36         unsigned char turCmdBlk[TUR_CMD_LEN] = { 0x00, 0, 0, 0, 0, 0 };
37         unsigned char sb[128];
38         struct sg_io_hdr io_hdr;
39         int ret = HP_PATH_FAILED;
40
41         memset(&io_hdr, 0, sizeof (struct sg_io_hdr));
42         io_hdr.interface_id = 'S';
43         io_hdr.cmd_len = sizeof (turCmdBlk);
44         io_hdr.mx_sb_len = sizeof (sb);
45         io_hdr.dxfer_direction = SG_DXFER_NONE;
46         io_hdr.cmdp = turCmdBlk;
47         io_hdr.sbp = sb;
48         io_hdr.timeout = 60000;
49         io_hdr.pack_id = 0;
50  retry:
51         if (ioctl(fd, SG_IO, &io_hdr) < 0) {
52                 pp_hp_sw_log(0, "sending tur command failed");
53                 goto out;
54         }
55         io_hdr.status &= 0x7e;
56         if ((0 == io_hdr.status) && (0 == io_hdr.host_status) &&
57             (0 == io_hdr.driver_status)) {
58                 /* Command completed normally, path is active */
59                 ret = HP_PATH_ACTIVE;
60         }
61
62         if ((SCSI_CHECK_CONDITION == io_hdr.status) ||
63             (SCSI_COMMAND_TERMINATED == io_hdr.status) ||
64             (SG_ERR_DRIVER_SENSE == (0xf & io_hdr.driver_status))) {
65                 if (io_hdr.sbp && (io_hdr.sb_len_wr > 2)) {
66                         int sense_key, asc, asq;
67                         unsigned char * sense_buffer = io_hdr.sbp;
68                         if (sense_buffer[0] & 0x2) {
69                                 sense_key = sense_buffer[1] & 0xf;
70                                 asc = sense_buffer[2];
71                                 asq = sense_buffer[3];
72                         } else {
73                                 sense_key = sense_buffer[2] & 0xf;
74                                 asc = sense_buffer[12];
75                                 asq = sense_buffer[13];
76                         }
77                         if(RECOVERED_ERROR == sense_key)
78                                 ret = HP_PATH_ACTIVE;
79                         if(NOT_READY == sense_key) {
80                                 if (asc == 0x04 && asq == 0x02) {
81                                         /* This is a standby path */
82                                         ret = HP_PATH_STANDBY;
83                                 }
84                         }
85                         if(UNIT_ATTENTION == sense_key) {
86                                 if (asc == 0x29) {
87                                         /* Retry for device reset */
88                                         goto retry;
89                                 }
90                         }
91                 }
92         }
93 out:
94         return(ret);
95 }
96
97 int getprio (struct path * pp, char * args)
98 {
99         return hp_sw_prio(pp->dev, pp->fd);
100 }