2 * Copyright (c) 2004, 2005 Lars Marowsky-Bree
11 #include <sys/ioctl.h>
15 #include "../libmultipath/sg_include.h"
20 #define INQUIRY_CMD 0x12
21 #define INQUIRY_CMDLEN 6
22 #define HEAVY_CHECK_COUNT 10
25 * Mechanism to track CLARiiON inactive snapshot LUs.
26 * This is done so that we can fail passive paths
27 * to an inactive snapshot LU even though since a
28 * simple read test would return 02/04/03 instead
29 * of 05/25/01 sensekey/ASC/ASCQ data.
31 #define IS_INACTIVE_SNAP(c) (c->mpcontext ? \
32 ((struct emc_clariion_checker_LU_context *) \
33 (*c->mpcontext))->inactive_snap \
36 #define SET_INACTIVE_SNAP(c) if (c->mpcontext) \
37 ((struct emc_clariion_checker_LU_context *)\
38 (*c->mpcontext))->inactive_snap = 1
40 #define CLR_INACTIVE_SNAP(c) if (c->mpcontext) \
41 ((struct emc_clariion_checker_LU_context *)\
42 (*c->mpcontext))->inactive_snap = 0
44 struct emc_clariion_checker_path_context {
49 struct emc_clariion_checker_LU_context {
54 hexadecimal_to_ascii(char * wwn, char *wwnstr)
58 for (i=0,j=0;i<16;i++) {
59 wwnstr[j++] = ((nbl = ((wwn[i]&0xf0) >> 4)) <= 9) ?
60 '0' + nbl : 'a' + (nbl - 10);
61 wwnstr[j++] = ((nbl = (wwn[i]&0x0f)) <= 9) ?
62 '0' + nbl : 'a' + (nbl - 10);
67 int libcheck_init (struct checker * c)
70 * Allocate and initialize the path specific context.
72 c->context = MALLOC(sizeof(struct emc_clariion_checker_path_context));
75 ((struct emc_clariion_checker_path_context *)c->context)->wwn_set = 0;
78 * Allocate and initialize the multi-path global context.
80 if (c->mpcontext && *c->mpcontext == NULL) {
81 void * mpctxt = malloc(sizeof(int));
82 *c->mpcontext = mpctxt;
89 void libcheck_free (struct checker * c)
94 int libcheck_check (struct checker * c)
96 unsigned char sense_buffer[128] = { 0, };
97 unsigned char sb[SENSE_BUFF_LEN] = { 0, }, *sbb;
98 unsigned char inqCmdBlk[INQUIRY_CMDLEN] = {INQUIRY_CMD, 1, 0xC0, 0,
99 sizeof(sense_buffer), 0};
100 struct sg_io_hdr io_hdr;
101 struct emc_clariion_checker_path_context * ct =
102 (struct emc_clariion_checker_path_context *)c->context;
106 memset(&io_hdr, 0, sizeof (struct sg_io_hdr));
107 memset(sense_buffer, 0, 128);
108 memset(sb, 0, SENSE_BUFF_LEN);
109 io_hdr.interface_id = 'S';
110 io_hdr.cmd_len = sizeof (inqCmdBlk);
111 io_hdr.mx_sb_len = sizeof (sb);
112 io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
113 io_hdr.dxfer_len = sizeof (sense_buffer);
114 io_hdr.dxferp = sense_buffer;
115 io_hdr.cmdp = inqCmdBlk;
117 io_hdr.timeout = c->timeout * 1000;
119 if (ioctl(c->fd, SG_IO, &io_hdr) < 0) {
120 MSG(c, "emc_clariion_checker: sending query command failed");
123 if (io_hdr.info & SG_INFO_OK_MASK) {
124 MSG(c, "emc_clariion_checker: query command indicates error");
127 if (/* Verify the code page - right page & revision */
128 sense_buffer[1] != 0xc0 || sense_buffer[9] != 0x00) {
129 MSG(c, "emc_clariion_checker: Path unit report page in "
134 if ( /* Effective initiator type */
135 sense_buffer[27] != 0x03
137 * Failover mode should be set to 1 (PNR failover mode)
138 * or 4 (ALUA failover mode).
140 || (((sense_buffer[28] & 0x07) != 0x04) &&
141 ((sense_buffer[28] & 0x07) != 0x06))
142 /* Arraycommpath should be set to 1 */
143 || (sense_buffer[30] & 0x04) != 0x04) {
144 MSG(c, "emc_clariion_checker: Path not correctly configured "
149 if ( /* LUN operations should indicate normal operations */
150 sense_buffer[48] != 0x00) {
151 MSG(c, "emc_clariion_checker: Path not available for normal "
156 if ( /* LUN should at least be bound somewhere and not be LUNZ */
157 sense_buffer[4] == 0x00) {
158 MSG(c, "emc_clariion_checker: Logical Unit is unbound "
164 * store the LUN WWN there and compare that it indeed did not
165 * change in between, to protect against the path suddenly
166 * pointing somewhere else.
169 if (memcmp(ct->wwn, &sense_buffer[10], 16) != 0) {
170 MSG(c, "emc_clariion_checker: Logical Unit WWN "
175 memcpy(ct->wwn, &sense_buffer[10], 16);
180 * Issue read on active path to determine if inactive snapshot.
182 if (sense_buffer[4] == 2) {/* if active path */
183 unsigned char buf[4096];
185 memset(buf, 0, 4096);
186 ret = sg_read(c->fd, &buf[0], 4096,
187 sbb = &sb[0], SENSE_BUFF_LEN, c->timeout);
188 if (ret == PATH_DOWN) {
189 hexadecimal_to_ascii(ct->wwn, wwnstr);
192 * Check for inactive snapshot LU this way. Must
195 if (((sbb[2]&0xf) == 5) && (sbb[12] == 0x25) &&
198 * Do this so that we can fail even the
199 * passive paths which will return
200 * 02/04/03 not 05/25/01 on read.
202 SET_INACTIVE_SNAP(c);
203 condlog(3, "emc_clariion_checker: Active "
204 "path to inactive snapshot WWN %s.",
207 MSG(c, "emc_clariion_checker: Read "
208 "error for WWN %s. Sense data are "
209 "0x%x/0x%x/0x%x.", wwnstr,
210 sbb[2]&0xf, sbb[12], sbb[13]);
212 MSG(c, "emc_clariion_checker: Active path is "
215 * Remove the path from the set of paths to inactive
216 * snapshot LUs if it was in this list since the
217 * snapshot is no longer inactive.
219 CLR_INACTIVE_SNAP(c);
222 if (IS_INACTIVE_SNAP(c)) {
223 hexadecimal_to_ascii(ct->wwn, wwnstr);
224 condlog(3, "emc_clariion_checker: Passive "
225 "path to inactive snapshot WWN %s.",
230 "emc_clariion_checker: Passive path is healthy.");
231 ret = PATH_UP; /* not ghost */