From: Christophe Varoqui Date: Thu, 23 Nov 2006 23:06:23 +0000 (+0100) Subject: [checkers] handling CLARiiON I/O to inactive snapshot logical units X-Git-Tag: 0.4.8~80 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=3324dcd1908634f9af555f7198caf9cc8ff0c9f6;p=platform%2Fupstream%2Fmultipath-tools.git [checkers] handling CLARiiON I/O to inactive snapshot logical units Prevent an I/O hang which can occur with host I/O to an inactive CLARiiON snapshot logical unit. While the inactive snapshot LU is presented to a host, inquiry, TUR, and read capacity commands succeed, but read and write commands are failed. Complicating the matter is the fact that read/write to the active paths fails with a particular sense code/asc/ascq combination while read/write to the passive paths does not. Edward Goggin, EMC --- diff --git a/libcheckers/checkers.h b/libcheckers/checkers.h index 050644a..5589fc7 100644 --- a/libcheckers/checkers.h +++ b/libcheckers/checkers.h @@ -90,7 +90,7 @@ struct checker { void (*free)(struct checker *); /* to free the context */ }; -#define MSG(c, a) snprintf((c)->message, CHECKER_MSG_LEN, a); +#define MSG(c, fmt, args...) snprintf((c)->message, CHECKER_MSG_LEN, fmt, ##args); int checker_init (struct checker *, void **); void checker_put (struct checker *); diff --git a/libcheckers/emc_clariion.c b/libcheckers/emc_clariion.c index a883e3d..384a943 100644 --- a/libcheckers/emc_clariion.c +++ b/libcheckers/emc_clariion.c @@ -11,25 +11,76 @@ #include #include -#include "checkers.h" - #include "../libmultipath/sg_include.h" +#include "libsg.h" +#include "checkers.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; } @@ -40,13 +91,15 @@ void emc_clariion_free (struct checker * c) 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 wwnstr[33]; + int ret; memset(&io_hdr, 0, sizeof (struct sg_io_hdr)); io_hdr.interface_id = 'S'; @@ -69,7 +122,8 @@ int emc_clariion(struct checker * c) } 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; } @@ -79,19 +133,22 @@ int emc_clariion(struct checker * c) || (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; } @@ -102,7 +159,8 @@ int emc_clariion(struct checker * c) */ 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 { @@ -110,7 +168,59 @@ int emc_clariion(struct checker * c) 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); + + /* + * 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); + MSG(c, "emc_clariion_checker: Active " + "path to inactive snapshot WWN %s.", + wwnstr); + } else + MSG(c, "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]); + } 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); + MSG(c, "emc_clariion_checker: Passive " + "path to inactive snapshot WWN %s.", + wwnstr); + ret = PATH_DOWN; + } else { + MSG(c, + "emc_clariion_checker: Passive path is healthy."); + ret = PATH_UP; /* not ghost */ + } + } + + return ret; }