Author: marius
Date: Fri Jul 12 18:02:10 2013
New Revision: 253278
URL: http://svnweb.freebsd.org/changeset/base/253278

Log:
  MFC: r240981, r240990, r240992, r244695
  
  Add 32-bit ABI compat shims. Those are necessary for i386 binary-only
  tools like sysutils/hpacucli (HP P4xx RAID controller management
  suite) working on amd64 systems.
  
  PR:           139271
  Submitted by: Kazumi MORINAGA, Eugene Grosbein
  Approved by:  re (kib)

Modified:
  stable/9/sys/dev/pci/pci_user.c
Directory Properties:
  stable/9/sys/   (props changed)
  stable/9/sys/dev/   (props changed)

Modified: stable/9/sys/dev/pci/pci_user.c
==============================================================================
--- stable/9/sys/dev/pci/pci_user.c     Fri Jul 12 17:37:05 2013        
(r253277)
+++ stable/9/sys/dev/pci/pci_user.c     Fri Jul 12 18:02:10 2013        
(r253278)
@@ -225,6 +225,51 @@ struct pci_io_old {
        u_int32_t       pi_data;        /* data to write or result of read */
 };
 
+#ifdef COMPAT_FREEBSD32
+struct pci_conf_old32 {
+       struct pcisel_old pc_sel;       /* bus+slot+function */
+       uint8_t         pc_hdr;         /* PCI header type */
+       uint16_t        pc_subvendor;   /* card vendor ID */
+       uint16_t        pc_subdevice;   /* card device ID, assigned by
+                                          card vendor */
+       uint16_t        pc_vendor;      /* chip vendor ID */
+       uint16_t        pc_device;      /* chip device ID, assigned by
+                                          chip vendor */
+       uint8_t         pc_class;       /* chip PCI class */
+       uint8_t         pc_subclass;    /* chip PCI subclass */
+       uint8_t         pc_progif;      /* chip PCI programming interface */
+       uint8_t         pc_revid;       /* chip revision ID */
+       char            pd_name[PCI_MAXNAMELEN + 1]; /* device name */
+       uint32_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 */
+       uint32_t        pd_unit;        /* Unit number (u_long) */
+       uint16_t        pc_vendor;      /* PCI Vendor ID */
+       uint16_t        pc_device;      /* PCI Device ID */
+       uint8_t         pc_class;       /* PCI class */
+       pci_getconf_flags_old flags;    /* Matching expression */
+};
+
+struct pci_conf_io32 {
+       uint32_t        pat_buf_len;    /* pattern buffer length */
+       uint32_t        num_patterns;   /* number of patterns */
+       uint32_t        patterns;       /* pattern buffer
+                                          (struct pci_match_conf_old32 *) */
+       uint32_t        match_buf_len;  /* match buffer length */
+       uint32_t        num_matches;    /* number of matches returned */
+       uint32_t        matches;        /* match buffer
+                                          (struct pci_conf_old32 *) */
+       uint32_t        offset;         /* offset into device list */
+       uint32_t        generation;     /* device list generation */
+       pci_getconf_status status;      /* request status */
+};
+
+#define        PCIOCGETCONF_OLD32      _IOWR('p', 1, struct pci_conf_io32)
+#endif /* COMPAT_FREEBSD32 */
+
 #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,7 +340,71 @@ pci_conf_match_old(struct pci_match_conf
        return(1);
 }
 
-#endif
+#ifdef COMPAT_FREEBSD32
+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 /* COMPAT_FREEBSD32 */
+#endif /* PRE7_COMPAT */
 
 static int
 pci_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread 
