6650a20c28a5ffd68c6d86cef5d95af4d79d754e
[multipath-tools/.git] / libmultipath / prioritizers / alua.c
1 /*
2  * (C) Copyright IBM Corp. 2004, 2005   All Rights Reserved.
3  *
4  * main.c
5  *
6  * Tool to make use of a SCSI-feature called Asymmetric Logical Unit Access.
7  * It determines the ALUA state of a device and prints a priority value to
8  * stdout.
9  *
10  * Author(s): Jan Kunigk
11  *            S. Bader <shbader@de.ibm.com>
12  *
13  * This file is released under the GPL.
14  */
15 #include <stdio.h>
16
17 #include <debug.h>
18 #include <prio.h>
19 #include <structs.h>
20
21 #include "alua.h"
22
23 #define ALUA_PRIO_NOT_SUPPORTED                 1
24 #define ALUA_PRIO_RTPG_FAILED                   2
25 #define ALUA_PRIO_GETAAS_FAILED                 3
26 #define ALUA_PRIO_TPGS_FAILED                   4
27 #define ALUA_PRIO_NO_INFORMATION                5
28
29 static const char * aas_string[] = {
30         [AAS_OPTIMIZED]         = "active/optimized",
31         [AAS_NON_OPTIMIZED]     = "active/non-optimized",
32         [AAS_STANDBY]           = "standby",
33         [AAS_UNAVAILABLE]       = "unavailable",
34         [AAS_LBA_DEPENDENT]     = "lba dependent",
35         [AAS_RESERVED]          = "invalid/reserved",
36         [AAS_OFFLINE]           = "offline",
37         [AAS_TRANSITIONING]     = "transitioning between states",
38 };
39
40 static const char *aas_print_string(int rc)
41 {
42         rc &= 0x7f;
43
44         if (rc & 0x70)
45                 return aas_string[AAS_RESERVED];
46         rc &= 0x0f;
47         if (rc > AAS_RESERVED && rc < AAS_OFFLINE)
48                 return aas_string[AAS_RESERVED];
49         else
50                 return aas_string[rc];
51 }
52
53 int
54 get_alua_info(struct path * pp, unsigned int timeout)
55 {
56         int     rc;
57         int     tpg;
58
59         tpg = get_target_port_group(pp, timeout);
60         if (tpg < 0) {
61                 rc = get_target_port_group_support(pp->fd, timeout);
62                 if (rc < 0)
63                         return -ALUA_PRIO_TPGS_FAILED;
64                 if (rc == TPGS_NONE)
65                         return -ALUA_PRIO_NOT_SUPPORTED;
66                 return -ALUA_PRIO_RTPG_FAILED;
67         }
68         condlog(3, "reported target port group is %i", tpg);
69         rc = get_asymmetric_access_state(pp->fd, tpg, timeout);
70         if (rc < 0)
71                 return -ALUA_PRIO_GETAAS_FAILED;
72
73         condlog(3, "aas = %02x [%s]%s", rc, aas_print_string(rc),
74                 (rc & 0x80) ? " [preferred]" : "");
75         return rc;
76 }
77
78 int get_exclusive_pref_arg(char *args)
79 {
80         char *ptr;
81
82         if (args == NULL)
83                 return 0;
84         ptr = strstr(args, "exclusive_pref_bit");
85         if (!ptr)
86                 return 0;
87         if (ptr[18] != '\0' && ptr[18] != ' ' && ptr[18] != '\t')
88                 return 0;
89         if (ptr != args && ptr[-1] != ' ' && ptr[-1] != '\t')
90                 return 0;
91         return 1;
92 }
93
94 int getprio (struct path * pp, char * args, unsigned int timeout)
95 {
96         int rc;
97         int aas;
98         int priopath;
99         int exclusive_pref;
100
101         if (pp->fd < 0)
102                 return -ALUA_PRIO_NO_INFORMATION;
103
104         exclusive_pref = get_exclusive_pref_arg(args);
105         rc = get_alua_info(pp, timeout);
106         if (rc >= 0) {
107                 aas = (rc & 0x0f);
108                 priopath = (rc & 0x80);
109                 switch(aas) {
110                         case AAS_OPTIMIZED:
111                                 rc = 50;
112                                 break;
113                         case AAS_NON_OPTIMIZED:
114                                 rc = 10;
115                                 break;
116                         case AAS_LBA_DEPENDENT:
117                                 rc = 5;
118                                 break;
119                         case AAS_STANDBY:
120                                 rc = 1;
121                                 break;
122                         default:
123                                 rc = 0;
124                 }
125                 if (priopath && (aas != AAS_OPTIMIZED || exclusive_pref))
126                         rc += 80;
127         } else {
128                 switch(-rc) {
129                         case ALUA_PRIO_NOT_SUPPORTED:
130                                 condlog(0, "%s: alua not supported", pp->dev);
131                                 break;
132                         case ALUA_PRIO_RTPG_FAILED:
133                                 condlog(0, "%s: couldn't get target port group", pp->dev);
134                                 break;
135                         case ALUA_PRIO_GETAAS_FAILED:
136                                 condlog(0, "%s: couldn't get asymmetric access state", pp->dev);
137                                 break;
138                         case ALUA_PRIO_TPGS_FAILED:
139                                 condlog(3, "%s: couldn't get supported alua states", pp->dev);
140                                 break;
141                 }
142         }
143         return rc;
144 }