Print this page
Code review changes
3644 Add virtio-net support into illumos
4945 Additional vioif fixes
Contributions by: Dan Kimmel <dan.kimmel@delphix.com>
Contributions by: Hans Rosenfeld <hans.rosenfeld@nexenta.com>
Contributions by: Alexey Zaytsev <alexey.zaytsev@gmail.com>
Contributions by: Dmitry Yusupov <Dmitry.Yusupov@nexenta.com>
Reviewed by: Igor Kozhukhov <ikozhukhov@gmail.com>
        
*** 18,28 ****
   *
   * CDDL HEADER END
   */
  
  /*
!  * Copyright 2012 Nexenta Systems, Inc.
   * Copyright 2012 Alexey Zaytsev <alexey.zaytsev@gmail.com>
   */
  
  /* Based on the NetBSD virtio driver by Minoura Makoto. */
  /*
--- 18,28 ----
   *
   * CDDL HEADER END
   */
  
  /*
!  * Copyright 2013 Nexenta Systems, Inc.  All rights reserved.
   * Copyright 2012 Alexey Zaytsev <alexey.zaytsev@gmail.com>
   */
  
  /* Based on the NetBSD virtio driver by Minoura Makoto. */
  /*
*** 69,78 ****
--- 69,79 ----
  #include <sys/sysmacros.h>
  #include <sys/pci.h>
  
  #include "virtiovar.h"
  #include "virtioreg.h"
+ 
  #define NDEVNAMES       (sizeof (virtio_device_name) / sizeof (char *))
  #define MINSEG_INDIRECT 2       /* use indirect if nsegs >= this value */
  #define VIRTQUEUE_ALIGN(n) (((n)+(VIRTIO_PAGE_SIZE-1)) & \
              ~(VIRTIO_PAGE_SIZE-1))
  
*** 79,96 ****
  void
  virtio_set_status(struct virtio_softc *sc, unsigned int status)
  {
          int old = 0;
  
!         if (status != 0)
!                 old = ddi_get8(sc->sc_ioh,
!                     (uint8_t *)(sc->sc_io_addr +
                      VIRTIO_CONFIG_DEVICE_STATUS));
  
!         ddi_put8(sc->sc_ioh,
!             (uint8_t *)(sc->sc_io_addr + VIRTIO_CONFIG_DEVICE_STATUS),
!             status | old);
  }
  
  /*
   * Negotiate features, save the result in sc->sc_features
   */
--- 80,96 ----
  void
  virtio_set_status(struct virtio_softc *sc, unsigned int status)
  {
          int old = 0;
  
!         if (status != 0) {
!                 old = ddi_get8(sc->sc_ioh, (uint8_t *)(sc->sc_io_addr +
                      VIRTIO_CONFIG_DEVICE_STATUS));
+         }
  
!         ddi_put8(sc->sc_ioh, (uint8_t *)(sc->sc_io_addr +
!             VIRTIO_CONFIG_DEVICE_STATUS), status | old);
  }
  
  /*
   * Negotiate features, save the result in sc->sc_features
   */
*** 102,113 ****
  
          host_features = ddi_get32(sc->sc_ioh,
              /* LINTED E_BAD_PTR_CAST_ALIGN */
              (uint32_t *)(sc->sc_io_addr + VIRTIO_CONFIG_DEVICE_FEATURES));
  
!         dev_debug(sc->sc_dev, CE_NOTE,
!             "host features: %x, guest features: %x",
              host_features, guest_features);
  
          features = host_features & guest_features;
          ddi_put32(sc->sc_ioh,
              /* LINTED E_BAD_PTR_CAST_ALIGN */
--- 102,112 ----
  
          host_features = ddi_get32(sc->sc_ioh,
              /* LINTED E_BAD_PTR_CAST_ALIGN */
              (uint32_t *)(sc->sc_io_addr + VIRTIO_CONFIG_DEVICE_FEATURES));
  
!         dev_debug(sc->sc_dev, CE_NOTE, "host features: %x, guest features: %x",
              host_features, guest_features);
  
          features = host_features & guest_features;
          ddi_put32(sc->sc_ioh,
              /* LINTED E_BAD_PTR_CAST_ALIGN */
*** 118,129 ****
  
          return (host_features);
  }
  
  size_t
! virtio_show_features(uint32_t features,
!     char *buf, size_t len)
  {
          char *orig_buf = buf;
          char *bufend = buf + len;
  
          /* LINTED E_PTRDIFF_OVERFLOW */
--- 117,127 ----
  
          return (host_features);
  }
  
  size_t
! virtio_show_features(uint32_t features, char *buf, size_t len)
  {
          char *orig_buf = buf;
          char *bufend = buf + len;
  
          /* LINTED E_PTRDIFF_OVERFLOW */
*** 192,232 ****
              (uint32_t *)(sc->sc_io_addr + sc->sc_config_offset + index));
          return (r);
  }
  
  void
