2 * (C) Copyright IBM Corp. 2004, 2005 All Rights Reserved.
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
10 * Author(s): Jan Kunigk
11 * S. Bader <shbader@de.ibm.com>
13 * This file is released under the GPL.
17 #include "../unaligned.h"
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
24 *=============================================================================
26 #define OPERATION_CODE_INQUIRY 0x12
28 struct inquiry_command {
30 unsigned char b1; /* xxxxxx.. = reserved */
31 /* ......x. = obsolete */
34 unsigned char length[2];
35 unsigned char control;
36 } __attribute__((packed));
39 inquiry_command_set_evpd(struct inquiry_command *ic)
44 /*-----------------------------------------------------------------------------
45 * Data returned by the standard inquiry command.
46 *-----------------------------------------------------------------------------
48 * Peripheral qualifier codes.
50 #define PQ_CONNECTED 0x0
51 #define PQ_DISCONNECTED 0x1
52 #define PQ_UNSUPPORTED 0x3
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
73 #define PDT_UNKNOWN 0x1f
75 /* Defined version codes. */
76 #define VERSION_NONE 0x00
77 #define VERSION_SPC 0x03
78 #define VERSION_SPC2 0x04
79 #define VERSION_SPC3 0x05
81 /* Defined TPGS field values. */
84 #define TPGS_IMPLICIT 0x1
85 #define TPGS_EXPLICIT 0x2
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 */
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.*/
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 */
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 */
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));
136 inquiry_data_get_tpgs(struct inquiry_data *id)
138 return (id->b5 >> 4) & 3;
141 /*-----------------------------------------------------------------------------
142 * Inquiry data returned when requesting vital product data page 0x83.
143 *-----------------------------------------------------------------------------
145 #define CODESET_BINARY 0x1
146 #define CODESET_ACSII 0x2
147 #define CODESET_UTF8 0x3
149 #define ASSOCIATION_UNIT 0x0
150 #define ASSOCIATION_PORT 0x1
151 #define ASSOCIATION_DEVICE 0x2
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
163 struct vpd83_tpg_dscr {
164 unsigned char reserved1[2];
165 unsigned char tpg[2];
166 } __attribute__((packed));
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));
181 vpd83_dscr_istype(const struct vpd83_dscr *d, unsigned char type)
183 return ((d->b1 & 7) == type);
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));
194 #define VPD_BUFLEN 4096
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)
199 uint16_t len = get_unaligned_be16(p->length) + 4;
201 return len <= VPD_BUFLEN ? len : VPD_BUFLEN;
205 vpd83_descr_fits(const struct vpd83_dscr *d, const struct vpd83_data *p)
207 ptrdiff_t max_offs = vpd83_max_offs(p);
208 ptrdiff_t offs = ((const char *)d - (const char *)p);
210 /* make sure we can read d->length */
211 if (offs < 0 || offs > max_offs - 4)
214 offs += d->length + 4;
215 return offs <= max_offs;
218 static inline const struct vpd83_dscr *
219 vpd83_next_dscr(const struct vpd83_dscr *d, const struct vpd83_data *p)
221 ptrdiff_t offs = ((const char *)d - (const char *)p) + d->length + 4;
223 return (const struct vpd83_dscr *)((const char *)p + offs);
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 *-----------------------------------------------------------------------------
233 #define FOR_EACH_VPD83_DSCR(p, d) \
236 vpd83_descr_fits(d, p); \
237 d = vpd83_next_dscr(d, p) \
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 *=============================================================================
248 #define OPERATION_CODE_RTPG 0xa3
249 #define SERVICE_ACTION_RTPG 0x0a
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));
262 rtpg_command_set_service_action(struct rtpg_command *cmd)
264 cmd->b1 = (cmd->b1 & 0xe0) | SERVICE_ACTION_RTPG;
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));
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
282 #define TPG_STATUS_NONE 0x0
283 #define TPG_STATUS_SET 0x1
284 #define TPG_STATUS_IMPLICIT_CHANGE 0x2
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));
305 rtpg_tpg_dscr_get_aas(struct rtpg_tpg_dscr *d)
307 return (d->b0 & 0x8f);
311 unsigned char length[4]; /* size-4 */
312 struct rtpg_tpg_dscr data[0];
313 } __attribute__((packed));
315 #define RTPG_FOR_EACH_PORT_GROUP(p, g) \
318 ((char *) g) < ((char *) p) + get_unaligned_be32(p->length); \
319 g = (struct rtpg_tpg_dscr *) ( \
321 sizeof(struct rtpg_tpg_dscr) + \
322 g->port_count * sizeof(struct rtpg_tp_dscr) \
326 #endif /* __SPC3_H__ */