hpacucli on 7-stable amd64, some progress

John Hay jhay at meraka.org.za
Mon Mar 30 00:12:34 PDT 2009


Hi,

I found that the reason hpacucli did not like amd64 7-stable was
because the kernel is missing code to do a 32 bit PCIOCGETCONF ioctl.

Here is a first stab at it. It works for me. I can do a "hpacucli
controller all show".

I also updated the firmware on the MSA20, so that I can put 1TB disks
in it and now hpacucli does not want to show me the physical or
logical disks behind it anymore. :-(

BTW, was hpacucli always so noisy? I got hold of a DL380-G4 only
recently, so did not run it on older versions of FreeBSD.

Anybody know if there is a chance to get a newer hpacucli?

John
-- 
John Hay -- John.Hay at meraka.csir.co.za / jhay at FreeBSD.org


--- sys/dev/pci/pci_user.c.orig	2009-02-26 20:54:24.000000000 +0200
+++ sys/dev/pci/pci_user.c	2009-03-29 17:10:45.000000000 +0200
@@ -225,6 +225,49 @@
 	u_int32_t	pi_data;	/* data to write or result of read */
 };
 
+#ifdef COMPAT_IA32
+struct pci_conf_old32 {
+	struct pcisel_old pc_sel;	/* bus+slot+function */
+	u_int8_t	pc_hdr;		/* PCI header type */
+	u_int16_t	pc_subvendor;	/* card vendor ID */
+	u_int16_t	pc_subdevice;	/* card device ID, assigned by
+					   card vendor */
+	u_int16_t	pc_vendor;	/* chip vendor ID */
+	u_int16_t	pc_device;	/* chip device ID, assigned by
+					   chip vendor */
+	u_int8_t	pc_class;	/* chip PCI class */
+	u_int8_t	pc_subclass;	/* chip PCI subclass */
+	u_int8_t	pc_progif;	/* chip PCI programming interface */
+	u_int8_t	pc_revid;	/* chip revision ID */
+	char		pd_name[PCI_MAXNAMELEN + 1];  /* device name */
+	u_int32_t	pd_unit;	/* device unit number (u_long) */
+};
+
+struct pci_match_conf_old32 {
+	struct pcisel_old	pc_sel;		/* bus+slot+function */
+	char			pd_name[PCI_MAXNAMELEN + 1];  /* device name */
+	u_int32_t		pd_unit;	/* Unit number (u_long) */
+	u_int16_t		pc_vendor;	/* PCI Vendor ID */
+	u_int16_t		pc_device;	/* PCI Device ID */
+	u_int8_t		pc_class;	/* PCI class */
+	pci_getconf_flags_old	flags;		/* Matching expression */
+};
+
+struct pci_conf_io32 {
+	u_int32_t		pat_buf_len;	/* pattern buffer length */
+	u_int32_t		num_patterns;	/* number of patterns */
+	u_int32_t		patterns;	/* pattern buffer (struct pci_match_conf_old32 *) */
+	u_int32_t		match_buf_len;	/* match buffer length */
+	u_int32_t		num_matches;	/* number of matches returned */
+	u_int32_t		matches;	/* match buffer (struct pci_conf_old32 *) */
+	u_int32_t		offset;		/* offset into device list */
+	u_int32_t		generation;	/* device list generation */
+	pci_getconf_status	status;		/* request status */
+};
+
+#define	PCIOCGETCONF_OLD32	_IOWR('p', 1, struct pci_conf_io32)
+#endif
+
 #define	PCIOCGETCONF_OLD	_IOWR('p', 1, struct pci_conf_io)
 #define	PCIOCREAD_OLD		_IOWR('p', 2, struct pci_io_old)
 #define	PCIOCWRITE_OLD		_IOWR('p', 3, struct pci_io_old)
@@ -295,6 +338,69 @@
 	return(1);
 }
 