! virtio_write_device_config_1(struct virtio_softc *sc,
!     unsigned int index, uint8_t value)
  {
          ASSERT(sc->sc_config_offset);
          ddi_put8(sc->sc_ioh,
              (uint8_t *)(sc->sc_io_addr + sc->sc_config_offset + index), value);
  }
  
  void
! virtio_write_device_config_2(struct virtio_softc *sc,
!     unsigned int index, uint16_t value)
  {
          ASSERT(sc->sc_config_offset);
          ddi_put16(sc->sc_ioh,
              /* LINTED E_BAD_PTR_CAST_ALIGN */
              (uint16_t *)(sc->sc_io_addr + sc->sc_config_offset + index), value);
  }
  
  void
! virtio_write_device_config_4(struct virtio_softc *sc,
!     unsigned int index, uint32_t value)
  {
          ASSERT(sc->sc_config_offset);
          ddi_put32(sc->sc_ioh,
              /* LINTED E_BAD_PTR_CAST_ALIGN */
              (uint32_t *)(sc->sc_io_addr + sc->sc_config_offset + index), value);
  }
  
  void
! virtio_write_device_config_8(struct virtio_softc *sc,
!     unsigned int index, uint64_t value)
  {
          ASSERT(sc->sc_config_offset);
          ddi_put32(sc->sc_ioh,
              /* LINTED E_BAD_PTR_CAST_ALIGN */
              (uint32_t *)(sc->sc_io_addr + sc->sc_config_offset + index),
--- 190,230 ----
              (uint32_t *)(sc->sc_io_addr + sc->sc_config_offset + index));
          return (r);
  }
  
  void
! virtio_write_device_config_1(struct virtio_softc *sc, unsigned int index,
!     uint8_t value)
  {
          ASSERT(sc->sc_config_offset);
          ddi_put8(sc->sc_ioh,
              (uint8_t *)(sc->sc_io_addr + sc->sc_config_offset + index), value);
  }
  
  void
! virtio_write_device_config_2(struct virtio_softc *sc, unsigned int index,
!     uint16_t value)
  {
          ASSERT(sc->sc_config_offset);
          ddi_put16(sc->sc_ioh,
              /* LINTED E_BAD_PTR_CAST_ALIGN */
              (uint16_t *)(sc->sc_io_addr + sc->sc_config_offset + index), value);
  }
  
  void
! virtio_write_device_config_4(struct virtio_softc *sc, unsigned int index,
!     uint32_t value)
  {
          ASSERT(sc->sc_config_offset);
          ddi_put32(sc->sc_ioh,
              /* LINTED E_BAD_PTR_CAST_ALIGN */
              (uint32_t *)(sc->sc_io_addr + sc->sc_config_offset + index), value);
  }
  
  void
