--- emc_clariion.c.orig 2006-11-19 18:30:32.000000000 -0600 +++ emc_clariion.c 2006-11-20 23:36:45.000000000 -0600 @@ -10,45 +10,101 @@ #include #include #include #include "checkers.h" +#include "readsector0.h" #include "../libmultipath/sg_include.h" +#include "../libmultipath/vector.h" +#include "../libmultipath/debug.h" #define INQUIRY_CMD 0x12 #define INQUIRY_CMDLEN 6 #define HEAVY_CHECK_COUNT 10 -struct emc_clariion_checker_context { +/* + * Mechanism to track CLARiiON inactive snapshot LUs. + * This is done so that we can fail passive paths + * to an inactive snapshot LU even though since a + * simple read test would return 02/04/03 instead + * of 05/25/01 sensekey/ASC/ASCQ data. + */ +#define IS_INACTIVE_SNAP(c) (c->mpcontext ? \ + ((struct emc_clariion_checker_LU_context *) \ + (*c->mpcontext))->inactive_snap \ + : 0) + +#define SET_INACTIVE_SNAP(c) if (c->mpcontext) \ + ((struct emc_clariion_checker_LU_context *)\ + (*c->mpcontext))->inactive_snap = 1 + +#define CLR_INACTIVE_SNAP(c) if (c->mpcontext) \ + ((struct emc_clariion_checker_LU_context *)\ + (*c->mpcontext))->inactive_snap = 0 + +struct emc_clariion_checker_path_context { char wwn[16]; unsigned wwn_set; }; +struct emc_clariion_checker_LU_context { + int inactive_snap; +}; + +extern void +hexadecimal_to_ascii(char * wwn, char *wwnstr) +{ + int i,j, nbl; + + for (i=0,j=0;i<16;i++) { + wwnstr[j++] = ((nbl = ((wwn[i]&0xf0) >> 4)) <= 9) ? + '0' + nbl : 'a' + (nbl - 10); + wwnstr[j++] = ((nbl = (wwn[i]&0x0f)) <= 9) ? + '0' + nbl : 'a' + (nbl - 10); + } + wwnstr[32]=0; +} + int emc_clariion_init (struct checker * c) { - c->context = malloc(sizeof(struct emc_clariion_checker_context)); + /* + * Allocate and initialize the path specific context. + */ + c->context = malloc(sizeof(struct emc_clariion_checker_path_context)); if (!c->context) return 1; - ((struct emc_clariion_checker_context *)c->context)->wwn_set = 0; + ((struct emc_clariion_checker_path_context *)c->context)->wwn_set = 0; + + /* + * Allocate and initialize the multi-path global context. + */ + if (c->mpcontext) { + void * mpctxt = malloc(sizeof(int)); + *c->mpcontext = mpctxt; + CLR_INACTIVE_SNAP(c); + } + return 0; } void emc_clariion_free (struct checker * c) { free(c->context); } int emc_clariion(struct checker * c) { - unsigned char sense_buffer[256] = { 0, }; - unsigned char sb[128] = { 0, }; + unsigned char sense_buffer[128] = { 0, }; + unsigned char sb[SENSE_BUFF_LEN] = { 0, }, *sbb; unsigned char inqCmdBlk[INQUIRY_CMDLEN] = {INQUIRY_CMD, 1, 0xC0, 0, - sizeof(sb), 0}; + sizeof(sense_buffer), 0}; struct sg_io_hdr io_hdr; - struct emc_clariion_checker_context * ct = - (struct emc_clariion_checker_context *)c->context; + struct emc_clariion_checker_path_context * ct = + (struct emc_clariion_checker_path_context *)c->context; + char str[256], wwnstr[33]; + int ret; memset(&io_hdr, 0, sizeof (struct sg_io_hdr)); io_hdr.interface_id = 'S'; io_hdr.cmd_len = sizeof (inqCmdBlk); io_hdr.mx_sb_len = sizeof (sb); @@ -67,50 +123,113 @@ MSG(c, "emc_clariion_checker: query command indicates error"); return PATH_DOWN; } if (/* Verify the code page - right page & revision */ sense_buffer[1] != 0xc0 || sense_buffer[9] != 0x00) { - MSG(c, "emc_clariion_checker: Path unit report page in unknown format"); + MSG(c, "emc_clariion_checker: Path unit report page in " + "unknown format"); return PATH_DOWN; } if ( /* Effective initiator type */ sense_buffer[27] != 0x03 /* Failover mode should be set to 1 */ || (sense_buffer[28] & 0x07) != 0x04 /* Arraycommpath should be set to 1 */ || (sense_buffer[30] & 0x04) != 0x04) { - MSG(c, "emc_clariion_checker: Path not correctly configured for failover"); + MSG(c, "emc_clariion_checker: Path not correctly configured " + "for failover"); return PATH_DOWN; } if ( /* LUN operations should indicate normal operations */ sense_buffer[48] != 0x00) { - MSG(c, "emc_clariion_checker: Path not available for normal operations"); + MSG(c, "emc_clariion_checker: Path not available for normal " + "operations"); return PATH_SHAKY; } if ( /* LUN should at least be bound somewhere and not be LUNZ */ sense_buffer[4] == 0x00) { - MSG(c, "emc_clariion_checker: Logical Unit is unbound or LUNZ"); + MSG(c, "emc_clariion_checker: Logical Unit is unbound " + "or LUNZ"); return PATH_DOWN; } /* * store the LUN WWN there and compare that it indeed did not * change in between, to protect against the path suddenly * pointing somewhere else. */ if (ct->wwn_set) { if (memcmp(ct->wwn, &sense_buffer[10], 16) != 0) { - MSG(c, "emc_clariion_checker: Logical Unit WWN has changed!"); + MSG(c, "emc_clariion_checker: Logical Unit WWN " + "has changed!"); return PATH_DOWN; } } else { memcpy(ct->wwn, &sense_buffer[10], 16); ct->wwn_set = 1; } - - MSG(c, "emc_clariion_checker: Path healthy"); - return PATH_UP; + /* + * Issue read on active path to determine if inactive snapshot. + */ + if (sense_buffer[4] == 2) {/* if active path */ + unsigned char buf[512]; + + ret = sg_read(c->fd, &buf[0], sbb = &sb[0]); + if (ret == PATH_DOWN) { + hexadecimal_to_ascii(ct->wwn, wwnstr); + + condlog(4, "emc_clariion_checker: Read error for " + "WWN %s. Sense data are 0x%x/0x%x/0x%x.", + wwnstr, sbb[2]&0xf, sbb[12], sbb[13]); + + /* + * Check for inactive snapshot LU this way. Must + * fail these. + */ + if (((sbb[2]&0xf) == 5) && (sbb[12] == 0x25) && + (sbb[13]==1)) { + /* + * Do this so that we can fail even the + * passive paths which will return + * 02/04/03 not 05/25/01 on read. + */ + SET_INACTIVE_SNAP(c); + sprintf(str, "emc_clariion_checker: Active " + "path to inactive snapshot WWN %s.", + wwnstr); + } else + sprintf(str, "emc_clariion_checker: Read " + "error for WWN %s. Sense data are " + "0x%x/0x%x/0x%x.", wwnstr, + sbb[2]&0xf, sbb[12], sbb[13]); + MSG(c, str); + } else { + MSG(c, "emc_clariion_checker: Active path is " + "healthy."); + /* + * Remove the path from the set of paths to inactive + * snapshot LUs if it was in this list since the + * snapshot is no longer inactive. + */ + CLR_INACTIVE_SNAP(c); + } + } else { + if (IS_INACTIVE_SNAP(c)) { + hexadecimal_to_ascii(ct->wwn, wwnstr); + sprintf(str, "emc_clariion_checker: Passive " + "path to inactive snapshot WWN %s.", + wwnstr); + MSG(c, str); + ret = PATH_DOWN; + } else { + MSG(c, + "emc_clariion_checker: Passive path is healthy."); + ret = PATH_UP; /* not ghost */ + } + } + + return ret; }