+static int
+pci_conf_match_old32(struct pci_match_conf_old32 *matches, int num_matches,
+    struct pci_conf *match_buf)
+{
+	int i;
+
+	if ((matches == NULL) || (match_buf == NULL) || (num_matches <= 0))
+		return(1);
+
+	for (i = 0; i < num_matches; i++) {
+		if (match_buf->pc_sel.pc_domain != 0)
+			continue;
+
+		/*
+		 * I'm not sure why someone would do this...but...
+		 */
+		if (matches[i].flags == PCI_GETCONF_NO_MATCH_OLD)
+			continue;
+
+		/*
+		 * Look at each of the match flags.  If it's set, do the
+		 * comparison.  If the comparison fails, we don't have a
+		 * match, go on to the next item if there is one.
+		 */
+		if (((matches[i].flags & PCI_GETCONF_MATCH_BUS_OLD) != 0)
+		 && (match_buf->pc_sel.pc_bus != matches[i].pc_sel.pc_bus))
+			continue;
+
+		if (((matches[i].flags & PCI_GETCONF_MATCH_DEV_OLD) != 0)
+		 && (match_buf->pc_sel.pc_dev != matches[i].pc_sel.pc_dev))
+			continue;
+
+		if (((matches[i].flags & PCI_GETCONF_MATCH_FUNC_OLD) != 0)
+		 && (match_buf->pc_sel.pc_func != matches[i].pc_sel.pc_func))
+			continue;
+
+		if (((matches[i].flags & PCI_GETCONF_MATCH_VENDOR_OLD) != 0)
+		 && (match_buf->pc_vendor != matches[i].pc_vendor))
+			continue;
+
+		if (((matches[i].flags & PCI_GETCONF_MATCH_DEVICE_OLD) != 0)
+		 && (match_buf->pc_device != matches[i].pc_device))
+			continue;
+
+		if (((matches[i].flags & PCI_GETCONF_MATCH_CLASS_OLD) != 0)
+		 && (match_buf->pc_class != matches[i].pc_class))
+			continue;
+
+		if (((matches[i].flags & PCI_GETCONF_MATCH_UNIT_OLD) != 0)
+		 && ((u_int32_t)match_buf->pd_unit != matches[i].pd_unit))
+			continue;
+
+		if (((matches[i].flags & PCI_GETCONF_MATCH_NAME_OLD) != 0)
+		 && (strncmp(matches[i].pd_name, match_buf->pd_name,
+			     sizeof(match_buf->pd_name)) != 0))
+			continue;
+
+		return(0);
+	}
+
+	return(1);
+}
+
 #endif
 
 static int
@@ -314,13 +420,21 @@
 	size_t confsz, iolen, pbufsz;
 	int error, ionum, i, num_patterns;
 #ifdef PRE7_COMPAT
+#ifdef COMPAT_IA32
+	struct pci_conf_io32 *cio32;
+#endif
 	struct pci_conf_old conf_old;
+	struct pci_conf_old32 conf_old32;
 	struct pci_io iodata;
 	struct pci_io_old *io_old;
 	struct pci_match_conf_old *pattern_buf_old;
+	struct pci_match_conf_old32 *pattern_buf_old32;
 
+	cio = NULL;
+	cio32 = NULL;
 	io_old = NULL;
 	pattern_buf_old = NULL;
+	pattern_buf_old32 = NULL;
 
 	if (!(flag & FWRITE) && cmd != PCIOCGETBAR &&
 	    cmd != PCIOCGETCONF && cmd != PCIOCGETCONF_OLD)
@@ -332,11 +446,27 @@
 
 	switch(cmd) {
 #ifdef PRE7_COMPAT
+	case PCIOCGETCONF_OLD32:
+		cio32 = (struct pci_conf_io32 *)data;
+		cio = malloc(sizeof(struct pci_conf_io), M_TEMP, M_WAITOK);
+		cio->pat_buf_len = cio32->pat_buf_len;
+		cio->num_patterns = cio32->num_patterns;
+		cio->patterns = (void *)(uintptr_t)cio32->patterns;
+		cio->match_buf_len = cio32->match_buf_len;
+		cio->num_matches = cio32->num_matches;
+		cio->matches = (void *)(uintptr_t)cio32->matches;
+		cio->offset = cio32->offset;
+		cio->generation = cio32->generation;
+		cio->status = cio32->status;
+		cio32->num_matches = 0;
+		/* FALLTHROUGH */
+
 	case PCIOCGETCONF_OLD:
 		/* FALLTHROUGH */
 #endif
 	case PCIOCGETCONF:
-		cio = (struct pci_conf_io *)data;
+		if (cio == NULL)
+			cio = (struct pci_conf_io *)data;
 
 		pattern_buf = NULL;
 		num_patterns = 0;
@@ -354,7 +484,7 @@
 		 && (cio->generation != pci_generation)){
 			cio->status = PCI_GETCONF_LIST_CHANGED;
 			error = 0;
-			break;
+			goto getconfexit;
 		}
 
 		/*
@@ -364,7 +494,7 @@
 		if (cio->offset >= pci_numdevs) {
 			cio->status = PCI_GETCONF_LAST_DEVICE;
 			error = 0;
-			break;
+			goto getconfexit;
 		}
 
 		/* get the head of the device queue */
@@ -377,6 +507,11 @@
 		 * didn't specify a multiple of that size.
 		 */
 #ifdef PRE7_COMPAT
+#ifdef COMPAT_IA32
+		if (cmd == PCIOCGETCONF_OLD32)
+			confsz = sizeof(struct pci_conf_old32);
+		else
+#endif
 		if (cmd == PCIOCGETCONF_OLD)
 			confsz = sizeof(struct pci_conf_old);
 		else