! virtio_write_device_config_8(struct virtio_softc *sc, unsigned int index,
!     uint64_t value)
  {
          ASSERT(sc->sc_config_offset);
          ddi_put32(sc->sc_ioh,
              /* LINTED E_BAD_PTR_CAST_ALIGN */
              (uint32_t *)(sc->sc_io_addr + sc->sc_config_offset + index),
*** 253,267 ****
  }
  
  static ddi_dma_attr_t virtio_vq_dma_attr = {
          DMA_ATTR_V0,    /* Version number */
          0,              /* low address */
!         /*
!          * high address. Has to fit into 32 bits
!          * after page-shifting
!          */
!         0x00000FFFFFFFFFFF,
          0xFFFFFFFF,     /* counter register max */
          VIRTIO_PAGE_SIZE, /* page alignment required */
          0x3F,           /* burst sizes: 1 - 32 */
          0x1,            /* minimum transfer size */
          0xFFFFFFFF,     /* max transfer size */
--- 251,262 ----
  }
  
  static ddi_dma_attr_t virtio_vq_dma_attr = {
          DMA_ATTR_V0,            /* Version number */
          0,                      /* low address */
!         0x00000FFFFFFFFFFF,     /* high address. Has to fit into 32 bits */
!                                 /* after page-shifting */
          0xFFFFFFFF,             /* counter register max */
          VIRTIO_PAGE_SIZE,       /* page alignment required */
          0x3F,                   /* burst sizes: 1 - 32 */
          0x1,                    /* minimum transfer size */
          0xFFFFFFFF,             /* max transfer size */
*** 321,358 ****
  
          ret = ddi_dma_alloc_handle(sc->sc_dev, &virtio_vq_indirect_dma_attr,
              DDI_DMA_SLEEP, NULL, &entry->qe_indirect_dma_handle);
          if (ret != DDI_SUCCESS) {
                  dev_err(sc->sc_dev, CE_WARN,
!                     "Failed to allocate dma handle for indirect descriptors,"
!                     " entry %d, vq %d", entry->qe_index,
                      entry->qe_queue->vq_index);
                  goto out_alloc_handle;
          }
  
!         ret = ddi_dma_mem_alloc(entry->qe_indirect_dma_handle,
!             allocsize, &virtio_vq_devattr,
!             DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL,
              (caddr_t *)&entry->qe_indirect_descs, &len,
              &entry->qe_indirect_dma_acch);
          if (ret != DDI_SUCCESS) {
                  dev_err(sc->sc_dev, CE_WARN,
!                     "Failed to alocate dma memory for indirect descriptors,"
!                     " entry %d, vq %d,", entry->qe_index,
                      entry->qe_queue->vq_index);
                  goto out_alloc;
          }
  
          (void) memset(entry->qe_indirect_descs, 0xff, allocsize);
  
          ret = ddi_dma_addr_bind_handle(entry->qe_indirect_dma_handle, NULL,
              (caddr_t)entry->qe_indirect_descs, len,
!             DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
!             DDI_DMA_SLEEP, NULL, &entry->qe_indirect_dma_cookie, &ncookies);
          if (ret != DDI_DMA_MAPPED) {
                  dev_err(sc->sc_dev, CE_WARN,
!                     "Failed to bind dma memory for indirect descriptors,"
                      "entry %d, vq %d", entry->qe_index,
                      entry->qe_queue->vq_index);
                  goto out_bind;
          }
  
--- 316,352 ----
  
          ret = ddi_dma_alloc_handle(sc->sc_dev, &virtio_vq_indirect_dma_attr,
              DDI_DMA_SLEEP, NULL, &entry->qe_indirect_dma_handle);
          if (ret != DDI_SUCCESS) {
                  dev_err(sc->sc_dev, CE_WARN,
!                     "Failed to allocate dma handle for indirect descriptors, "
!                     "entry %d, vq %d", entry->qe_index,
                      entry->qe_queue->vq_index);
                  goto out_alloc_handle;
          }
  
!         ret = ddi_dma_mem_alloc(entry->qe_indirect_dma_handle, allocsize,
!             &virtio_vq_devattr, DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL,
              (caddr_t *)&entry->qe_indirect_descs, &len,
              &entry->qe_indirect_dma_acch);
          if (ret != DDI_SUCCESS) {
                  dev_err(sc->sc_dev, CE_WARN,
!                     "Failed to allocate dma memory for indirect descriptors, "
!                     "entry %d, vq %d,", entry->qe_index,
                      entry->qe_queue->vq_index);
                  goto out_alloc;
          }
  
          (void) memset(entry->qe_indirect_descs, 0xff, allocsize);
  
          ret = ddi_dma_addr_bind_handle(entry->qe_indirect_dma_handle, NULL,
              (caddr_t)entry->qe_indirect_descs, len,
!             DDI_DMA_RDWR | DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL,
!             &entry->qe_indirect_dma_cookie, &ncookies);
          if (ret != DDI_DMA_MAPPED) {
                  dev_err(sc->sc_dev, CE_WARN,
!                     "Failed to bind dma memory for indirect descriptors, "
                      "entry %d, vq %d", entry->qe_index,
                      entry->qe_queue->vq_index);
                  goto out_bind;
          }
  
*** 397,412 ****
                          if (ret)
                                  goto out_indirect;
                  }
          }
  
!         mutex_init(&vq->vq_freelist_lock, "virtio-freelist",
!             MUTEX_DRIVER, DDI_INTR_PRI(sc->sc_intr_prio));
!         mutex_init(&vq->vq_avail_lock, "virtio-avail",
!             MUTEX_DRIVER, DDI_INTR_PRI(sc->sc_intr_prio));
!         mutex_init(&vq->vq_used_lock, "virtio-used",
!             MUTEX_DRIVER, DDI_INTR_PRI(sc->sc_intr_prio));
  
          return (0);
  
  out_indirect:
          for (i = 0; i < vq_size; i++) {
--- 391,406 ----
                          if (ret)
                                  goto out_indirect;
                  }
          }
  
!         mutex_init(&vq->vq_freelist_lock, "virtio-freelist", MUTEX_DRIVER,
!             DDI_INTR_PRI(sc->sc_intr_prio));
!         mutex_init(&vq->vq_avail_lock, "virtio-avail", MUTEX_DRIVER,
!             DDI_INTR_PRI(sc->sc_intr_prio));
!         mutex_init(&vq->vq_used_lock, "virtio-used", MUTEX_DRIVER,
!             DDI_INTR_PRI(sc->sc_intr_prio));
  
          return (0);
  
  out_indirect:
          for (i = 0; i < vq_size; i++) {
*** 416,444 ****
          }
  
          return (ret);
  }
  
- 
- 
  /*
   * Allocate/free a vq.
   */
  struct virtqueue *
! virtio_alloc_vq(struct virtio_softc *sc,
!     unsigned int index,
!     unsigned int size,
!     unsigned int indirect_num,
!     const char *name)
  {
          int vq_size, allocsize1, allocsize2, allocsize = 0;
          int ret;
          unsigned int ncookies;
          size_t len;
          struct virtqueue *vq;
  
- 
          ddi_put16(sc->sc_ioh,
              /* LINTED E_BAD_PTR_CAST_ALIGN */
              (uint16_t *)(sc->sc_io_addr + VIRTIO_CONFIG_QUEUE_SELECT), index);
          vq_size = ddi_get16(sc->sc_ioh,
              /* LINTED E_BAD_PTR_CAST_ALIGN */
--- 410,432 ----
          }
  
          return (ret);
  }
  
  /*
   * Allocate/free a vq.
   */
  struct virtqueue *