*td)
@@ -304,7 +413,7 @@ pci_ioctl(struct cdev *dev, u_long cmd, 
        void *confdata;
        const char *name;
        struct devlist *devlist_head;
-       struct pci_conf_io *cio;
+       struct pci_conf_io *cio = NULL;
        struct pci_devinfo *dinfo;
        struct pci_io *io;
        struct pci_bar_io *bio;
@@ -313,13 +422,17 @@ pci_ioctl(struct cdev *dev, u_long cmd, 
        size_t confsz, iolen, pbufsz;
        int error, ionum, i, num_patterns;
 #ifdef PRE7_COMPAT
+#ifdef COMPAT_FREEBSD32
+       struct pci_conf_io32 *cio32 = NULL;
+       struct pci_conf_old32 conf_old32;
+       struct pci_match_conf_old32 *pattern_buf_old32 = NULL;
+#endif
        struct pci_conf_old conf_old;
        struct pci_io iodata;
        struct pci_io_old *io_old;
-       struct pci_match_conf_old *pattern_buf_old;
+       struct pci_match_conf_old *pattern_buf_old = NULL;
 
        io_old = NULL;
-       pattern_buf_old = NULL;
 
        if (!(flag & FWRITE) && cmd != PCIOCGETBAR &&
            cmd != PCIOCGETCONF && cmd != PCIOCGETCONF_OLD)
@@ -331,11 +444,36 @@ pci_ioctl(struct cdev *dev, u_long cmd, 
 
        switch(cmd) {
 #ifdef PRE7_COMPAT
+#ifdef COMPAT_FREEBSD32
+       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;
+               break;
+#endif
        case PCIOCGETCONF_OLD:
-               /* FALLTHROUGH */
 #endif
        case PCIOCGETCONF:
                cio = (struct pci_conf_io *)data;
+       }
+
+       switch(cmd) {
+#ifdef PRE7_COMPAT
+#ifdef COMPAT_FREEBSD32
+       case PCIOCGETCONF_OLD32:
+#endif
+       case PCIOCGETCONF_OLD:
+#endif
+       case PCIOCGETCONF:
 
                pattern_buf = NULL;
                num_patterns = 0;
@@ -353,7 +491,7 @@ pci_ioctl(struct cdev *dev, u_long cmd, 
                 && (cio->generation != pci_generation)){
                        cio->status = PCI_GETCONF_LIST_CHANGED;
                        error = 0;
-                       break;
+                       goto getconfexit;
                }
 
                /*
@@ -363,7 +501,7 @@ pci_ioctl(struct cdev *dev, u_long cmd, 
                if (cio->offset >= pci_numdevs) {
                        cio->status = PCI_GETCONF_LAST_DEVICE;
                        error = 0;
-                       break;
+                       goto getconfexit;
                }
 
                /* get the head of the device queue */
@@ -376,6 +514,11 @@ pci_ioctl(struct cdev *dev, u_long cmd, 
                 * didn't specify a multiple of that size.
                 */
 #ifdef PRE7_COMPAT
+#ifdef COMPAT_FREEBSD32
+               if (cmd == PCIOCGETCONF_OLD32)
+                       confsz = sizeof(struct pci_conf_old32);
+               else
+#endif
                if (cmd == PCIOCGETCONF_OLD)
                        confsz = sizeof(struct pci_conf_old);
                else
@@ -410,6 +553,11 @@ pci_ioctl(struct cdev *dev, u_long cmd, 
                         * updated their kernel but not their userland.
                         */
 #ifdef PRE7_COMPAT
+#ifdef COMPAT_FREEBSD32
+                       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
@@ -419,20 +567,28 @@ pci_ioctl(struct cdev *dev, u_long cmd, 
                                /* 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
+#ifdef COMPAT_FREEBSD32
+                       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
+#endif /* COMPAT_FREEBSD32 */
                        if (cmd == PCIOCGETCONF_OLD) {
                                pattern_buf_old = malloc(cio->pat_buf_len,
                                    M_TEMP, M_WAITOK);
                                error = copyin(cio->patterns,
                                    pattern_buf_old, cio->pat_buf_len);
                        } else
-#endif
+#endif /* PRE7_COMPAT */
                        {
                                pattern_buf = malloc(cio->pat_buf_len, M_TEMP,
                                    M_WAITOK);
@@ -451,7 +607,7 @@ pci_ioctl(struct cdev *dev, u_long cmd, 
                         */
                        cio->status = PCI_GETCONF_ERROR;
                        error = EINVAL;
-                       break;
+                       goto getconfexit;
                }
 
                /*
@@ -483,7 +639,14 @@ pci_ioctl(struct cdev *dev, u_long cmd, 
                        }
 
 #ifdef PRE7_COMPAT
-                       if ((cmd == PCIOCGETCONF_OLD &&
+                       if (
+#ifdef COMPAT_FREEBSD32
+                           (cmd == PCIOCGETCONF_OLD32 &&
+                           (pattern_buf_old32 == NULL ||
+                           pci_conf_match_old32(pattern_buf_old32,
+                           num_patterns, &dinfo->conf) == 0)) ||
+#endif
+                           (cmd == PCIOCGETCONF_OLD &&
                            (pattern_buf_old == NULL ||
                            pci_conf_match_old(pattern_buf_old, num_patterns,
                            &dinfo->conf) == 0)) ||
@@ -508,6 +671,40 @@ pci_ioctl(struct cdev *dev, u_long cmd, 
                                        break;
 
 #ifdef PRE7_COMPAT
+#ifdef COMPAT_FREEBSD32
+                               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 =
+                                           (uint32_t)dinfo->conf.pd_unit;
+                                       confdata = &conf_old32;
+                               } else
+#endif /* COMPAT_FREEBSD32 */
                                if (cmd == PCIOCGETCONF_OLD) {
                                        conf_old.pc_sel.pc_bus =
                                            dinfo->conf.pc_sel.pc_bus;
@@ -540,7 +737,7 @@ pci_ioctl(struct cdev *dev, u_long cmd, 
                                            dinfo->conf.pd_unit;
                                        confdata = &conf_old;
                                } else
-#endif
+#endif /* PRE7_COMPAT */
                                        confdata = &dinfo->conf;
                                /* Only if we can copy it out do we count it. */
                                if (!(error = copyout(confdata,
@@ -574,12 +771,23 @@ pci_ioctl(struct cdev *dev, u_long cmd, 
                        cio->status = PCI_GETCONF_MORE_DEVS;
 
 getconfexit:
-               if (pattern_buf != NULL)
-                       free(pattern_buf, M_TEMP);
 #ifdef PRE7_COMPAT
+#ifdef COMPAT_FREEBSD32
+               if (cmd == PCIOCGETCONF_OLD32) {
+                       cio32->status = cio->status;
+                       cio32->generation = cio->generation;
+                       cio32->offset = cio->offset;
+                       cio32->num_matches = cio->num_matches;
+                       free(cio, M_TEMP);
+               }
+               if (pattern_buf_old32 != NULL)
+                       free(pattern_buf_old32, M_TEMP);
+#endif
                if (pattern_buf_old != NULL)
                        free(pattern_buf_old, M_TEMP);
 #endif
+               if (pattern_buf != NULL)
+                       free(pattern_buf, M_TEMP);
 
                break;
 
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to