@@ -411,6 +546,11 @@
 			 * updated their kernel but not their userland.
 			 */
 #ifdef PRE7_COMPAT
+#ifdef COMPAT_IA32
+			if (cmd == PCIOCGETCONF_OLD32)
+				pbufsz = sizeof(struct pci_match_conf_old32);
+			else
+#endif
 			if (cmd == PCIOCGETCONF_OLD)
 				pbufsz = sizeof(struct pci_match_conf_old);
 			else
@@ -420,13 +560,19 @@
 				/* The user made a mistake, return an error. */
 				cio->status = PCI_GETCONF_ERROR;
 				error = EINVAL;
-				break;
+				goto getconfexit;
 			}
 
 			/*
 			 * Allocate a buffer to hold the patterns.
 			 */
 #ifdef PRE7_COMPAT
+			if (cmd == PCIOCGETCONF_OLD32) {
+				pattern_buf_old32 = malloc(cio->pat_buf_len,
+				    M_TEMP, M_WAITOK);
+				error = copyin(cio->patterns,
+				    pattern_buf_old32, cio->pat_buf_len);
+			} else
 			if (cmd == PCIOCGETCONF_OLD) {
 				pattern_buf_old = malloc(cio->pat_buf_len,
 				    M_TEMP, M_WAITOK);
@@ -452,7 +598,7 @@
 			 */
 			cio->status = PCI_GETCONF_ERROR;
 			error = EINVAL;
-			break;
+			goto getconfexit;
 		}
 
 		/*
@@ -484,7 +630,11 @@
 			}
 
 #ifdef PRE7_COMPAT
-			if ((cmd == PCIOCGETCONF_OLD &&
+			if ((cmd == PCIOCGETCONF_OLD32 &&
+			    (pattern_buf_old32 == NULL ||
+			    pci_conf_match_old32(pattern_buf_old32,
+			    num_patterns, &dinfo->conf) == 0)) ||
+			    (cmd == PCIOCGETCONF_OLD &&
 			    (pattern_buf_old == NULL ||
 			    pci_conf_match_old(pattern_buf_old, num_patterns,
 			    &dinfo->conf) == 0)) ||
@@ -509,6 +659,38 @@
 					break;
 
 #ifdef PRE7_COMPAT
+				if (cmd == PCIOCGETCONF_OLD32) {
+					conf_old32.pc_sel.pc_bus =
+					    dinfo->conf.pc_sel.pc_bus;
+					conf_old32.pc_sel.pc_dev =
+					    dinfo->conf.pc_sel.pc_dev;
+					conf_old32.pc_sel.pc_func =
+					    dinfo->conf.pc_sel.pc_func;
+					conf_old32.pc_hdr = dinfo->conf.pc_hdr;
+					conf_old32.pc_subvendor =
+					    dinfo->conf.pc_subvendor;
+					conf_old32.pc_subdevice =
+					    dinfo->conf.pc_subdevice;
+					conf_old32.pc_vendor =
+					    dinfo->conf.pc_vendor;
+					conf_old32.pc_device =
+					    dinfo->conf.pc_device;
+					conf_old32.pc_class =
+					    dinfo->conf.pc_class;
+					conf_old32.pc_subclass =
+					    dinfo->conf.pc_subclass;
+					conf_old32.pc_progif =
+					    dinfo->conf.pc_progif;
+					conf_old32.pc_revid =
+					    dinfo->conf.pc_revid;
+					strncpy(conf_old32.pd_name,
+					    dinfo->conf.pd_name,
+					    sizeof(conf_old32.pd_name));
+					conf_old32.pd_name[PCI_MAXNAMELEN] = 0;
+					conf_old32.pd_unit =
+					    (u_int32_t)dinfo->conf.pd_unit;
+					confdata = &conf_old32;
+				} else
 				if (cmd == PCIOCGETCONF_OLD) {
 					conf_old.pc_sel.pc_bus =
 					    dinfo->conf.pc_sel.pc_bus;
@@ -575,9 +757,22 @@
 			cio->status = PCI_GETCONF_MORE_DEVS;
 
 getconfexit:
+#ifdef COMPAT_IA32
+		if (cmd == PCIOCGETCONF_OLD32) {
+			cio32->status = cio->status;
+			cio32->generation = cio->generation;
+			cio32->offset = cio->offset;
+			cio32->num_matches = cio->num_matches;
+			if (cio != NULL)
+				free(cio, M_TEMP);
+		}
+#endif
+
 		if (pattern_buf != NULL)
 			free(pattern_buf, M_TEMP);
 #ifdef PRE7_COMPAT
+		if (pattern_buf_old32 != NULL)
+			free(pattern_buf_old32, M_TEMP);
 		if (pattern_buf_old != NULL)
 			free(pattern_buf_old, M_TEMP);
 #endif


More information about the freebsd-proliant mailing list