! virtio_alloc_vq(struct virtio_softc *sc, unsigned int index, unsigned int size,
!     unsigned int indirect_num, const char *name)
  {
          int vq_size, allocsize1, allocsize2, allocsize = 0;
          int ret;
          unsigned int ncookies;
          size_t len;
          struct virtqueue *vq;
  
          ddi_put16(sc->sc_ioh,
              /* LINTED E_BAD_PTR_CAST_ALIGN */
              (uint16_t *)(sc->sc_io_addr + VIRTIO_CONFIG_QUEUE_SELECT), index);
          vq_size = ddi_get16(sc->sc_ioh,
              /* LINTED E_BAD_PTR_CAST_ALIGN */
*** 455,469 ****
          if (size)
                  vq_size = MIN(vq_size, size);
  
          /* allocsize1: descriptor table + avail ring + pad */
          allocsize1 = VIRTQUEUE_ALIGN(sizeof (struct vring_desc) * vq_size +
!             sizeof (struct vring_avail) +
!             sizeof (uint16_t) * vq_size);
          /* allocsize2: used ring + pad */
!         allocsize2 = VIRTQUEUE_ALIGN(sizeof (struct vring_used)
!             + sizeof (struct vring_used_elem) * vq_size);
  
          allocsize = allocsize1 + allocsize2;
  
          ret = ddi_dma_alloc_handle(sc->sc_dev, &virtio_vq_dma_attr,
              DDI_DMA_SLEEP, NULL, &vq->vq_dma_handle);
--- 443,456 ----
          if (size)
                  vq_size = MIN(vq_size, size);
  
          /* allocsize1: descriptor table + avail ring + pad */
          allocsize1 = VIRTQUEUE_ALIGN(sizeof (struct vring_desc) * vq_size +
!             sizeof (struct vring_avail) + sizeof (uint16_t) * vq_size);
          /* allocsize2: used ring + pad */
!         allocsize2 = VIRTQUEUE_ALIGN(sizeof (struct vring_used) +
!             sizeof (struct vring_used_elem) * vq_size);
  
          allocsize = allocsize1 + allocsize2;
  
          ret = ddi_dma_alloc_handle(sc->sc_dev, &virtio_vq_dma_attr,
              DDI_DMA_SLEEP, NULL, &vq->vq_dma_handle);
*** 476,493 ****
          ret = ddi_dma_mem_alloc(vq->vq_dma_handle, allocsize,
              &virtio_vq_devattr, DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL,
              (caddr_t *)&vq->vq_vaddr, &len, &vq->vq_dma_acch);
          if (ret != DDI_SUCCESS) {
                  dev_err(sc->sc_dev, CE_WARN,
!                     "Failed to alocate dma memory for vq %d", index);
                  goto out_alloc;
          }
  
- 
          ret = ddi_dma_addr_bind_handle(vq->vq_dma_handle, NULL,
!             (caddr_t)vq->vq_vaddr, len,
!             DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
              DDI_DMA_SLEEP, NULL, &vq->vq_dma_cookie, &ncookies);
          if (ret != DDI_DMA_MAPPED) {
                  dev_err(sc->sc_dev, CE_WARN,
                      "Failed to bind dma memory for vq %d", index);
                  goto out_bind;
--- 463,478 ----
          ret = ddi_dma_mem_alloc(vq->vq_dma_handle, allocsize,
              &virtio_vq_devattr, DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL,
              (caddr_t *)&vq->vq_vaddr, &len, &vq->vq_dma_acch);
          if (ret != DDI_SUCCESS) {
                  dev_err(sc->sc_dev, CE_WARN,
!                     "Failed to allocate dma memory for vq %d", index);
                  goto out_alloc;
          }
  
          ret = ddi_dma_addr_bind_handle(vq->vq_dma_handle, NULL,
!             (caddr_t)vq->vq_vaddr, len, DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
              DDI_DMA_SLEEP, NULL, &vq->vq_dma_cookie, &ncookies);
          if (ret != DDI_DMA_MAPPED) {
                  dev_err(sc->sc_dev, CE_WARN,
                      "Failed to bind dma memory for vq %d", index);
                  goto out_bind;
*** 530,540 ****
          ret = virtio_init_vq(sc, vq);
          if (ret)
                  goto out_init;
  
          dev_debug(sc->sc_dev, CE_NOTE,
!             "Allocated %d entries for vq %d:%s (%d incdirect descs)",
              vq_size, index, name, indirect_num * vq_size);
  
          return (vq);
  
  out_init:
--- 515,525 ----
          ret = virtio_init_vq(sc, vq);
          if (ret)
                  goto out_init;
  
          dev_debug(sc->sc_dev, CE_NOTE,
!             "Allocated %d entries for vq %d:%s (%d indirect descs)",
              vq_size, index, name, indirect_num * vq_size);
  
          return (vq);
  
  out_init:
*** 548,558 ****
          kmem_free(vq, sizeof (struct virtqueue));
  out:
          return (NULL);
  }
  
- 
  void
  virtio_free_vq(struct virtqueue *vq)
  {
          struct virtio_softc *sc = vq->vq_owner;
          int i;
--- 533,542 ----
*** 646,666 ****
          desc->flags = 0;
  
          /* 'write' - from the driver's point of view */
          if (!write)
                  desc->flags = VRING_DESC_F_WRITE;
- 
- 
  }
  
  void
  virtio_ve_set(struct vq_entry *qe, uint64_t paddr, uint32_t len,
      boolean_t write)
  {
          virtio_ve_set_desc(qe->qe_desc, paddr, len, write);
  }
  
  void
  virtio_ve_add_indirect_buf(struct vq_entry *qe, uint64_t paddr, uint32_t len,
      boolean_t write)
  {
          struct vring_desc *indirect_desc;
--- 630,654 ----
          desc->flags = 0;
  
          /* 'write' - from the driver's point of view */
          if (!write)
                  desc->flags = VRING_DESC_F_WRITE;
  }
  
  void
  virtio_ve_set(struct vq_entry *qe, uint64_t paddr, uint32_t len,
      boolean_t write)
  {
          virtio_ve_set_desc(qe->qe_desc, paddr, len, write);
  }
  
+ unsigned int
+ virtio_ve_indirect_available(struct vq_entry *qe)
+ {
+         return (qe->qe_queue->vq_indirect_num - (qe->qe_indirect_next - 1));
+ }
+ 
  void
  virtio_ve_add_indirect_buf(struct vq_entry *qe, uint64_t paddr, uint32_t len,
      boolean_t write)
  {
          struct vring_desc *indirect_desc;
*** 700,715 ****
          membar_producer();
  
          /* Make sure we see the flags update */
          membar_consumer();
  
!         if (!(vq->vq_used->flags & VRING_USED_F_NO_NOTIFY))
                  ddi_put16(vsc->sc_ioh,
                      /* LINTED E_BAD_PTR_CAST_ALIGN */
                      (uint16_t *)(vsc->sc_io_addr +
                      VIRTIO_CONFIG_QUEUE_NOTIFY),
                      vq->vq_index);
  }
  
  void
  virtio_push_chain(struct vq_entry *qe, boolean_t sync)
  {
--- 688,704 ----
          membar_producer();
  
          /* Make sure we see the flags update */
          membar_consumer();
  
!         if (!(vq->vq_used->flags & VRING_USED_F_NO_NOTIFY)) {
                  ddi_put16(vsc->sc_ioh,
                      /* LINTED E_BAD_PTR_CAST_ALIGN */
                      (uint16_t *)(vsc->sc_io_addr +
                      VIRTIO_CONFIG_QUEUE_NOTIFY),
                      vq->vq_index);
+         }
  }
  
  void
  virtio_push_chain(struct vq_entry *qe, boolean_t sync)
  {
*** 771,781 ****
                  virtio_sync_vq(vq);
  
          mutex_exit(&vq->vq_avail_lock);
  }
  
! /* Get a chain of descriptors from the used ring, if one is available. */
  struct vq_entry *
  virtio_pull_chain(struct virtqueue *vq, uint32_t *len)
  {
          struct vq_entry *head;
          int slot;
--- 760,772 ----
                  virtio_sync_vq(vq);
  
          mutex_exit(&vq->vq_avail_lock);
  }
  
! /*
!  * Get a chain of descriptors from the used ring, if one is available.
!  */
  struct vq_entry *
  virtio_pull_chain(struct virtqueue *vq, uint32_t *len)
  {
          struct vq_entry *head;
          int slot;
*** 817,827 ****
          do {
                  ASSERT(qe->qe_queue == vq);
                  tmp = qe->qe_next;
                  vq_free_entry(vq, qe);
                  qe = tmp;
!         } while (tmp);
  }
  
  void
  virtio_ventry_stick(struct vq_entry *first, struct vq_entry *second)
  {
--- 808,818 ----
          do {
                  ASSERT(qe->qe_queue == vq);
                  tmp = qe->qe_next;
                  vq_free_entry(vq, qe);
                  qe = tmp;
!         } while (tmp != NULL);
  }
  
  void
  virtio_ventry_stick(struct vq_entry *first, struct vq_entry *second)
  {
*** 829,840 ****
  }
  
  static int
  virtio_register_msi(struct virtio_softc *sc,
      struct virtio_int_handler *config_handler,
!     struct virtio_int_handler vq_handlers[],
!     int intr_types)
  {
          int count, actual;
          int int_type;
          int i;
          int handler_count;
--- 820,830 ----
  }
  
  static int
  virtio_register_msi(struct virtio_softc *sc,
      struct virtio_int_handler *config_handler,
!     struct virtio_int_handler vq_handlers[], int intr_types)
  {
          int count, actual;
          int int_type;
          int i;
          int handler_count;
*** 850,860 ****
              vq_handlers && vq_handlers[handler_count].vh_func;
              handler_count++)
                  ;
  
          /* +1 if there is a config change handler. */
!         if (config_handler)
                  handler_count++;
  
          /* Number of MSIs supported by the device. */
          ret = ddi_intr_get_nintrs(sc->sc_dev, int_type, &count);
          if (ret != DDI_SUCCESS) {
--- 840,850 ----
              vq_handlers && vq_handlers[handler_count].vh_func;
              handler_count++)
                  ;
  
          /* +1 if there is a config change handler. */
!         if (config_handler != NULL)
                  handler_count++;
  
          /* Number of MSIs supported by the device. */
          ret = ddi_intr_get_nintrs(sc->sc_dev, int_type, &count);
          if (ret != DDI_SUCCESS) {
*** 866,877 ****
           * Those who try to register more handlers then the device
           * supports shall suffer.
           */
          ASSERT(handler_count <= count);
  
!         sc->sc_intr_htable = kmem_zalloc(
!             sizeof (ddi_intr_handle_t) * handler_count, KM_SLEEP);
  
          ret = ddi_intr_alloc(sc->sc_dev, sc->sc_intr_htable, int_type, 0,
              handler_count, &actual, DDI_INTR_ALLOC_NORMAL);
          if (ret != DDI_SUCCESS) {
                  dev_err(sc->sc_dev, CE_WARN, "Failed to allocate MSI: %d", ret);
--- 856,867 ----
           * Those who try to register more handlers then the device
           * supports shall suffer.
           */
          ASSERT(handler_count <= count);
  
!         sc->sc_intr_htable = kmem_zalloc(sizeof (ddi_intr_handle_t) *
!             handler_count, KM_SLEEP);
  
          ret = ddi_intr_alloc(sc->sc_dev, sc->sc_intr_htable, int_type, 0,
              handler_count, &actual, DDI_INTR_ALLOC_NORMAL);
          if (ret != DDI_SUCCESS) {
                  dev_err(sc->sc_dev, CE_WARN, "Failed to allocate MSI: %d", ret);
*** 885,895 ****
                  goto out_msi_available;
          }
  
          sc->sc_intr_num = handler_count;
          sc->sc_intr_config = B_FALSE;
!         if (config_handler) {
                  sc->sc_intr_config = B_TRUE;
          }
  
          /* Assume they are all same priority */
          ret = ddi_intr_get_pri(sc->sc_intr_htable[0], &sc->sc_intr_prio);
--- 875,885 ----
                  goto out_msi_available;
          }
  
          sc->sc_intr_num = handler_count;
          sc->sc_intr_config = B_FALSE;
!         if (config_handler != NULL) {
                  sc->sc_intr_config = B_TRUE;
          }
  
          /* Assume they are all same priority */
          ret = ddi_intr_get_pri(sc->sc_intr_htable[0], &sc->sc_intr_prio);
*** 899,910 ****
          }
  
          /* Add the vq handlers */
          for (i = 0; vq_handlers[i].vh_func; i++) {
                  ret = ddi_intr_add_handler(sc->sc_intr_htable[i],
!                     vq_handlers[i].vh_func,
!                     sc, vq_handlers[i].vh_priv);
                  if (ret != DDI_SUCCESS) {
                          dev_err(sc->sc_dev, CE_WARN,
                              "ddi_intr_add_handler failed");
                          /* Remove the handlers that succeeded. */
                          while (--i >= 0) {
--- 889,899 ----
          }
  
          /* Add the vq handlers */
          for (i = 0; vq_handlers[i].vh_func; i++) {
                  ret = ddi_intr_add_handler(sc->sc_intr_htable[i],
!                     vq_handlers[i].vh_func, sc, vq_handlers[i].vh_priv);
                  if (ret != DDI_SUCCESS) {
                          dev_err(sc->sc_dev, CE_WARN,
                              "ddi_intr_add_handler failed");
                          /* Remove the handlers that succeeded. */
                          while (--i >= 0) {
*** 914,927 ****
                          goto out_add_handlers;
                  }
          }
  
          /* Don't forget the config handler */
!         if (config_handler) {
                  ret = ddi_intr_add_handler(sc->sc_intr_htable[i],
!                     config_handler->vh_func,
!                     sc, config_handler->vh_priv);
                  if (ret != DDI_SUCCESS) {
                          dev_err(sc->sc_dev, CE_WARN,
                              "ddi_intr_add_handler failed");
                          /* Remove the handlers that succeeded. */
                          while (--i >= 0) {
--- 903,915 ----
                          goto out_add_handlers;
                  }
          }
  
          /* Don't forget the config handler */
!         if (config_handler != NULL) {
                  ret = ddi_intr_add_handler(sc->sc_intr_htable[i],
!                     config_handler->vh_func, sc, config_handler->vh_priv);
                  if (ret != DDI_SUCCESS) {
                          dev_err(sc->sc_dev, CE_WARN,
                              "ddi_intr_add_handler failed");
                          /* Remove the handlers that succeeded. */
                          while (--i >= 0) {
*** 933,944 ****
          }
  
          /* We know we are using MSI, so set the config offset. */
          sc->sc_config_offset = VIRTIO_CONFIG_DEVICE_CONFIG_MSI;
  
!         ret = ddi_intr_get_cap(sc->sc_intr_htable[0],
!             &sc->sc_intr_cap);
          /* Just in case. */
          if (ret != DDI_SUCCESS)
                  sc->sc_intr_cap = 0;
  
  out_add_handlers:
--- 921,931 ----
          }
  
          /* We know we are using MSI, so set the config offset. */
          sc->sc_config_offset = VIRTIO_CONFIG_DEVICE_CONFIG_MSI;
  
!         ret = ddi_intr_get_cap(sc->sc_intr_htable[0], &sc->sc_intr_cap);
          /* Just in case. */
          if (ret != DDI_SUCCESS)
                  sc->sc_intr_cap = 0;
  
  out_add_handlers:
*** 1006,1037 ****
          for (vq_handler_count = 0;
              vq_handlers && vq_handlers[vq_handler_count].vh_func;
              vq_handler_count++)
                  ;
  
!         if (config_handler)
                  config_handler_count = 1;
  
          vhc = kmem_zalloc(sizeof (struct virtio_handler_container) +
!             sizeof (struct virtio_int_handler) * vq_handler_count,
!             KM_SLEEP);
  
          vhc->nhandlers = vq_handler_count;
          (void) memcpy(vhc->vq_handlers, vq_handlers,
              sizeof (struct virtio_int_handler) * vq_handler_count);
  
!         if (config_handler) {
                  (void) memcpy(&vhc->config_handler, config_handler,
                      sizeof (struct virtio_int_handler));
          }
  
          /* Just a single entry for a single interrupt. */
          sc->sc_intr_htable = kmem_zalloc(sizeof (ddi_intr_handle_t), KM_SLEEP);
  
          ret = ddi_intr_alloc(sc->sc_dev, sc->sc_intr_htable,
!             DDI_INTR_TYPE_FIXED, 0, 1, &actual,
!             DDI_INTR_ALLOC_NORMAL);
          if (ret != DDI_SUCCESS) {
                  dev_err(sc->sc_dev, CE_WARN,
                      "Failed to allocate a fixed interrupt: %d", ret);
                  goto out_int_alloc;
          }
--- 993,1022 ----
          for (vq_handler_count = 0;
              vq_handlers && vq_handlers[vq_handler_count].vh_func;
              vq_handler_count++)
                  ;
  
!         if (config_handler != NULL)
                  config_handler_count = 1;
  
          vhc = kmem_zalloc(sizeof (struct virtio_handler_container) +
!             sizeof (struct virtio_int_handler) * vq_handler_count, KM_SLEEP);
  
          vhc->nhandlers = vq_handler_count;
          (void) memcpy(vhc->vq_handlers, vq_handlers,
              sizeof (struct virtio_int_handler) * vq_handler_count);
  
!         if (config_handler != NULL) {
                  (void) memcpy(&vhc->config_handler, config_handler,
                      sizeof (struct virtio_int_handler));
          }
  
          /* Just a single entry for a single interrupt. */
          sc->sc_intr_htable = kmem_zalloc(sizeof (ddi_intr_handle_t), KM_SLEEP);
  
          ret = ddi_intr_alloc(sc->sc_dev, sc->sc_intr_htable,
!             DDI_INTR_TYPE_FIXED, 0, 1, &actual, DDI_INTR_ALLOC_NORMAL);
          if (ret != DDI_SUCCESS) {
                  dev_err(sc->sc_dev, CE_WARN,
                      "Failed to allocate a fixed interrupt: %d", ret);
                  goto out_int_alloc;
          }
*** 1109,1119 ****
  
  out_inttype:
          return (ret);
  }
  
- 
  static int
  virtio_enable_msi(struct virtio_softc *sc)
  {
          int ret, i;
          int vq_handler_count = sc->sc_intr_num;
--- 1094,1103 ----
*** 1149,1158 ****
--- 1133,1143 ----
          }
  
          /* Bind the allocated MSI to the queues and config */
          for (i = 0; i < vq_handler_count; i++) {
                  int check;
+ 
                  ddi_put16(sc->sc_ioh,
                      /* LINTED E_BAD_PTR_CAST_ALIGN */
                      (uint16_t *)(sc->sc_io_addr +
                      VIRTIO_CONFIG_QUEUE_SELECT), i);
  
*** 1164,1182 ****
                  check = ddi_get16(sc->sc_ioh,
                      /* LINTED E_BAD_PTR_CAST_ALIGN */
                      (uint16_t *)(sc->sc_io_addr +
                      VIRTIO_CONFIG_QUEUE_VECTOR));
                  if (check != i) {
!                         dev_err(sc->sc_dev, CE_WARN, "Failed to bind handler"
                              "for VQ %d, MSI %d. Check = %x", i, i, check);
                          ret = ENODEV;
                          goto out_bind;
                  }
          }
  
          if (sc->sc_intr_config) {
                  int check;
                  ddi_put16(sc->sc_ioh,
                      /* LINTED E_BAD_PTR_CAST_ALIGN */
                      (uint16_t *)(sc->sc_io_addr +
                      VIRTIO_CONFIG_CONFIG_VECTOR), i);
  
--- 1149,1168 ----
                  check = ddi_get16(sc->sc_ioh,
                      /* LINTED E_BAD_PTR_CAST_ALIGN */
                      (uint16_t *)(sc->sc_io_addr +
                      VIRTIO_CONFIG_QUEUE_VECTOR));
                  if (check != i) {
!                         dev_err(sc->sc_dev, CE_WARN, "Failed to bind handler "
                              "for VQ %d, MSI %d. Check = %x", i, i, check);
                          ret = ENODEV;
                          goto out_bind;
                  }
          }
  
          if (sc->sc_intr_config) {
                  int check;
+ 
                  ddi_put16(sc->sc_ioh,
                      /* LINTED E_BAD_PTR_CAST_ALIGN */
                      (uint16_t *)(sc->sc_io_addr +
                      VIRTIO_CONFIG_CONFIG_VECTOR), i);
  
*** 1217,1234 ****
  
  out_enable:
          return (ret);
  }
  
! static int virtio_enable_intx(struct virtio_softc *sc)
  {
          int ret;
  
          ret = ddi_intr_enable(sc->sc_intr_htable[0]);
!         if (ret != DDI_SUCCESS)
                  dev_err(sc->sc_dev, CE_WARN,
                      "Failed to enable interrupt: %d", ret);
          return (ret);
  }
  
  /*
   * We can't enable/disable individual handlers in the INTx case so do
--- 1203,1223 ----
  
  out_enable:
          return (ret);
  }
  
! static int
! virtio_enable_intx(struct virtio_softc *sc)
  {
          int ret;
  
          ret = ddi_intr_enable(sc->sc_intr_htable[0]);
!         if (ret != DDI_SUCCESS) {
                  dev_err(sc->sc_dev, CE_WARN,
                      "Failed to enable interrupt: %d", ret);
+         }
+ 
          return (ret);
  }
  
  /*
   * We can't enable/disable individual handlers in the INTx case so do
*** 1280,1300 ****
          if (sc->sc_intr_cap & DDI_INTR_FLAG_BLOCK) {
                  ret = ddi_intr_block_disable(sc->sc_intr_htable,
                      sc->sc_intr_num);
                  if (ret != DDI_SUCCESS) {
                          dev_err(sc->sc_dev, CE_WARN,
!                             "Failed to disable MSIs, won't be able to"
                              "reuse next time");
                  }
          } else {
                  for (i = 0; i < sc->sc_intr_num; i++) {
                          ret = ddi_intr_disable(sc->sc_intr_htable[i]);
                          if (ret != DDI_SUCCESS) {
                                  dev_err(sc->sc_dev, CE_WARN,
                                      "Failed to disable interrupt %d, "
                                      "won't be able to reuse", i);
- 
                          }
                  }
          }
  
  
--- 1269,1288 ----
          if (sc->sc_intr_cap & DDI_INTR_FLAG_BLOCK) {
                  ret = ddi_intr_block_disable(sc->sc_intr_htable,
                      sc->sc_intr_num);
                  if (ret != DDI_SUCCESS) {
                          dev_err(sc->sc_dev, CE_WARN,
!                             "Failed to disable MSIs, won't be able to "
                              "reuse next time");
                  }
          } else {
                  for (i = 0; i < sc->sc_intr_num; i++) {
                          ret = ddi_intr_disable(sc->sc_intr_htable[i]);
                          if (ret != DDI_SUCCESS) {
                                  dev_err(sc->sc_dev, CE_WARN,
                                      "Failed to disable interrupt %d, "
                                      "won't be able to reuse", i);
                          }
                  }
          }
  
  
*** 1303,1316 ****
          }
  
          for (i = 0; i < sc->sc_intr_num; i++)
                  (void) ddi_intr_free(sc->sc_intr_htable[i]);
  
!         kmem_free(sc->sc_intr_htable,
!             sizeof (ddi_intr_handle_t) * sc->sc_intr_num);
  
- 
          /* After disabling interrupts, the config offset is non-MSI. */
          sc->sc_config_offset = VIRTIO_CONFIG_DEVICE_CONFIG_NOMSI;
  }
  
  /*
--- 1291,1303 ----
          }
  
          for (i = 0; i < sc->sc_intr_num; i++)
                  (void) ddi_intr_free(sc->sc_intr_htable[i]);
  
!         kmem_free(sc->sc_intr_htable, sizeof (ddi_intr_handle_t) *
!             sc->sc_intr_num);
  
          /* After disabling interrupts, the config offset is non-MSI. */
          sc->sc_config_offset = VIRTIO_CONFIG_DEVICE_CONFIG_NOMSI;
  }
  
  /*