Imported Upstream version 0.8.9
[platform/upstream/multipath-tools.git] / libmultipath / prioritizers / alua_spc3.h
1 /*
2  * (C) Copyright IBM Corp. 2004, 2005   All Rights Reserved.
3  *
4  * spc3.h
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 #ifndef __SPC3_H__
16 #define __SPC3_H__
17 #include "../unaligned.h"
18
19 /*=============================================================================
20  * Definitions to support the standard inquiry command as defined in SPC-3.
21  * If the evpd (enable vital product data) bit is set the data that will be
22  * returned is selected by the page field. This field must be 0 if the evpd
23  * bit is not set.
24  *=============================================================================
25  */
26 #define OPERATION_CODE_INQUIRY          0x12
27
28 struct inquiry_command {
29         unsigned char   op;
30         unsigned char   b1;             /* xxxxxx.. = reserved               */
31                                         /* ......x. = obsolete               */
32                                         /* .......x = evpd                   */
33         unsigned char   page;
34         unsigned char   length[2];
35         unsigned char   control;
36 } __attribute__((packed));
37
38 static inline void
39 inquiry_command_set_evpd(struct inquiry_command *ic)
40 {
41         ic->b1 |= 1;
42 }
43
44 /*-----------------------------------------------------------------------------
45  * Data returned by the standard inquiry command.
46  *-----------------------------------------------------------------------------
47  *
48  * Peripheral qualifier codes.
49  */
50 #define PQ_CONNECTED                                    0x0
51 #define PQ_DISCONNECTED                                 0x1
52 #define PQ_UNSUPPORTED                                  0x3
53
54 /* Defined peripheral device types. */
55 #define PDT_DIRECT_ACCESS                               0x00
56 #define PDT_SEQUENTIAL_ACCESS                           0x01
57 #define PDT_PRINTER                                     0x02
58 #define PDT_PROCESSOR                                   0x03
59 #define PDT_WRITE_ONCE                                  0x04
60 #define PDT_CD_DVD                                      0x05
61 #define PDT_SCANNER                                     0x06
62 #define PDT_OPTICAL_MEMORY                              0x07
63 #define PDT_MEDIUM_CHANGER                              0x08
64 #define PDT_COMMUNICATIONS                              0x09
65 #define PDT_STORAGE_ARRAY_CONTROLLER                    0x0c
66 #define PDT_ENCLOSURE_SERVICES                          0x0d
67 #define PDT_SIMPLIFIED_DIRECT_ACCESS                    0x0e
68 #define PDT_OPTICAL_CARD_READER_WRITER                  0x0f
69 #define PDT_BRIDGE_CONTROLLER                           0x10
70 #define PDT_OBJECT_BASED                                0x11
71 #define PDT_AUTOMATION_INTERFACE                        0x12
72 #define PDT_LUN                                         0x1e
73 #define PDT_UNKNOWN                                     0x1f
74
75 /* Defined version codes. */
76 #define VERSION_NONE                                    0x00
77 #define VERSION_SPC                                     0x03
78 #define VERSION_SPC2                                    0x04
79 #define VERSION_SPC3                                    0x05
80
81 /* Defined TPGS field values. */
82 #define TPGS_UNDEF                                       -1
83 #define TPGS_NONE                                       0x0
84 #define TPGS_IMPLICIT                                   0x1
85 #define TPGS_EXPLICIT                                   0x2
86 #define TPGS_BOTH                                       0x3
87
88 struct inquiry_data {
89         unsigned char   b0;             /* xxx..... = peripheral_qualifier   */
90                                         /* ...xxxxx = peripheral_device_type */
91         unsigned char   b1;             /* x....... = removable medium       */
92                                         /* .xxxxxxx = reserved              */
93         unsigned char   version;
94         unsigned char   b3;             /* xx...... = obsolete               */
95                                         /* ..x..... = normal aca supported   */
96                                         /* ...x.... = hirarchichal lun supp. */
97                                         /* ....xxxx = response format        */
98                                         /*            2 is spc-3 format      */
99         unsigned char   length;
100         unsigned char   b5;             /* x....... = storage controller     */
101                                         /*            component supported    */
102                                         /* .x...... = access controls coord. */
103                                         /* ..xx.... = target port group supp.*/
104                                         /* ....x... = third party copy supp. */
105                                         /* .....xx. = reserved               */
106                                         /* .......x = protection info supp.  */
107         unsigned char   b6;             /* x....... = bque                   */
108                                         /* .x...... = enclosure services sup.*/
109                                         /* ..x..... = vs1                    */
110                                         /* ...x.... = multiport support      */
111                                         /* ....x... = medium changer         */
112                                         /* .....xx. = obsolete               */
113                                         /* .......x = add16                  */
114         unsigned char   b7;             /* xx...... = obsolete               */
115                                         /* ..x..... = wbus16                 */
116                                         /* ...x.... = sync                   */
117                                         /* ....x... = linked commands supp.  */
118                                         /* .....x.. = obsolete               */
119                                         /* ......x. = command queue support  */
120                                         /* .......x = vs2                    */
121         unsigned char   vendor_identification[8];
122         unsigned char   product_identification[16];
123         unsigned char   product_revision[4];
124         unsigned char   vendor_specific[20];
125         unsigned char   b56;            /* xxxx.... = reserved               */
126                                         /* ....xx.. = clocking               */
127                                         /* ......x. = qas                    */
128                                         /* .......x = ius                    */
129         unsigned char   reserved4;
130         unsigned char   version_descriptor[8][2];
131         unsigned char   reserved5[22];
132         unsigned char   vendor_parameters[0];
133 } __attribute__((packed));
134
135 static inline int
136 inquiry_data_get_tpgs(struct inquiry_data *id)
137 {
138         return (id->b5 >> 4) & 3;
139 }
140
141 /*-----------------------------------------------------------------------------
142  * Inquiry data returned when requesting vital product data page 0x83.
143  *-----------------------------------------------------------------------------
144  */
145 #define CODESET_BINARY                  0x1
146 #define CODESET_ACSII                   0x2
147 #define CODESET_UTF8                    0x3
148
149 #define ASSOCIATION_UNIT                0x0
150 #define ASSOCIATION_PORT                0x1
151 #define ASSOCIATION_DEVICE              0x2
152
153 #define IDTYPE_VENDOR_SPECIFIC          0x0
154 #define IDTYPE_T10_VENDOR_ID            0x1
155 #define IDTYPE_EUI64                    0x2
156 #define IDTYPE_NAA                      0x3
157 #define IDTYPE_RELATIVE_TPG_ID          0x4
158 #define IDTYPE_TARGET_PORT_GROUP        0x5
159 #define IDTYPE_LUN_GROUP                0x6
160 #define IDTYPE_MD5_LUN_ID               0x7
161 #define IDTYPE_SCSI_NAME_STRING         0x8
162
163 struct vpd83_tpg_dscr {
164         unsigned char           reserved1[2];
165         unsigned char           tpg[2];
166 } __attribute__((packed));
167
168 struct vpd83_dscr {
169         unsigned char           b0;     /* xxxx.... = protocol id            */
170                                         /* ....xxxx = codeset                */
171         unsigned char           b1;     /* x....... = protocol id valid      */
172                                         /* .x...... = reserved               */
173                                         /* ..xx.... = association            */
174                                         /* ....xxxx = id type                */
175         unsigned char           reserved2;
176         unsigned char           length;                         /* size-4    */
177         unsigned char           data[0];
178 } __attribute__((packed));
179
180 static inline int
181 vpd83_dscr_istype(const struct vpd83_dscr *d, unsigned char type)
182 {
183         return ((d->b1 & 7) == type);
184 }
185
186 struct vpd83_data {
187         unsigned char           b0;     /* xxx..... = peripheral_qualifier   */
188                                         /* ...xxxxx = peripheral_device_type */
189         unsigned char           page_code;                      /* 0x83      */
190         unsigned char           length[2];                      /* size-4    */
191         struct vpd83_dscr       data[0];
192 } __attribute__((packed));
193
194 #define VPD_BUFLEN 4096
195
196 /* Returns the max byte offset in the VPD page from the start of the page */
197 static inline unsigned int vpd83_max_offs(const struct vpd83_data *p)
198 {
199         uint16_t len = get_unaligned_be16(p->length) + 4;
200
201         return len <= VPD_BUFLEN ? len : VPD_BUFLEN;
202 }
203
204 static inline bool
205 vpd83_descr_fits(const struct vpd83_dscr *d, const struct vpd83_data *p)
206 {
207         ptrdiff_t max_offs = vpd83_max_offs(p);
208         ptrdiff_t offs = ((const char *)d - (const char *)p);
209
210         /* make sure we can read d->length */
211         if (offs < 0 || offs > max_offs - 4)
212                 return false;
213
214         offs += d->length + 4;
215         return offs <= max_offs;
216 }
217
218 static inline const struct vpd83_dscr *
219 vpd83_next_dscr(const struct vpd83_dscr *d, const struct vpd83_data *p)
220 {
221         ptrdiff_t offs = ((const char *)d - (const char *)p) + d->length + 4;
222
223         return (const struct vpd83_dscr *)((const char *)p + offs);
224 }
225
226 /*-----------------------------------------------------------------------------
227  * This macro should be used to walk through all identification descriptors
228  * defined in the code page 0x83.
229  * The argument p is a pointer to the code page 0x83 data and d is used to
230  * point to the current descriptor.
231  *-----------------------------------------------------------------------------
232  */
233 #define FOR_EACH_VPD83_DSCR(p, d) \
234                 for( \
235                         d = p->data;              \
236                         vpd83_descr_fits(d, p);   \
237                         d = vpd83_next_dscr(d, p) \
238                 )
239
240 /*=============================================================================
241  * The following structures and macros are used to call the report target port
242  * groups command defined in SPC-3.
243  * This command is used to get information about the target port groups (which
244  * states are supported, which ports belong to this group, and so on) and the
245  * current state of each target port group.
246  *=============================================================================
247  */
248 #define OPERATION_CODE_RTPG             0xa3
249 #define SERVICE_ACTION_RTPG             0x0a
250
251 struct rtpg_command {
252         unsigned char           op;     /* 0xa3                              */
253         unsigned char           b1;     /* xxx..... = reserved               */
254                                         /* ...xxxxx = service action (0x0a)  */
255         unsigned char                   reserved2[4];
256         unsigned char                   length[4];
257         unsigned char                   reserved3;
258         unsigned char                   control;
259 } __attribute__((packed));
260
261 static inline void
262 rtpg_command_set_service_action(struct rtpg_command *cmd)
263 {
264         cmd->b1 = (cmd->b1 & 0xe0) | SERVICE_ACTION_RTPG;
265 }
266
267 struct rtpg_tp_dscr {
268         unsigned char                   obsolete1[2];
269         /* The Relative Target Port Identifier of a target port. */
270         unsigned char                   rtpi[2];
271 } __attribute__((packed));
272
273 #define AAS_OPTIMIZED                   0x0
274 #define AAS_NON_OPTIMIZED               0x1
275 #define AAS_STANDBY                     0x2
276 #define AAS_UNAVAILABLE                 0x3
277 #define AAS_LBA_DEPENDENT               0x4
278 #define AAS_RESERVED                    0x5
279 #define AAS_OFFLINE                     0xe
280 #define AAS_TRANSITIONING               0xf
281
282 #define TPG_STATUS_NONE                 0x0
283 #define TPG_STATUS_SET                  0x1
284 #define TPG_STATUS_IMPLICIT_CHANGE      0x2
285
286 struct rtpg_tpg_dscr {
287         unsigned char   b0;             /* x....... = pref(ered) port        */
288                                         /* .xxx.... = reserved               */
289                                         /* ....xxxx = asymmetric access state*/
290         unsigned char   b1;             /* xxx..... = reserved               */
291                                         /* ...x.... = LBA dependent support  */
292                                         /* ....x... = unavailable support    */
293                                         /* .....x.. = standby support        */
294                                         /* ......x. = non-optimized support  */
295                                         /* .......x = optimized support      */
296         unsigned char                   tpg[2];
297         unsigned char                   reserved3;
298         unsigned char                   status;
299         unsigned char                   vendor_unique;
300         unsigned char                   port_count;
301         struct rtpg_tp_dscr             data[0];
302 } __attribute__((packed));
303
304 static inline int
305 rtpg_tpg_dscr_get_aas(struct rtpg_tpg_dscr *d)
306 {
307         return (d->b0 & 0x8f);
308 }
309
310 struct rtpg_data {
311         unsigned char                   length[4];              /* size-4 */
312         struct rtpg_tpg_dscr            data[0];
313 } __attribute__((packed));
314
315 #define RTPG_FOR_EACH_PORT_GROUP(p, g) \
316                 for( \
317                         g = &(p->data[0]); \
318                         ((char *) g) < ((char *) p) + get_unaligned_be32(p->length); \
319                         g = (struct rtpg_tpg_dscr *) ( \
320                                 ((char *) g) + \
321                                 sizeof(struct rtpg_tpg_dscr) + \
322                                 g->port_count * sizeof(struct rtpg_tp_dscr) \
323                         ) \
324                 )
325
326 #endif /* __SPC3_H__ */