linux-hotplug.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* Patch to multipath-tools 0.2.4
@ 2004-07-05  9:37 Hannes Reinecke
  2004-07-05 12:11 ` christophe.varoqui
                   ` (8 more replies)
  0 siblings, 9 replies; 10+ messages in thread
From: Hannes Reinecke @ 2004-07-05  9:37 UTC (permalink / raw)
  To: linux-hotplug

[-- Attachment #1: Type: text/plain, Size: 1478 bytes --]

Hi Christophe,

I've made a patch to multipath-tools 0.2.4 to correctly decipher SCSI 
EVPD page 0x83. The current code is totally ignorant of the fact that 
EVPD page 0x83 can return more than one identifier, some of which are 
either bogus (i.e. containing an empty string) or should be preferred to 
the other identifiers.

The attached patch
- correctly deciphers EVPD page 0x83
- Tries to select the 'best' candidate if several IDs are returned:
   - ID should not be empty (i.e. either only spaces or Nulls)
   - Order of preference:
	- NAA (hightest subtype is preferrred)
	- EUI-64
	- T-10
	- Vendor specific
- Map spaces to underscores if the serial number is ASCII; this is 	
   mainly to generate valid mapping names.

Would be great if this patch could be included, as without this the 
multipath tools do not work correctly with the IBM ESS.

Most of the decoding logic is in fact stolen from scsi_id (thanks 
Patrick), so we should probably add a copyright statement somewhere.

We should actually be using the scsi_id package directly as this would 
give us identical mappings for udev and multipath tools. But as this 
would mean a major restructuring of the program itself I took the cheap 
way out. Patrick, can you think of a clever way of integrating both?

Cheers,

Hannes
-- 
Dr. Hannes Reinecke			hare@suse.de
SuSE Linux AG				S390 & zSeries
Maxfeldstraße 5				+49 911 74053 688
90409 Nürnberg				http://www.suse.de

[-- Attachment #2: multipath-page83.patch --]
[-- Type: text/x-patch, Size: 7125 bytes --]

diff -u --recursive multipath-tools-0.2.4/multipath/devinfo.c multipath-tools-0.2.4.patched/multipath/devinfo.c
--- multipath-tools-0.2.4/multipath/devinfo.c	2004-06-04 23:10:06.000000000 +0200
+++ multipath-tools-0.2.4.patched/multipath/devinfo.c	2004-07-05 11:18:52.689351761 +0200
@@ -33,7 +33,8 @@
         if (evpd)
                 inqCmdBlk[1] |= 1;
         inqCmdBlk[2] = (unsigned char) pg_op;
-        inqCmdBlk[4] = (unsigned char) mx_resp_len;
+        inqCmdBlk[3] = (unsigned char)((mx_resp_len >> 8) & 0xff);
+        inqCmdBlk[4] = (unsigned char) (mx_resp_len & 0xff);
         memset(&io_hdr, 0, sizeof (struct sg_io_hdr));
         io_hdr.interface_id = 'S';
         io_hdr.cmd_len = sizeof (inqCmdBlk);
@@ -139,28 +140,231 @@
 	return 0;
 }
 
-static void
-sprint_wwid(char * buff, const char * str)
+/*
+ * Supported Code Set values.
+ */
+#define	CODESET_BINARY	1
+#define	CODESET_ASCII	2
+
+static const char hex_str[]="0123456789abcdef";
+
+/**
+ * check_fill_0x83_id - check the page 0x83 id, if OK allocate and fill
+ * serial number.
+ **/
+static int check_0x83_id(char *scsi_dev, char *page_83, int max_len)
+{
+	int i, j, len, idweight;
+
+	/*
+	 * ASSOCIATION must be with the device (value 0)
+	 */
+#ifdef DEBUG
+	fprintf(stdout,"%s: Association: %X\n", scsi_dev, page_83[1] & 0x30);
+#endif
+	if ((page_83[1] & 0x30) != 0)
+		return -1;
+
+	/*
+	 * Check for code set - ASCII or BINARY.
+	 */
+#ifdef DEBUG
+	fprintf(stdout,"%s: Codeset: %X\n", scsi_dev, page_83[0] & 0x0f);
+#endif
+	if (((page_83[0] & 0x0f) != CODESET_ASCII) &&
+	    ((page_83[0] & 0x0f) != CODESET_BINARY))
+		return -1;
+
+	/*
+	 * Check for ID type
+	 */
+	idweight = page_83[1] & 0x0f;
+#ifdef DEBUG
+	fprintf(stdout,"%s: ID type: ", scsi_dev);
+	switch (page_83[1] & 0x0f) {
+	case 0x0:
+		printf("Vendor specific\n");
+		break;
+	case 0x1:
+		printf("T-10 vendor identification\n");
+		break;
+	case 0x2:
+		printf("EUI-64\n");
+		break;
+	case 0x3:
+		printf("NAA ");
+		switch((page_83[4] >> 4) & 0x0f) {
+		case 0x02:
+			printf("IEEE Extended\n");
+			break;
+		case 0x05:
+			printf("IEEE Registered\n");
+			break;
+		case 0x06:
+			printf("IEEE Registered Extended\n");
+			break;
+		default:
+			printf("Reserved (%X)\n", (page_83[4] >> 4) & 0x0f);
+			break;
+		}
+		break;
+	case 0x4:
+		printf("Relative target port\n");
+		break;
+	case 0x5:
+		printf("Target port group\n");
+		break;
+	case 0x6:
+		printf("Logical unit group\n");
+		break;
+	case 0x7:
+		printf("MD5 logical unit identifier\n");
+		break;
+	default:
+		printf("Reserved\n");
+		break;
+	}
+#endif
+	/*
+	 * Only allow vendor specific, T-10 Vendor Identifcation,
+	 * EUI-64 or NAA identificators
+	 */
+	if ((page_83[1] & 0x0f) > 0x3)
+		return -1;
+
+	/*
+	 * Prefer NAA Registered Extended to NAA Registered and
+	 * NAA Extended.
+	 * Not checking for actual NAA types as some devices
+	 * ( e.g. Compaq iSCSI disks via CISCO routers) return
+	 * add NAA subtypes (0x3).
+	 */
+	if ((page_83[1] & 0x0f) == 0x03) {
+		idweight += (page_83[4] >> 4) & 0x0f;
+	}
+	 
+	/*
+	 * page_83[3]: identifier length
+	 */
+	len = page_83[3];
+	if ((page_83[0] & 0x0f) != CODESET_ASCII)
+		/*
+		 * If not ASCII, use two bytes for each binary value.
+		 */
+		len *= 2;
+
+
+       	/*
+	 * Add one byte for the NUL termination.
+	 */
+	if (max_len < len + 1) {
+		fprintf(stderr, "%s: length %d too short - need %d\n",
+			scsi_dev, max_len, len);
+		return 1;
+	}
+
+	i = 4; /* offset to the start of the identifier */
+	j = 0;
+	if ((page_83[0] & 0x0f) == CODESET_ASCII) {
+		/*
+		 * ASCII descriptor.
+		 *
+		 * Check whether the descriptor contains anything useful
+		 * i.e. anything apart from ' ' or '0'.
+		 */
+#ifdef DEBUG
+		fprintf(stdout,"%s: string '", scsi_dev);
+#endif
+		while (i < (4 + page_83[3])) {
+			if (page_83[i] == ' ' || page_83[i] == '0')
+				len--;
+#ifdef DEBUG		
+			fputc(page_83[i],stdout);
+#endif
+			i++;
+		}
+#ifdef DEBUG
+		fprintf(stdout,"'");
+#endif
+	} else {
+		/*
+		 * Binary descriptor, convert to ASCII, using two bytes of
+		 * ASCII for each byte in the page_83.
+		 *
+		 * Again, check whether the descriptor contains anything
+		 * useful; in this case, anything > 0.
+		 */
+#ifdef DEBUG
+		fprintf(stdout,"%s: binary ", scsi_dev);
+#endif
+		while (i < (4 + page_83[3])) {
+			if (page_83[i] == 0)
+				len-=2;
+#ifdef DEBUG
+			fputc(hex_str[(page_83[i] & 0xf0) >> 4],stdout);
+			fputc(hex_str[page_83[i] & 0x0f],stdout);
+#endif
+			i++;
+		}
+	}
+#ifdef DEBUG
+	fprintf(stdout," (len %d)\n", len);
+#endif
+
+	if (len <= 0)
+		return -1;
+
+	return idweight;
+}
+
+/**
+ * fill_0x83_id - fill serial number.
+ **/
+static int fill_0x83_id(char *page_83, char *serial)
 {
-	int i;
-	const char *p;
-	char *cursor;
-	unsigned char c;
-	char empty_buff[WWID_SIZE];
-
-	memset(empty_buff, 0, WWID_SIZE);
-
-	if (0 == memcmp(empty_buff, str, WWID_SIZE))
-		return;
-
-	p = str;
-	cursor = buff;
-	for (i = 0; i <= WWID_SIZE / 2 - 1; i++) {
-		c = *p++;
-		sprintf(cursor, "%.2x", (int) (unsigned char) c);
-		cursor += 2;
+	int i, j, len;
+
+	/*
+	 * page_83[3]: identifier length
+	 */
+	len = page_83[3];
+	if ((page_83[0] & 0x0f) != CODESET_ASCII)
+		/*
+		 * If not ASCII, use two bytes for each binary value.
+		 */
+		len *= 2;
+
+       	/*
+	 * Add one byte for the NUL termination.
+	 */
+	len += 1;
+
+	i = 4; /* offset to the start of the identifier */
+	j = 0;
+	if ((page_83[0] & 0x0f) == CODESET_ASCII) {
+		/*
+		 * ASCII descriptor.
+		 */
+		while (i < (4 + page_83[3])) {
+			/* Map ' ' -> '_' */
+			if (page_83[i] == ' ')
+				serial[j] = '_';
+			else
+				serial[j] = page_83[i];
+			j++; i++;
+		}
+	} else {
+		/*
+		 * Binary descriptor, convert to ASCII, using two bytes of
+		 * ASCII for each byte in the page_83.
+		 */
+		while (i < (4 + page_83[3])) {
+			serial[j++] = hex_str[(page_83[i] & 0xf0) >> 4];
+			serial[j++] = hex_str[page_83[i] & 0x0f];
+			i++;
+		}
 	}
-	buff[WWID_SIZE - 1] = '\0';
+	return 0;
 }
 
 long
@@ -246,18 +450,39 @@
 int
 get_evpd_wwid (char * devname, char * wwid)
 {
-        int fd;
+        int fd, j, weight, weight_cur, offset_cur, retval = 0;
         char buff[MX_ALLOC_LEN + 1];
 
         if ((fd = open(devname, O_RDONLY)) < 0)
                         return 1;
 
+	weight_cur = -1;
+	offset_cur = -1;
         if (0 == do_inq(fd, 0, 1, 0x83, buff, MX_ALLOC_LEN, 1)) {
-                sprint_wwid(wwid, &buff[8]);
-                close(fd);
-                return 0;
+		/*
+		 * Examine each descriptor returned. There is normally only
+		 * one or a small number of descriptors.
+		 */
+		for (j = 4; j <= buff[3] + 3; j += buff[j + 3] + 4) {
+#ifdef DEBUG
+			fprintf(stdout,"%s: ID descriptor at %d:\n", 
+				devname, j);
+#endif
+			weight = check_0x83_id(devname, &buff[j], 
+					       MX_ALLOC_LEN);
+			if (weight >= 0 && weight > weight_cur) {
+				weight_cur = weight;
+				offset_cur = j;
+			}
+		}
+		if (weight_cur >= 0)
+			fill_0x83_id(&buff[offset_cur], wwid);
+		else
+			retval = 1;
+	} else {
+		retval = 1;
         }
 
         close(fd);
-        return 1;
+        return retval;
 }

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2004-07-14  9:49 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2004-07-05  9:37 Patch to multipath-tools 0.2.4 Hannes Reinecke
2004-07-05 12:11 ` christophe.varoqui
2004-07-09 15:32 ` Patrick Mansfield
2004-07-09 15:50 ` christophe varoqui
2004-07-09 16:00 ` Patrick Mansfield
2004-07-12 21:46 ` christophe varoqui
2004-07-13  0:26 ` Patrick Mansfield
2004-07-13  8:17 ` christophe.varoqui
2004-07-13 16:57 ` Patrick Mansfield
2004-07-14  9:49 ` christophe varoqui

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).