Commit d6130604 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'for-linus-5.19-rc1-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/xen/tip

Pull xen updates from Juergen Gross:

 - decouple the PV interface from kernel internals in the Xen
   scsifront/scsiback pv drivers

 - harden the Xen scsifront PV driver against a malicious backend driver

 - simplify Xen PV frontend driver ring page setup

 - support Xen setups with multiple domains created at boot time to
   tolerate Xenstore coming up late

 - two small cleanup patches

* tag 'for-linus-5.19-rc1-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/xen/tip: (29 commits)
  xen: add support for initializing xenstore later as HVM domain
  xen: sync xs_wire.h header with upstream xen
  x86: xen: remove STACK_FRAME_NON_STANDARD from xen_cpuid
  xen-blk{back,front}: Update contact points for buffer_squeeze_duration_ms and feature_persistent
  xen/xenbus: eliminate xenbus_grant_ring()
  xen/sndfront: use xenbus_setup_ring() and xenbus_teardown_ring()
  xen/usbfront: use xenbus_setup_ring() and xenbus_teardown_ring()
  xen/scsifront: use xenbus_setup_ring() and xenbus_teardown_ring()
  xen/pcifront: use xenbus_setup_ring() and xenbus_teardown_ring()
  xen/drmfront: use xenbus_setup_ring() and xenbus_teardown_ring()
  xen/tpmfront: use xenbus_setup_ring() and xenbus_teardown_ring()
  xen/netfront: use xenbus_setup_ring() and xenbus_teardown_ring()
  xen/blkfront: use xenbus_setup_ring() and xenbus_teardown_ring()
  xen/xenbus: add xenbus_setup_ring() service function
  xen: update ring.h
  xen/shbuf: switch xen-front-pgdir-shbuf to use INVALID_GRANT_REF
  xen/dmabuf: switch gntdev-dmabuf to use INVALID_GRANT_REF
  xen/sound: switch xen_snd_front to use INVALID_GRANT_REF
  xen/drm: switch xen_drm_front to use INVALID_GRANT_REF
  xen/usb: switch xen-hcd to use INVALID_GRANT_REF
  ...
parents 8443516d 5b335394
...@@ -29,7 +29,7 @@ Description: ...@@ -29,7 +29,7 @@ Description:
What: /sys/module/xen_blkback/parameters/buffer_squeeze_duration_ms What: /sys/module/xen_blkback/parameters/buffer_squeeze_duration_ms
Date: December 2019 Date: December 2019
KernelVersion: 5.6 KernelVersion: 5.6
Contact: SeongJae Park <sj@kernel.org> Contact: Maximilian Heyne <mheyne@amazon.de>
Description: Description:
When memory pressure is reported to blkback this option When memory pressure is reported to blkback this option
controls the duration in milliseconds that blkback will not controls the duration in milliseconds that blkback will not
...@@ -39,7 +39,7 @@ Description: ...@@ -39,7 +39,7 @@ Description:
What: /sys/module/xen_blkback/parameters/feature_persistent What: /sys/module/xen_blkback/parameters/feature_persistent
Date: September 2020 Date: September 2020
KernelVersion: 5.10 KernelVersion: 5.10
Contact: SeongJae Park <sj@kernel.org> Contact: Maximilian Heyne <mheyne@amazon.de>
Description: Description:
Whether to enable the persistent grants feature or not. Note Whether to enable the persistent grants feature or not. Note
that this option only takes effect on newly created backends. that this option only takes effect on newly created backends.
......
...@@ -12,7 +12,7 @@ Description: ...@@ -12,7 +12,7 @@ Description:
What: /sys/module/xen_blkfront/parameters/feature_persistent What: /sys/module/xen_blkfront/parameters/feature_persistent
Date: September 2020 Date: September 2020
KernelVersion: 5.10 KernelVersion: 5.10
Contact: SeongJae Park <sj@kernel.org> Contact: Maximilian Heyne <mheyne@amazon.de>
Description: Description:
Whether to enable the persistent grants feature or not. Note Whether to enable the persistent grants feature or not. Note
that this option only takes effect on newly created frontends. that this option only takes effect on newly created frontends.
......
...@@ -30,7 +30,6 @@ ...@@ -30,7 +30,6 @@
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/gfp.h> #include <linux/gfp.h>
#include <linux/edd.h> #include <linux/edd.h>
#include <linux/objtool.h>
#include <xen/xen.h> #include <xen/xen.h>
#include <xen/events.h> #include <xen/events.h>
...@@ -165,7 +164,6 @@ static void xen_cpuid(unsigned int *ax, unsigned int *bx, ...@@ -165,7 +164,6 @@ static void xen_cpuid(unsigned int *ax, unsigned int *bx,
*bx &= maskebx; *bx &= maskebx;
} }
STACK_FRAME_NON_STANDARD(xen_cpuid); /* XEN_EMULATE_PREFIX */
static bool __init xen_check_mwait(void) static bool __init xen_check_mwait(void)
{ {
......
...@@ -229,8 +229,6 @@ static unsigned int nr_minors; ...@@ -229,8 +229,6 @@ static unsigned int nr_minors;
static unsigned long *minors; static unsigned long *minors;
static DEFINE_SPINLOCK(minor_lock); static DEFINE_SPINLOCK(minor_lock);
#define GRANT_INVALID_REF 0
#define PARTS_PER_DISK 16 #define PARTS_PER_DISK 16
#define PARTS_PER_EXT_DISK 256 #define PARTS_PER_EXT_DISK 256
...@@ -321,7 +319,7 @@ static int fill_grant_buffer(struct blkfront_ring_info *rinfo, int num) ...@@ -321,7 +319,7 @@ static int fill_grant_buffer(struct blkfront_ring_info *rinfo, int num)
gnt_list_entry->page = granted_page; gnt_list_entry->page = granted_page;
} }
gnt_list_entry->gref = GRANT_INVALID_REF; gnt_list_entry->gref = INVALID_GRANT_REF;
list_add(&gnt_list_entry->node, &rinfo->grants); list_add(&gnt_list_entry->node, &rinfo->grants);
i++; i++;
} }
...@@ -350,7 +348,7 @@ static struct grant *get_free_grant(struct blkfront_ring_info *rinfo) ...@@ -350,7 +348,7 @@ static struct grant *get_free_grant(struct blkfront_ring_info *rinfo)
node); node);
list_del(&gnt_list_entry->node); list_del(&gnt_list_entry->node);
if (gnt_list_entry->gref != GRANT_INVALID_REF) if (gnt_list_entry->gref != INVALID_GRANT_REF)
rinfo->persistent_gnts_c--; rinfo->persistent_gnts_c--;
return gnt_list_entry; return gnt_list_entry;
...@@ -372,7 +370,7 @@ static struct grant *get_grant(grant_ref_t *gref_head, ...@@ -372,7 +370,7 @@ static struct grant *get_grant(grant_ref_t *gref_head,
struct grant *gnt_list_entry = get_free_grant(rinfo); struct grant *gnt_list_entry = get_free_grant(rinfo);
struct blkfront_info *info = rinfo->dev_info; struct blkfront_info *info = rinfo->dev_info;
if (gnt_list_entry->gref != GRANT_INVALID_REF) if (gnt_list_entry->gref != INVALID_GRANT_REF)
return gnt_list_entry; return gnt_list_entry;
/* Assign a gref to this page */ /* Assign a gref to this page */
...@@ -396,7 +394,7 @@ static struct grant *get_indirect_grant(grant_ref_t *gref_head, ...@@ -396,7 +394,7 @@ static struct grant *get_indirect_grant(grant_ref_t *gref_head,
struct grant *gnt_list_entry = get_free_grant(rinfo); struct grant *gnt_list_entry = get_free_grant(rinfo);
struct blkfront_info *info = rinfo->dev_info; struct blkfront_info *info = rinfo->dev_info;
if (gnt_list_entry->gref != GRANT_INVALID_REF) if (gnt_list_entry->gref != INVALID_GRANT_REF)
return gnt_list_entry; return gnt_list_entry;
/* Assign a gref to this page */ /* Assign a gref to this page */
...@@ -1221,7 +1219,7 @@ static void blkif_free_ring(struct blkfront_ring_info *rinfo) ...@@ -1221,7 +1219,7 @@ static void blkif_free_ring(struct blkfront_ring_info *rinfo)
list_for_each_entry_safe(persistent_gnt, n, list_for_each_entry_safe(persistent_gnt, n,
&rinfo->grants, node) { &rinfo->grants, node) {
list_del(&persistent_gnt->node); list_del(&persistent_gnt->node);
if (persistent_gnt->gref != GRANT_INVALID_REF) { if (persistent_gnt->gref != INVALID_GRANT_REF) {
gnttab_end_foreign_access(persistent_gnt->gref, gnttab_end_foreign_access(persistent_gnt->gref,
0UL); 0UL);
rinfo->persistent_gnts_c--; rinfo->persistent_gnts_c--;
...@@ -1282,15 +1280,8 @@ static void blkif_free_ring(struct blkfront_ring_info *rinfo) ...@@ -1282,15 +1280,8 @@ static void blkif_free_ring(struct blkfront_ring_info *rinfo)
flush_work(&rinfo->work); flush_work(&rinfo->work);
/* Free resources associated with old device channel. */ /* Free resources associated with old device channel. */
for (i = 0; i < info->nr_ring_pages; i++) { xenbus_teardown_ring((void **)&rinfo->ring.sring, info->nr_ring_pages,
if (rinfo->ring_ref[i] != GRANT_INVALID_REF) { rinfo->ring_ref);
gnttab_end_foreign_access(rinfo->ring_ref[i], 0);
rinfo->ring_ref[i] = GRANT_INVALID_REF;
}
}
free_pages_exact(rinfo->ring.sring,
info->nr_ring_pages * XEN_PAGE_SIZE);
rinfo->ring.sring = NULL;
if (rinfo->irq) if (rinfo->irq)
unbind_from_irqhandler(rinfo->irq, rinfo); unbind_from_irqhandler(rinfo->irq, rinfo);
...@@ -1475,7 +1466,7 @@ static int blkif_completion(unsigned long *id, ...@@ -1475,7 +1466,7 @@ static int blkif_completion(unsigned long *id,
* to the tail of the list, so it will not be picked * to the tail of the list, so it will not be picked
* again unless we run out of persistent grants. * again unless we run out of persistent grants.
*/ */
s->grants_used[i]->gref = GRANT_INVALID_REF; s->grants_used[i]->gref = INVALID_GRANT_REF;
list_add_tail(&s->grants_used[i]->node, &rinfo->grants); list_add_tail(&s->grants_used[i]->node, &rinfo->grants);
} }
} }
...@@ -1500,7 +1491,7 @@ static int blkif_completion(unsigned long *id, ...@@ -1500,7 +1491,7 @@ static int blkif_completion(unsigned long *id,
indirect_page = s->indirect_grants[i]->page; indirect_page = s->indirect_grants[i]->page;
list_add(&indirect_page->lru, &rinfo->indirect_pages); list_add(&indirect_page->lru, &rinfo->indirect_pages);
} }
s->indirect_grants[i]->gref = GRANT_INVALID_REF; s->indirect_grants[i]->gref = INVALID_GRANT_REF;
list_add_tail(&s->indirect_grants[i]->node, &rinfo->grants); list_add_tail(&s->indirect_grants[i]->node, &rinfo->grants);
} }
} }
...@@ -1681,30 +1672,16 @@ static int setup_blkring(struct xenbus_device *dev, ...@@ -1681,30 +1672,16 @@ static int setup_blkring(struct xenbus_device *dev,
struct blkfront_ring_info *rinfo) struct blkfront_ring_info *rinfo)
{ {
struct blkif_sring *sring; struct blkif_sring *sring;
int err, i; int err;
struct blkfront_info *info = rinfo->dev_info; struct blkfront_info *info = rinfo->dev_info;
unsigned long ring_size = info->nr_ring_pages * XEN_PAGE_SIZE; unsigned long ring_size = info->nr_ring_pages * XEN_PAGE_SIZE;
grant_ref_t gref[XENBUS_MAX_RING_GRANTS];
for (i = 0; i < info->nr_ring_pages; i++)
rinfo->ring_ref[i] = GRANT_INVALID_REF;
sring = alloc_pages_exact(ring_size, GFP_NOIO); err = xenbus_setup_ring(dev, GFP_NOIO, (void **)&sring,
if (!sring) { info->nr_ring_pages, rinfo->ring_ref);
xenbus_dev_fatal(dev, -ENOMEM, "allocating shared ring"); if (err)
return -ENOMEM;
}
SHARED_RING_INIT(sring);
FRONT_RING_INIT(&rinfo->ring, sring, ring_size);
err = xenbus_grant_ring(dev, rinfo->ring.sring, info->nr_ring_pages, gref);
if (err < 0) {
free_pages_exact(sring, ring_size);
rinfo->ring.sring = NULL;
goto fail; goto fail;
}
for (i = 0; i < info->nr_ring_pages; i++) XEN_FRONT_RING_INIT(&rinfo->ring, sring, ring_size);
rinfo->ring_ref[i] = gref[i];
err = xenbus_alloc_evtchn(dev, &rinfo->evtchn); err = xenbus_alloc_evtchn(dev, &rinfo->evtchn);
if (err) if (err)
...@@ -2544,13 +2521,13 @@ static void purge_persistent_grants(struct blkfront_info *info) ...@@ -2544,13 +2521,13 @@ static void purge_persistent_grants(struct blkfront_info *info)
list_for_each_entry_safe(gnt_list_entry, tmp, &rinfo->grants, list_for_each_entry_safe(gnt_list_entry, tmp, &rinfo->grants,
node) { node) {
if (gnt_list_entry->gref == GRANT_INVALID_REF || if (gnt_list_entry->gref == INVALID_GRANT_REF ||
!gnttab_try_end_foreign_access(gnt_list_entry->gref)) !gnttab_try_end_foreign_access(gnt_list_entry->gref))
continue; continue;
list_del(&gnt_list_entry->node); list_del(&gnt_list_entry->node);
rinfo->persistent_gnts_c--; rinfo->persistent_gnts_c--;
gnt_list_entry->gref = GRANT_INVALID_REF; gnt_list_entry->gref = INVALID_GRANT_REF;
list_add_tail(&gnt_list_entry->node, &grants); list_add_tail(&gnt_list_entry->node, &grants);
} }
......
...@@ -253,20 +253,12 @@ static int setup_ring(struct xenbus_device *dev, struct tpm_private *priv) ...@@ -253,20 +253,12 @@ static int setup_ring(struct xenbus_device *dev, struct tpm_private *priv)
struct xenbus_transaction xbt; struct xenbus_transaction xbt;
const char *message = NULL; const char *message = NULL;
int rv; int rv;
grant_ref_t gref;
priv->shr = (void *)__get_free_page(GFP_KERNEL|__GFP_ZERO); rv = xenbus_setup_ring(dev, GFP_KERNEL, (void **)&priv->shr, 1,
if (!priv->shr) { &priv->ring_ref);
xenbus_dev_fatal(dev, -ENOMEM, "allocating shared ring");
return -ENOMEM;
}
rv = xenbus_grant_ring(dev, priv->shr, 1, &gref);
if (rv < 0) if (rv < 0)
return rv; return rv;
priv->ring_ref = gref;
rv = xenbus_alloc_evtchn(dev, &priv->evtchn); rv = xenbus_alloc_evtchn(dev, &priv->evtchn);
if (rv) if (rv)
return rv; return rv;
...@@ -331,11 +323,7 @@ static void ring_free(struct tpm_private *priv) ...@@ -331,11 +323,7 @@ static void ring_free(struct tpm_private *priv)
if (!priv) if (!priv)
return; return;
if (priv->ring_ref) xenbus_teardown_ring((void **)&priv->shr, 1, &priv->ring_ref);
gnttab_end_foreign_access(priv->ring_ref,
(unsigned long)priv->shr);
else
free_page((unsigned long)priv->shr);
if (priv->irq) if (priv->irq)
unbind_from_irqhandler(priv->irq, priv); unbind_from_irqhandler(priv->irq, priv);
......
...@@ -80,15 +80,6 @@ struct drm_pending_vblank_event; ...@@ -80,15 +80,6 @@ struct drm_pending_vblank_event;
/* timeout in ms to wait for backend to respond */ /* timeout in ms to wait for backend to respond */
#define XEN_DRM_FRONT_WAIT_BACK_MS 3000 #define XEN_DRM_FRONT_WAIT_BACK_MS 3000
#ifndef GRANT_INVALID_REF
/*
* Note on usage of grant reference 0 as invalid grant reference:
* grant reference 0 is valid, but never exposed to a PV driver,
* because of the fact it is already in use/reserved by the PV console.
*/
#define GRANT_INVALID_REF 0
#endif
struct xen_drm_front_info { struct xen_drm_front_info {
struct xenbus_device *xb_dev; struct xenbus_device *xb_dev;
struct xen_drm_front_drm_info *drm_info; struct xen_drm_front_drm_info *drm_info;
......
...@@ -123,12 +123,12 @@ static irqreturn_t evtchnl_interrupt_evt(int irq, void *dev_id) ...@@ -123,12 +123,12 @@ static irqreturn_t evtchnl_interrupt_evt(int irq, void *dev_id)
static void evtchnl_free(struct xen_drm_front_info *front_info, static void evtchnl_free(struct xen_drm_front_info *front_info,
struct xen_drm_front_evtchnl *evtchnl) struct xen_drm_front_evtchnl *evtchnl)
{ {
unsigned long page = 0; void *page = NULL;
if (evtchnl->type == EVTCHNL_TYPE_REQ) if (evtchnl->type == EVTCHNL_TYPE_REQ)
page = (unsigned long)evtchnl->u.req.ring.sring; page = evtchnl->u.req.ring.sring;
else if (evtchnl->type == EVTCHNL_TYPE_EVT) else if (evtchnl->type == EVTCHNL_TYPE_EVT)
page = (unsigned long)evtchnl->u.evt.page; page = evtchnl->u.evt.page;
if (!page) if (!page)
return; return;
...@@ -147,8 +147,7 @@ static void evtchnl_free(struct xen_drm_front_info *front_info, ...@@ -147,8 +147,7 @@ static void evtchnl_free(struct xen_drm_front_info *front_info,
xenbus_free_evtchn(front_info->xb_dev, evtchnl->port); xenbus_free_evtchn(front_info->xb_dev, evtchnl->port);
/* end access and free the page */ /* end access and free the page */
if (evtchnl->gref != GRANT_INVALID_REF) xenbus_teardown_ring(&page, 1, &evtchnl->gref);
gnttab_end_foreign_access(evtchnl->gref, page);
memset(evtchnl, 0, sizeof(*evtchnl)); memset(evtchnl, 0, sizeof(*evtchnl));
} }
...@@ -158,8 +157,7 @@ static int evtchnl_alloc(struct xen_drm_front_info *front_info, int index, ...@@ -158,8 +157,7 @@ static int evtchnl_alloc(struct xen_drm_front_info *front_info, int index,
enum xen_drm_front_evtchnl_type type) enum xen_drm_front_evtchnl_type type)
{ {
struct xenbus_device *xb_dev = front_info->xb_dev; struct xenbus_device *xb_dev = front_info->xb_dev;
unsigned long page; void *page;
grant_ref_t gref;
irq_handler_t handler; irq_handler_t handler;
int ret; int ret;
...@@ -168,44 +166,25 @@ static int evtchnl_alloc(struct xen_drm_front_info *front_info, int index, ...@@ -168,44 +166,25 @@ static int evtchnl_alloc(struct xen_drm_front_info *front_info, int index,
evtchnl->index = index; evtchnl->index = index;
evtchnl->front_info = front_info; evtchnl->front_info = front_info;
evtchnl->state = EVTCHNL_STATE_DISCONNECTED; evtchnl->state = EVTCHNL_STATE_DISCONNECTED;
evtchnl->gref = GRANT_INVALID_REF;
page = get_zeroed_page(GFP_NOIO | __GFP_HIGH); ret = xenbus_setup_ring(xb_dev, GFP_NOIO | __GFP_HIGH, &page,
if (!page) { 1, &evtchnl->gref);
ret = -ENOMEM; if (ret)
goto fail; goto fail;
}
if (type == EVTCHNL_TYPE_REQ) { if (type == EVTCHNL_TYPE_REQ) {
struct xen_displif_sring *sring; struct xen_displif_sring *sring;
init_completion(&evtchnl->u.req.completion); init_completion(&evtchnl->u.req.completion);
mutex_init(&evtchnl->u.req.req_io_lock); mutex_init(&evtchnl->u.req.req_io_lock);
sring = (struct xen_displif_sring *)page; sring = page;
SHARED_RING_INIT(sring); XEN_FRONT_RING_INIT(&evtchnl->u.req.ring, sring, XEN_PAGE_SIZE);
FRONT_RING_INIT(&evtchnl->u.req.ring, sring, XEN_PAGE_SIZE);
ret = xenbus_grant_ring(xb_dev, sring, 1, &gref);
if (ret < 0) {
evtchnl->u.req.ring.sring = NULL;
free_page(page);
goto fail;
}
handler = evtchnl_interrupt_ctrl; handler = evtchnl_interrupt_ctrl;
} else { } else {
ret = gnttab_grant_foreign_access(xb_dev->otherend_id, evtchnl->u.evt.page = page;
virt_to_gfn((void *)page), 0);
if (ret < 0) {
free_page(page);
goto fail;
}
evtchnl->u.evt.page = (struct xendispl_event_page *)page;
gref = ret;
handler = evtchnl_interrupt_evt; handler = evtchnl_interrupt_evt;
} }
evtchnl->gref = gref;
ret = xenbus_alloc_evtchn(xb_dev, &evtchnl->port); ret = xenbus_alloc_evtchn(xb_dev, &evtchnl->port);
if (ret < 0) if (ret < 0)
......
...@@ -78,8 +78,6 @@ struct netfront_cb { ...@@ -78,8 +78,6 @@ struct netfront_cb {
#define RX_COPY_THRESHOLD 256 #define RX_COPY_THRESHOLD 256
#define GRANT_INVALID_REF 0
#define NET_TX_RING_SIZE __CONST_RING_SIZE(xen_netif_tx, XEN_PAGE_SIZE) #define NET_TX_RING_SIZE __CONST_RING_SIZE(xen_netif_tx, XEN_PAGE_SIZE)
#define NET_RX_RING_SIZE __CONST_RING_SIZE(xen_netif_rx, XEN_PAGE_SIZE) #define NET_RX_RING_SIZE __CONST_RING_SIZE(xen_netif_rx, XEN_PAGE_SIZE)
...@@ -224,7 +222,7 @@ static grant_ref_t xennet_get_rx_ref(struct netfront_queue *queue, ...@@ -224,7 +222,7 @@ static grant_ref_t xennet_get_rx_ref(struct netfront_queue *queue,
{ {
int i = xennet_rxidx(ri); int i = xennet_rxidx(ri);
grant_ref_t ref = queue->grant_rx_ref[i]; grant_ref_t ref = queue->grant_rx_ref[i];
queue->grant_rx_ref[i] = GRANT_INVALID_REF; queue->grant_rx_ref[i] = INVALID_GRANT_REF;
return ref; return ref;
} }
...@@ -432,7 +430,7 @@ static bool xennet_tx_buf_gc(struct netfront_queue *queue) ...@@ -432,7 +430,7 @@ static bool xennet_tx_buf_gc(struct netfront_queue *queue)
} }
gnttab_release_grant_reference( gnttab_release_grant_reference(
&queue->gref_tx_head, queue->grant_tx_ref[id]); &queue->gref_tx_head, queue->grant_tx_ref[id]);
queue->grant_tx_ref[id] = GRANT_INVALID_REF; queue->grant_tx_ref[id] = INVALID_GRANT_REF;
queue->grant_tx_page[id] = NULL; queue->grant_tx_page[id] = NULL;
add_id_to_list(&queue->tx_skb_freelist, queue->tx_link, id); add_id_to_list(&queue->tx_skb_freelist, queue->tx_link, id);
dev_kfree_skb_irq(skb); dev_kfree_skb_irq(skb);
...@@ -868,7 +866,7 @@ static void xennet_set_rx_rsp_cons(struct netfront_queue *queue, RING_IDX val) ...@@ -868,7 +866,7 @@ static void xennet_set_rx_rsp_cons(struct netfront_queue *queue, RING_IDX val)
spin_lock_irqsave(&queue->rx_cons_lock, flags); spin_lock_irqsave(&queue->rx_cons_lock, flags);
queue->rx.rsp_cons = val; queue->rx.rsp_cons = val;
queue->rx_rsp_unconsumed = RING_HAS_UNCONSUMED_RESPONSES(&queue->rx); queue->rx_rsp_unconsumed = XEN_RING_NR_UNCONSUMED_RESPONSES(&queue->rx);
spin_unlock_irqrestore(&queue->rx_cons_lock, flags); spin_unlock_irqrestore(&queue->rx_cons_lock, flags);
} }
...@@ -1021,7 +1019,7 @@ static int xennet_get_responses(struct netfront_queue *queue, ...@@ -1021,7 +1019,7 @@ static int xennet_get_responses(struct netfront_queue *queue,
* the backend driver. In future this should flag the bad * the backend driver. In future this should flag the bad
* situation to the system controller to reboot the backend. * situation to the system controller to reboot the backend.
*/ */
if (ref == GRANT_INVALID_REF) { if (ref == INVALID_GRANT_REF) {
if (net_ratelimit()) if (net_ratelimit())
dev_warn(dev, "Bad rx response id %d.\n", dev_warn(dev, "Bad rx response id %d.\n",
rx->id); rx->id);
...@@ -1390,7 +1388,7 @@ static void xennet_release_tx_bufs(struct netfront_queue *queue) ...@@ -1390,7 +1388,7 @@ static void xennet_release_tx_bufs(struct netfront_queue *queue)
gnttab_end_foreign_access(queue->grant_tx_ref[i], gnttab_end_foreign_access(queue->grant_tx_ref[i],
(unsigned long)page_address(queue->grant_tx_page[i])); (unsigned long)page_address(queue->grant_tx_page[i]));
queue->grant_tx_page[i] = NULL; queue->grant_tx_page[i] = NULL;
queue->grant_tx_ref[i] = GRANT_INVALID_REF; queue->grant_tx_ref[i] = INVALID_GRANT_REF;
add_id_to_list(&queue->tx_skb_freelist, queue->tx_link, i); add_id_to_list(&queue->tx_skb_freelist, queue->tx_link, i);
dev_kfree_skb_irq(skb); dev_kfree_skb_irq(skb);
} }
...@@ -1411,7 +1409,7 @@ static void xennet_release_rx_bufs(struct netfront_queue *queue) ...@@ -1411,7 +1409,7 @@ static void xennet_release_rx_bufs(struct netfront_queue *queue)
continue; continue;
ref = queue->grant_rx_ref[id]; ref = queue->grant_rx_ref[id];
if (ref == GRANT_INVALID_REF) if (ref == INVALID_GRANT_REF)
continue; continue;
page = skb_frag_page(&skb_shinfo(skb)->frags[0]); page = skb_frag_page(&skb_shinfo(skb)->frags[0]);
...@@ -1422,7 +1420,7 @@ static void xennet_release_rx_bufs(struct netfront_queue *queue) ...@@ -1422,7 +1420,7 @@ static void xennet_release_rx_bufs(struct netfront_queue *queue)
get_page(page); get_page(page);
gnttab_end_foreign_access(ref, gnttab_end_foreign_access(ref,
(unsigned long)page_address(page)); (unsigned long)page_address(page));
queue->grant_rx_ref[id] = GRANT_INVALID_REF; queue->grant_rx_ref[id] = INVALID_GRANT_REF;
kfree_skb(skb); kfree_skb(skb);
} }
...@@ -1500,7 +1498,7 @@ static bool xennet_handle_rx(struct netfront_queue *queue, unsigned int *eoi) ...@@ -1500,7 +1498,7 @@ static bool xennet_handle_rx(struct netfront_queue *queue, unsigned int *eoi)
return false; return false;
spin_lock_irqsave(&queue->rx_cons_lock, flags); spin_lock_irqsave(&queue->rx_cons_lock, flags);
work_queued = RING_HAS_UNCONSUMED_RESPONSES(&queue->rx); work_queued = XEN_RING_NR_UNCONSUMED_RESPONSES(&queue->rx);
if (work_queued > queue->rx_rsp_unconsumed) { if (work_queued > queue->rx_rsp_unconsumed) {
queue->rx_rsp_unconsumed = work_queued; queue->rx_rsp_unconsumed = work_queued;
*eoi = 0; *eoi = 0;
...@@ -1761,7 +1759,7 @@ static int netfront_probe(struct xenbus_device *dev, ...@@ -1761,7 +1759,7 @@ static int netfront_probe(struct xenbus_device *dev,
static void xennet_end_access(int ref, void *page) static void xennet_end_access(int ref, void *page)
{ {
/* This frees the page as a side-effect */ /* This frees the page as a side-effect */
if (ref != GRANT_INVALID_REF) if (ref != INVALID_GRANT_REF)
gnttab_end_foreign_access(ref, (unsigned long)page); gnttab_end_foreign_access(ref, (unsigned long)page);
} }
...@@ -1798,8 +1796,8 @@ static void xennet_disconnect_backend(struct netfront_info *info) ...@@ -1798,8 +1796,8 @@ static void xennet_disconnect_backend(struct netfront_info *info)
xennet_end_access(queue->tx_ring_ref, queue->tx.sring); xennet_end_access(queue->tx_ring_ref, queue->tx.sring);
xennet_end_access(queue->rx_ring_ref, queue->rx.sring); xennet_end_access(queue->rx_ring_ref, queue->rx.sring);
queue->tx_ring_ref = GRANT_INVALID_REF; queue->tx_ring_ref = INVALID_GRANT_REF;
queue->rx_ring_ref = GRANT_INVALID_REF; queue->rx_ring_ref = INVALID_GRANT_REF;
queue->tx.sring = NULL; queue->tx.sring = NULL;
queue->rx.sring = NULL; queue->rx.sring = NULL;
...@@ -1923,42 +1921,27 @@ static int setup_netfront(struct xenbus_device *dev, ...@@ -1923,42 +1921,27 @@ static int setup_netfront(struct xenbus_device *dev,
struct netfront_queue *queue, unsigned int feature_split_evtchn) struct netfront_queue *queue, unsigned int feature_split_evtchn)
{ {
struct xen_netif_tx_sring *txs; struct xen_netif_tx_sring *txs;
struct xen_netif_rx_sring *rxs = NULL; struct xen_netif_rx_sring *rxs;
grant_ref_t gref;
int err; int err;
queue->tx_ring_ref = GRANT_INVALID_REF; queue->tx_ring_ref = INVALID_GRANT_REF;
queue->rx_ring_ref = GRANT_INVALID_REF; queue->rx_ring_ref = INVALID_GRANT_REF;
queue->rx.sring = NULL; queue->rx.sring = NULL;
queue->tx.sring = NULL; queue->tx.sring = NULL;
txs = (struct xen_netif_tx_sring *)get_zeroed_page(GFP_NOIO | __GFP_HIGH); err = xenbus_setup_ring(dev, GFP_NOIO | __GFP_HIGH, (void **)&txs,
if (!txs) { 1, &queue->tx_ring_ref);
err = -ENOMEM; if (err)
xenbus_dev_fatal(dev, err, "allocating tx ring page");
goto fail; goto fail;
}
SHARED_RING_INIT(txs);
FRONT_RING_INIT(&queue->tx, txs, XEN_PAGE_SIZE);
err = xenbus_grant_ring(dev, txs, 1, &gref); XEN_FRONT_RING_INIT(&queue->tx, txs, XEN_PAGE_SIZE);
if (err < 0)
goto fail;
queue->tx_ring_ref = gref;
rxs = (struct xen_netif_rx_sring *)get_zeroed_page(GFP_NOIO | __GFP_HIGH); err = xenbus_setup_ring(dev, GFP_NOIO | __GFP_HIGH, (void **)&rxs,
if (!rxs) { 1, &queue->rx_ring_ref);
err = -ENOMEM; if (err)
xenbus_dev_fatal(dev, err, "allocating rx ring page");
goto fail; goto fail;
}
SHARED_RING_INIT(rxs);
FRONT_RING_INIT(&queue->rx, rxs, XEN_PAGE_SIZE);
err = xenbus_grant_ring(dev, rxs, 1, &gref); XEN_FRONT_RING_INIT(&queue->rx, rxs, XEN_PAGE_SIZE);
if (err < 0)
goto fail;
queue->rx_ring_ref = gref;
if (feature_split_evtchn) if (feature_split_evtchn)
err = setup_netfront_split(queue); err = setup_netfront_split(queue);
...@@ -1974,24 +1957,10 @@ static int setup_netfront(struct xenbus_device *dev, ...@@ -1974,24 +1957,10 @@ static int setup_netfront(struct xenbus_device *dev,
return 0; return 0;
/* If we fail to setup netfront, it is safe to just revoke access to
* granted pages because backend is not accessing it at this point.
*/
fail: fail:
if (queue->rx_ring_ref != GRANT_INVALID_REF) { xenbus_teardown_ring((void **)&queue->rx.sring, 1, &queue->rx_ring_ref);
gnttab_end_foreign_access(queue->rx_ring_ref, xenbus_teardown_ring((void **)&queue->tx.sring, 1, &queue->tx_ring_ref);
(unsigned long)rxs);
queue->rx_ring_ref = GRANT_INVALID_REF;
} else {
free_page((unsigned long)rxs);
}
if (queue->tx_ring_ref != GRANT_INVALID_REF) {
gnttab_end_foreign_access(queue->tx_ring_ref,
(unsigned long)txs);
queue->tx_ring_ref = GRANT_INVALID_REF;
} else {
free_page((unsigned long)txs);
}
return err; return err;
} }
...@@ -2020,7 +1989,7 @@ static int xennet_init_queue(struct netfront_queue *queue) ...@@ -2020,7 +1989,7 @@ static int xennet_init_queue(struct netfront_queue *queue)
queue->tx_pend_queue = TX_LINK_NONE; queue->tx_pend_queue = TX_LINK_NONE;
for (i = 0; i < NET_TX_RING_SIZE; i++) { for (i = 0; i < NET_TX_RING_SIZE; i++) {
queue->tx_link[i] = i + 1; queue->tx_link[i] = i + 1;
queue->grant_tx_ref[i] = GRANT_INVALID_REF; queue->grant_tx_ref[i] = INVALID_GRANT_REF;
queue->grant_tx_page[i] = NULL; queue->grant_tx_page[i] = NULL;
} }
queue->tx_link[NET_TX_RING_SIZE - 1] = TX_LINK_NONE; queue->tx_link[NET_TX_RING_SIZE - 1] = TX_LINK_NONE;
...@@ -2028,7 +1997,7 @@ static int xennet_init_queue(struct netfront_queue *queue) ...@@ -2028,7 +1997,7 @@ static int xennet_init_queue(struct netfront_queue *queue)
/* Clear out rx_skbs */ /* Clear out rx_skbs */
for (i = 0; i < NET_RX_RING_SIZE; i++) { for (i = 0; i < NET_RX_RING_SIZE; i++) {
queue->rx_skbs[i] = NULL; queue->rx_skbs[i] = NULL;
queue->grant_rx_ref[i] = GRANT_INVALID_REF; queue->grant_rx_ref[i] = INVALID_GRANT_REF;
} }
/* A grant for every tx ring slot */ /* A grant for every tx ring slot */
......
...@@ -709,9 +709,8 @@ static struct pcifront_device *alloc_pdev(struct xenbus_device *xdev) ...@@ -709,9 +709,8 @@ static struct pcifront_device *alloc_pdev(struct xenbus_device *xdev)
if (pdev == NULL) if (pdev == NULL)
goto out; goto out;
pdev->sh_info = if (xenbus_setup_ring(xdev, GFP_KERNEL, (void **)&pdev->sh_info, 1,
(struct xen_pci_sharedinfo *)__get_free_page(GFP_KERNEL); &pdev->gnt_ref)) {
if (pdev->sh_info == NULL) {
kfree(pdev); kfree(pdev);
pdev = NULL; pdev = NULL;
goto out; goto out;
...@@ -729,7 +728,6 @@ static struct pcifront_device *alloc_pdev(struct xenbus_device *xdev) ...@@ -729,7 +728,6 @@ static struct pcifront_device *alloc_pdev(struct xenbus_device *xdev)
spin_lock_init(&pdev->sh_info_lock); spin_lock_init(&pdev->sh_info_lock);
pdev->evtchn = INVALID_EVTCHN; pdev->evtchn = INVALID_EVTCHN;
pdev->gnt_ref = INVALID_GRANT_REF;
pdev->irq = -1; pdev->irq = -1;
INIT_WORK(&pdev->op_work, pcifront_do_aer); INIT_WORK(&pdev->op_work, pcifront_do_aer);
...@@ -754,11 +752,7 @@ static void free_pdev(struct pcifront_device *pdev) ...@@ -754,11 +752,7 @@ static void free_pdev(struct pcifront_device *pdev)
if (pdev->evtchn != INVALID_EVTCHN) if (pdev->evtchn != INVALID_EVTCHN)
xenbus_free_evtchn(pdev->xdev, pdev->evtchn); xenbus_free_evtchn(pdev->xdev, pdev->evtchn);
if (pdev->gnt_ref != INVALID_GRANT_REF) xenbus_teardown_ring((void **)&pdev->sh_info, 1, &pdev->gnt_ref);
gnttab_end_foreign_access(pdev->gnt_ref,
(unsigned long)pdev->sh_info);
else
free_page((unsigned long)pdev->sh_info);
dev_set_drvdata(&pdev->xdev->dev, NULL); dev_set_drvdata(&pdev->xdev->dev, NULL);
...@@ -769,13 +763,6 @@ static int pcifront_publish_info(struct pcifront_device *pdev) ...@@ -769,13 +763,6 @@ static int pcifront_publish_info(struct pcifront_device *pdev)
{ {
int err = 0; int err = 0;
struct xenbus_transaction trans; struct xenbus_transaction trans;
grant_ref_t gref;
err = xenbus_grant_ring(pdev->xdev, pdev->sh_info, 1, &gref);
if (err < 0)
goto out;
pdev->gnt_ref = gref;
err = xenbus_alloc_evtchn(pdev->xdev, &pdev->evtchn); err = xenbus_alloc_evtchn(pdev->xdev, &pdev->evtchn);
if (err) if (err)
......
This diff is collapsed.
...@@ -87,8 +87,6 @@ struct xenhcd_info { ...@@ -87,8 +87,6 @@ struct xenhcd_info {
bool error; bool error;
}; };
#define GRANT_INVALID_REF 0
#define XENHCD_RING_JIFFIES (HZ/200) #define XENHCD_RING_JIFFIES (HZ/200)
#define XENHCD_SCAN_JIFFIES 1 #define XENHCD_SCAN_JIFFIES 1
...@@ -1100,19 +1098,10 @@ static void xenhcd_destroy_rings(struct xenhcd_info *info) ...@@ -1100,19 +1098,10 @@ static void xenhcd_destroy_rings(struct xenhcd_info *info)
unbind_from_irqhandler(info->irq, info); unbind_from_irqhandler(info->irq, info);
info->irq = 0; info->irq = 0;
if (info->urb_ring_ref != GRANT_INVALID_REF) { xenbus_teardown_ring((void **)&info->urb_ring.sring, 1,
gnttab_end_foreign_access(info->urb_ring_ref, &info->urb_ring_ref);
(unsigned long)info->urb_ring.sring); xenbus_teardown_ring((void **)&info->conn_ring.sring, 1,
info->urb_ring_ref = GRANT_INVALID_REF; &info->conn_ring_ref);
}
info->urb_ring.sring = NULL;
if (info->conn_ring_ref != GRANT_INVALID_REF) {
gnttab_end_foreign_access(info->conn_ring_ref,
(unsigned long)info->conn_ring.sring);
info->conn_ring_ref = GRANT_INVALID_REF;
}
info->conn_ring.sring = NULL;
} }
static int xenhcd_setup_rings(struct xenbus_device *dev, static int xenhcd_setup_rings(struct xenbus_device *dev,
...@@ -1120,46 +1109,24 @@ static int xenhcd_setup_rings(struct xenbus_device *dev, ...@@ -1120,46 +1109,24 @@ static int xenhcd_setup_rings(struct xenbus_device *dev,
{ {
struct xenusb_urb_sring *urb_sring; struct xenusb_urb_sring *urb_sring;
struct xenusb_conn_sring *conn_sring; struct xenusb_conn_sring *conn_sring;
grant_ref_t gref;
int err; int err;
info->urb_ring_ref = GRANT_INVALID_REF; info->conn_ring_ref = INVALID_GRANT_REF;
info->conn_ring_ref = GRANT_INVALID_REF; err = xenbus_setup_ring(dev, GFP_NOIO | __GFP_HIGH,
(void **)&urb_sring, 1, &info->urb_ring_ref);
urb_sring = (struct xenusb_urb_sring *)get_zeroed_page( if (err) {
GFP_NOIO | __GFP_HIGH); xenbus_dev_fatal(dev, err, "allocating urb ring");
if (!urb_sring) { return err;
xenbus_dev_fatal(dev, -ENOMEM, "allocating urb ring");
return -ENOMEM;
}
SHARED_RING_INIT(urb_sring);
FRONT_RING_INIT(&info->urb_ring, urb_sring, PAGE_SIZE);
err = xenbus_grant_ring(dev, urb_sring, 1, &gref);
if (err < 0) {
free_page((unsigned long)urb_sring);
info->urb_ring.sring = NULL;
goto fail;
}
info->urb_ring_ref = gref;
conn_sring = (struct xenusb_conn_sring *)get_zeroed_page(
GFP_NOIO | __GFP_HIGH);
if (!conn_sring) {
xenbus_dev_fatal(dev, -ENOMEM, "allocating conn ring");
err = -ENOMEM;
goto fail;
} }
SHARED_RING_INIT(conn_sring); XEN_FRONT_RING_INIT(&info->urb_ring, urb_sring, PAGE_SIZE);
FRONT_RING_INIT(&info->conn_ring, conn_sring, PAGE_SIZE);
err = xenbus_grant_ring(dev, conn_sring, 1, &gref); err = xenbus_setup_ring(dev, GFP_NOIO | __GFP_HIGH,
if (err < 0) { (void **)&conn_sring, 1, &info->conn_ring_ref);
free_page((unsigned long)conn_sring); if (err) {
info->conn_ring.sring = NULL; xenbus_dev_fatal(dev, err, "allocating conn ring");
goto fail; goto fail;
} }
info->conn_ring_ref = gref; XEN_FRONT_RING_INIT(&info->conn_ring, conn_sring, PAGE_SIZE);
err = xenbus_alloc_evtchn(dev, &info->evtchn); err = xenbus_alloc_evtchn(dev, &info->evtchn);
if (err) { if (err) {
......
...@@ -24,15 +24,6 @@ ...@@ -24,15 +24,6 @@
MODULE_IMPORT_NS(DMA_BUF); MODULE_IMPORT_NS(DMA_BUF);
#ifndef GRANT_INVALID_REF
/*
* Note on usage of grant reference 0 as invalid grant reference:
* grant reference 0 is valid, but never exposed to a driver,
* because of the fact it is already in use/reserved by the PV console.
*/
#define GRANT_INVALID_REF 0
#endif
struct gntdev_dmabuf { struct gntdev_dmabuf {
struct gntdev_dmabuf_priv *priv; struct gntdev_dmabuf_priv *priv;
struct dma_buf *dmabuf; struct dma_buf *dmabuf;
...@@ -532,7 +523,7 @@ static void dmabuf_imp_end_foreign_access(u32 *refs, int count) ...@@ -532,7 +523,7 @@ static void dmabuf_imp_end_foreign_access(u32 *refs, int count)
int i; int i;
for (i = 0; i < count; i++) for (i = 0; i < count; i++)
if (refs[i] != GRANT_INVALID_REF) if (refs[i] != INVALID_GRANT_REF)
gnttab_end_foreign_access(refs[i], 0UL); gnttab_end_foreign_access(refs[i], 0UL);
} }
...@@ -567,7 +558,7 @@ static struct gntdev_dmabuf *dmabuf_imp_alloc_storage(int count) ...@@ -567,7 +558,7 @@ static struct gntdev_dmabuf *dmabuf_imp_alloc_storage(int count)
gntdev_dmabuf->nr_pages = count; gntdev_dmabuf->nr_pages = count;
for (i = 0; i < count; i++) for (i = 0; i < count; i++)
gntdev_dmabuf->u.imp.refs[i] = GRANT_INVALID_REF; gntdev_dmabuf->u.imp.refs[i] = INVALID_GRANT_REF;
return gntdev_dmabuf; return gntdev_dmabuf;
......
...@@ -66,8 +66,6 @@ ...@@ -66,8 +66,6 @@
#include <asm/sync_bitops.h> #include <asm/sync_bitops.h>
/* External tools reserve first few grant table entries. */
#define NR_RESERVED_ENTRIES 8
#define GNTTAB_LIST_END 0xffffffff #define GNTTAB_LIST_END 0xffffffff
static grant_ref_t **gnttab_list; static grant_ref_t **gnttab_list;
...@@ -209,6 +207,10 @@ static inline void check_free_callbacks(void) ...@@ -209,6 +207,10 @@ static inline void check_free_callbacks(void)
static void put_free_entry(grant_ref_t ref) static void put_free_entry(grant_ref_t ref)
{ {
unsigned long flags; unsigned long flags;
if (unlikely(ref < GNTTAB_NR_RESERVED_ENTRIES))
return;
spin_lock_irqsave(&gnttab_list_lock, flags); spin_lock_irqsave(&gnttab_list_lock, flags);
gnttab_entry(ref) = gnttab_free_head; gnttab_entry(ref) = gnttab_free_head;
gnttab_free_head = ref; gnttab_free_head = ref;
...@@ -1465,12 +1467,12 @@ int gnttab_init(void) ...@@ -1465,12 +1467,12 @@ int gnttab_init(void)
nr_init_grefs = nr_grant_frames * nr_init_grefs = nr_grant_frames *
gnttab_interface->grefs_per_grant_frame; gnttab_interface->grefs_per_grant_frame;
for (i = NR_RESERVED_ENTRIES; i < nr_init_grefs - 1; i++) for (i = GNTTAB_NR_RESERVED_ENTRIES; i < nr_init_grefs - 1; i++)
gnttab_entry(i) = i + 1; gnttab_entry(i) = i + 1;
gnttab_entry(nr_init_grefs - 1) = GNTTAB_LIST_END; gnttab_entry(nr_init_grefs - 1) = GNTTAB_LIST_END;
gnttab_free_count = nr_init_grefs - NR_RESERVED_ENTRIES; gnttab_free_count = nr_init_grefs - GNTTAB_NR_RESERVED_ENTRIES;
gnttab_free_head = NR_RESERVED_ENTRIES; gnttab_free_head = GNTTAB_NR_RESERVED_ENTRIES;
printk("Grant table initialized\n"); printk("Grant table initialized\n");
return 0; return 0;
......
...@@ -21,15 +21,6 @@ ...@@ -21,15 +21,6 @@
#include <xen/xen-front-pgdir-shbuf.h> #include <xen/xen-front-pgdir-shbuf.h>
#ifndef GRANT_INVALID_REF
/*
* FIXME: usage of grant reference 0 as invalid grant reference:
* grant reference 0 is valid, but never exposed to a PV driver,
* because of the fact it is already in use/reserved by the PV console.
*/
#define GRANT_INVALID_REF 0
#endif
/** /**
* This structure represents the structure of a shared page * This structure represents the structure of a shared page
* that contains grant references to the pages of the shared * that contains grant references to the pages of the shared
...@@ -38,6 +29,7 @@ ...@@ -38,6 +29,7 @@
*/ */
struct xen_page_directory { struct xen_page_directory {
grant_ref_t gref_dir_next_page; grant_ref_t gref_dir_next_page;
#define XEN_GREF_LIST_END 0
grant_ref_t gref[1]; /* Variable length */ grant_ref_t gref[1]; /* Variable length */
}; };
...@@ -83,7 +75,7 @@ grant_ref_t ...@@ -83,7 +75,7 @@ grant_ref_t
xen_front_pgdir_shbuf_get_dir_start(struct xen_front_pgdir_shbuf *buf) xen_front_pgdir_shbuf_get_dir_start(struct xen_front_pgdir_shbuf *buf)
{ {
if (!buf->grefs) if (!buf->grefs)
return GRANT_INVALID_REF; return INVALID_GRANT_REF;
return buf->grefs[0]; return buf->grefs[0];
} }
...@@ -142,7 +134,7 @@ void xen_front_pgdir_shbuf_free(struct xen_front_pgdir_shbuf *buf) ...@@ -142,7 +134,7 @@ void xen_front_pgdir_shbuf_free(struct xen_front_pgdir_shbuf *buf)
int i; int i;
for (i = 0; i < buf->num_grefs; i++) for (i = 0; i < buf->num_grefs; i++)
if (buf->grefs[i] != GRANT_INVALID_REF) if (buf->grefs[i] != INVALID_GRANT_REF)
gnttab_end_foreign_access(buf->grefs[i], 0UL); gnttab_end_foreign_access(buf->grefs[i], 0UL);
} }
kfree(buf->grefs); kfree(buf->grefs);
...@@ -355,7 +347,7 @@ static void backend_fill_page_dir(struct xen_front_pgdir_shbuf *buf) ...@@ -355,7 +347,7 @@ static void backend_fill_page_dir(struct xen_front_pgdir_shbuf *buf)
} }
/* Last page must say there is no more pages. */ /* Last page must say there is no more pages. */
page_dir = (struct xen_page_directory *)ptr; page_dir = (struct xen_page_directory *)ptr;
page_dir->gref_dir_next_page = GRANT_INVALID_REF; page_dir->gref_dir_next_page = XEN_GREF_LIST_END;
} }
/** /**
...@@ -384,7 +376,7 @@ static void guest_fill_page_dir(struct xen_front_pgdir_shbuf *buf) ...@@ -384,7 +376,7 @@ static void guest_fill_page_dir(struct xen_front_pgdir_shbuf *buf)
if (grefs_left <= XEN_NUM_GREFS_PER_PAGE) { if (grefs_left <= XEN_NUM_GREFS_PER_PAGE) {
to_copy = grefs_left; to_copy = grefs_left;
page_dir->gref_dir_next_page = GRANT_INVALID_REF; page_dir->gref_dir_next_page = XEN_GREF_LIST_END;
} else { } else {
to_copy = XEN_NUM_GREFS_PER_PAGE; to_copy = XEN_NUM_GREFS_PER_PAGE;
page_dir->gref_dir_next_page = buf->grefs[i + 1]; page_dir->gref_dir_next_page = buf->grefs[i + 1];
......
...@@ -280,6 +280,82 @@ static void scsiback_free_translation_entry(struct kref *kref) ...@@ -280,6 +280,82 @@ static void scsiback_free_translation_entry(struct kref *kref)
kfree(entry); kfree(entry);
} }
static int32_t scsiback_result(int32_t result)
{
int32_t host_status;
switch (XEN_VSCSIIF_RSLT_HOST(result)) {
case DID_OK:
host_status = XEN_VSCSIIF_RSLT_HOST_OK;
break;
case DID_NO_CONNECT:
host_status = XEN_VSCSIIF_RSLT_HOST_NO_CONNECT;
break;
case DID_BUS_BUSY:
host_status = XEN_VSCSIIF_RSLT_HOST_BUS_BUSY;
break;
case DID_TIME_OUT:
host_status = XEN_VSCSIIF_RSLT_HOST_TIME_OUT;
break;
case DID_BAD_TARGET:
host_status = XEN_VSCSIIF_RSLT_HOST_BAD_TARGET;
break;
case DID_ABORT:
host_status = XEN_VSCSIIF_RSLT_HOST_ABORT;
break;
case DID_PARITY:
host_status = XEN_VSCSIIF_RSLT_HOST_PARITY;
break;
case DID_ERROR:
host_status = XEN_VSCSIIF_RSLT_HOST_ERROR;
break;
case DID_RESET:
host_status = XEN_VSCSIIF_RSLT_HOST_RESET;
break;
case DID_BAD_INTR:
host_status = XEN_VSCSIIF_RSLT_HOST_BAD_INTR;
break;
case DID_PASSTHROUGH:
host_status = XEN_VSCSIIF_RSLT_HOST_PASSTHROUGH;
break;
case DID_SOFT_ERROR:
host_status = XEN_VSCSIIF_RSLT_HOST_SOFT_ERROR;
break;
case DID_IMM_RETRY:
host_status = XEN_VSCSIIF_RSLT_HOST_IMM_RETRY;
break;
case DID_REQUEUE:
host_status = XEN_VSCSIIF_RSLT_HOST_REQUEUE;
break;
case DID_TRANSPORT_DISRUPTED:
host_status = XEN_VSCSIIF_RSLT_HOST_TRANSPORT_DISRUPTED;
break;
case DID_TRANSPORT_FAILFAST:
host_status = XEN_VSCSIIF_RSLT_HOST_TRANSPORT_FAILFAST;
break;
case DID_TARGET_FAILURE:
host_status = XEN_VSCSIIF_RSLT_HOST_TARGET_FAILURE;
break;
case DID_NEXUS_FAILURE:
host_status = XEN_VSCSIIF_RSLT_HOST_NEXUS_FAILURE;
break;
case DID_ALLOC_FAILURE:
host_status = XEN_VSCSIIF_RSLT_HOST_ALLOC_FAILURE;
break;
case DID_MEDIUM_ERROR:
host_status = XEN_VSCSIIF_RSLT_HOST_MEDIUM_ERROR;
break;
case DID_TRANSPORT_MARGINAL:
host_status = XEN_VSCSIIF_RSLT_HOST_TRANSPORT_MARGINAL;
break;
default:
host_status = XEN_VSCSIIF_RSLT_HOST_ERROR;
break;
}
return (host_status << 16) | (result & 0x00ffff);
}
static void scsiback_send_response(struct vscsibk_info *info, static void scsiback_send_response(struct vscsibk_info *info,
char *sense_buffer, int32_t result, uint32_t resid, char *sense_buffer, int32_t result, uint32_t resid,
uint16_t rqid) uint16_t rqid)
...@@ -295,7 +371,7 @@ static void scsiback_send_response(struct vscsibk_info *info, ...@@ -295,7 +371,7 @@ static void scsiback_send_response(struct vscsibk_info *info,
ring_res = RING_GET_RESPONSE(&info->ring, info->ring.rsp_prod_pvt); ring_res = RING_GET_RESPONSE(&info->ring, info->ring.rsp_prod_pvt);
info->ring.rsp_prod_pvt++; info->ring.rsp_prod_pvt++;
ring_res->rslt = result; ring_res->rslt = scsiback_result(result);
ring_res->rqid = rqid; ring_res->rqid = rqid;
if (sense_buffer != NULL && if (sense_buffer != NULL &&
...@@ -555,7 +631,7 @@ static void scsiback_device_action(struct vscsibk_pend *pending_req, ...@@ -555,7 +631,7 @@ static void scsiback_device_action(struct vscsibk_pend *pending_req,
struct scsiback_nexus *nexus = tpg->tpg_nexus; struct scsiback_nexus *nexus = tpg->tpg_nexus;
struct se_cmd *se_cmd = &pending_req->se_cmd; struct se_cmd *se_cmd = &pending_req->se_cmd;
u64 unpacked_lun = pending_req->v2p->lun; u64 unpacked_lun = pending_req->v2p->lun;
int rc, err = FAILED; int rc, err = XEN_VSCSIIF_RSLT_RESET_FAILED;
init_completion(&pending_req->tmr_done); init_completion(&pending_req->tmr_done);
...@@ -569,7 +645,7 @@ static void scsiback_device_action(struct vscsibk_pend *pending_req, ...@@ -569,7 +645,7 @@ static void scsiback_device_action(struct vscsibk_pend *pending_req,
wait_for_completion(&pending_req->tmr_done); wait_for_completion(&pending_req->tmr_done);
err = (se_cmd->se_tmr_req->response == TMR_FUNCTION_COMPLETE) ? err = (se_cmd->se_tmr_req->response == TMR_FUNCTION_COMPLETE) ?
SUCCESS : FAILED; XEN_VSCSIIF_RSLT_RESET_SUCCESS : XEN_VSCSIIF_RSLT_RESET_FAILED;
scsiback_do_resp_with_sense(NULL, err, 0, pending_req); scsiback_do_resp_with_sense(NULL, err, 0, pending_req);
transport_generic_free_cmd(&pending_req->se_cmd, 0); transport_generic_free_cmd(&pending_req->se_cmd, 0);
......
...@@ -363,50 +363,92 @@ static void xenbus_switch_fatal(struct xenbus_device *dev, int depth, int err, ...@@ -363,50 +363,92 @@ static void xenbus_switch_fatal(struct xenbus_device *dev, int depth, int err,
__xenbus_switch_state(dev, XenbusStateClosing, 1); __xenbus_switch_state(dev, XenbusStateClosing, 1);
} }
/** /*
* xenbus_grant_ring * xenbus_setup_ring
* @dev: xenbus device * @dev: xenbus device
* @vaddr: starting virtual address of the ring * @vaddr: pointer to starting virtual address of the ring
* @nr_pages: number of pages to be granted * @nr_pages: number of pages to be granted
* @grefs: grant reference array to be filled in * @grefs: grant reference array to be filled in
* *
* Grant access to the given @vaddr to the peer of the given device. * Allocate physically contiguous pages for a shared ring buffer and grant it
* Then fill in @grefs with grant references. Return 0 on success, or * to the peer of the given device. The ring buffer is initially filled with
* -errno on error. On error, the device will switch to * zeroes. The virtual address of the ring is stored at @vaddr and the
* XenbusStateClosing, and the error will be saved in the store. * grant references are stored in the @grefs array. In case of error @vaddr
* will be set to NULL and @grefs will be filled with INVALID_GRANT_REF.
*/ */
int xenbus_grant_ring(struct xenbus_device *dev, void *vaddr, int xenbus_setup_ring(struct xenbus_device *dev, gfp_t gfp, void **vaddr,
unsigned int nr_pages, grant_ref_t *grefs) unsigned int nr_pages, grant_ref_t *grefs)
{ {
int err; unsigned long ring_size = nr_pages * XEN_PAGE_SIZE;
unsigned int i;
grant_ref_t gref_head; grant_ref_t gref_head;
unsigned int i;
int ret;
err = gnttab_alloc_grant_references(nr_pages, &gref_head); *vaddr = alloc_pages_exact(ring_size, gfp | __GFP_ZERO);
if (err) { if (!*vaddr) {
xenbus_dev_fatal(dev, err, "granting access to ring page"); ret = -ENOMEM;
return err; goto err;
}
ret = gnttab_alloc_grant_references(nr_pages, &gref_head);
if (ret) {
xenbus_dev_fatal(dev, ret, "granting access to %u ring pages",
nr_pages);
goto err;
} }
for (i = 0; i < nr_pages; i++) { for (i = 0; i < nr_pages; i++) {
unsigned long gfn; unsigned long gfn;
if (is_vmalloc_addr(vaddr)) if (is_vmalloc_addr(*vaddr))
gfn = pfn_to_gfn(vmalloc_to_pfn(vaddr)); gfn = pfn_to_gfn(vmalloc_to_pfn(vaddr[i]));
else else
gfn = virt_to_gfn(vaddr); gfn = virt_to_gfn(vaddr[i]);
grefs[i] = gnttab_claim_grant_reference(&gref_head); grefs[i] = gnttab_claim_grant_reference(&gref_head);
gnttab_grant_foreign_access_ref(grefs[i], dev->otherend_id, gnttab_grant_foreign_access_ref(grefs[i], dev->otherend_id,
gfn, 0); gfn, 0);
vaddr = vaddr + XEN_PAGE_SIZE;
} }
return 0; return 0;
err:
if (*vaddr)
free_pages_exact(*vaddr, ring_size);
for (i = 0; i < nr_pages; i++)
grefs[i] = INVALID_GRANT_REF;
*vaddr = NULL;
return ret;
} }
EXPORT_SYMBOL_GPL(xenbus_grant_ring); EXPORT_SYMBOL_GPL(xenbus_setup_ring);
/*
* xenbus_teardown_ring
* @vaddr: starting virtual address of the ring
* @nr_pages: number of pages
* @grefs: grant reference array
*
* Remove grants for the shared ring buffer and free the associated memory.
* On return the grant reference array is filled with INVALID_GRANT_REF.
*/
void xenbus_teardown_ring(void **vaddr, unsigned int nr_pages,
grant_ref_t *grefs)
{
unsigned int i;
for (i = 0; i < nr_pages; i++) {
if (grefs[i] != INVALID_GRANT_REF) {
gnttab_end_foreign_access(grefs[i], 0);
grefs[i] = INVALID_GRANT_REF;
}
}
if (*vaddr)
free_pages_exact(*vaddr, nr_pages * XEN_PAGE_SIZE);
*vaddr = NULL;
}
EXPORT_SYMBOL_GPL(xenbus_teardown_ring);
/** /**
* Allocate an event channel for the given xenbus_device, assigning the newly * Allocate an event channel for the given xenbus_device, assigning the newly
......
...@@ -65,6 +65,7 @@ ...@@ -65,6 +65,7 @@
#include "xenbus.h" #include "xenbus.h"
static int xs_init_irq;
int xen_store_evtchn; int xen_store_evtchn;
EXPORT_SYMBOL_GPL(xen_store_evtchn); EXPORT_SYMBOL_GPL(xen_store_evtchn);
...@@ -750,6 +751,20 @@ static void xenbus_probe(void) ...@@ -750,6 +751,20 @@ static void xenbus_probe(void)
{ {
xenstored_ready = 1; xenstored_ready = 1;
if (!xen_store_interface) {
xen_store_interface = xen_remap(xen_store_gfn << XEN_PAGE_SHIFT,
XEN_PAGE_SIZE);
/*
* Now it is safe to free the IRQ used for xenstore late
* initialization. No need to unbind: it is about to be
* bound again from xb_init_comms. Note that calling
* unbind_from_irqhandler now would result in xen_evtchn_close()
* being called and the event channel not being enabled again
* afterwards, resulting in missed event notifications.
*/
free_irq(xs_init_irq, &xb_waitq);
}
/* /*
* In the HVM case, xenbus_init() deferred its call to * In the HVM case, xenbus_init() deferred its call to
* xs_init() in case callbacks were not operational yet. * xs_init() in case callbacks were not operational yet.
...@@ -798,20 +813,22 @@ static int __init xenbus_probe_initcall(void) ...@@ -798,20 +813,22 @@ static int __init xenbus_probe_initcall(void)
{ {
/* /*
* Probe XenBus here in the XS_PV case, and also XS_HVM unless we * Probe XenBus here in the XS_PV case, and also XS_HVM unless we
* need to wait for the platform PCI device to come up. * need to wait for the platform PCI device to come up or
* xen_store_interface is not ready.
*/ */
if (xen_store_domain_type == XS_PV || if (xen_store_domain_type == XS_PV ||
(xen_store_domain_type == XS_HVM && (xen_store_domain_type == XS_HVM &&
!xs_hvm_defer_init_for_callback())) !xs_hvm_defer_init_for_callback() &&
xen_store_interface != NULL))
xenbus_probe(); xenbus_probe();
/* /*
* For XS_LOCAL, spawn a thread which will wait for xenstored * For XS_LOCAL or when xen_store_interface is not ready, spawn a
* or a xenstore-stubdom to be started, then probe. It will be * thread which will wait for xenstored or a xenstore-stubdom to be
* triggered when communication starts happening, by waiting * started, then probe. It will be triggered when communication
* on xb_waitq. * starts happening, by waiting on xb_waitq.
*/ */
if (xen_store_domain_type == XS_LOCAL) { if (xen_store_domain_type == XS_LOCAL || xen_store_interface == NULL) {
struct task_struct *probe_task; struct task_struct *probe_task;
probe_task = kthread_run(xenbus_probe_thread, NULL, probe_task = kthread_run(xenbus_probe_thread, NULL,
...@@ -907,10 +924,25 @@ static struct notifier_block xenbus_resume_nb = { ...@@ -907,10 +924,25 @@ static struct notifier_block xenbus_resume_nb = {
.notifier_call = xenbus_resume_cb, .notifier_call = xenbus_resume_cb,
}; };
static irqreturn_t xenbus_late_init(int irq, void *unused)
{
int err;
uint64_t v = 0;
err = hvm_get_parameter(HVM_PARAM_STORE_PFN, &v);
if (err || !v || !~v)
return IRQ_HANDLED;
xen_store_gfn = (unsigned long)v;
wake_up(&xb_waitq);
return IRQ_HANDLED;
}
static int __init xenbus_init(void) static int __init xenbus_init(void)
{ {
int err; int err;
uint64_t v = 0; uint64_t v = 0;
bool wait = false;
xen_store_domain_type = XS_UNKNOWN; xen_store_domain_type = XS_UNKNOWN;
if (!xen_domain()) if (!xen_domain())
...@@ -957,12 +989,15 @@ static int __init xenbus_init(void) ...@@ -957,12 +989,15 @@ static int __init xenbus_init(void)
* been properly initialized. Instead of attempting to map a * been properly initialized. Instead of attempting to map a
* wrong guest physical address return error. * wrong guest physical address return error.
* *
* Also recognize all bits set as an invalid value. * Also recognize all bits set as an invalid/uninitialized value.
*/ */
if (!v || !~v) { if (!v) {
err = -ENOENT; err = -ENOENT;
goto out_error; goto out_error;
} }
if (v == ~0ULL) {
wait = true;
} else {
/* Avoid truncation on 32-bit. */ /* Avoid truncation on 32-bit. */
#if BITS_PER_LONG == 32 #if BITS_PER_LONG == 32
if (v > ULONG_MAX) { if (v > ULONG_MAX) {
...@@ -976,6 +1011,22 @@ static int __init xenbus_init(void) ...@@ -976,6 +1011,22 @@ static int __init xenbus_init(void)
xen_store_interface = xen_store_interface =
xen_remap(xen_store_gfn << XEN_PAGE_SHIFT, xen_remap(xen_store_gfn << XEN_PAGE_SHIFT,
XEN_PAGE_SIZE); XEN_PAGE_SIZE);
if (xen_store_interface->connection != XENSTORE_CONNECTED)
wait = true;
}
if (wait) {
err = bind_evtchn_to_irqhandler(xen_store_evtchn,
xenbus_late_init,
0, "xenstore_late_init",
&xb_waitq);
if (err < 0) {
pr_err("xenstore_late_init couldn't bind irq err=%d\n",
err);
return err;
}
xs_init_irq = err;
}
break; break;
default: default:
pr_warn("Xenstore state unknown\n"); pr_warn("Xenstore state unknown\n");
......
...@@ -57,8 +57,6 @@ ...@@ -57,8 +57,6 @@
#define INVALID_GRANT_REF ((grant_ref_t)-1) #define INVALID_GRANT_REF ((grant_ref_t)-1)
#define INVALID_GRANT_HANDLE ((grant_handle_t)-1) #define INVALID_GRANT_HANDLE ((grant_handle_t)-1)
#define GNTTAB_RESERVED_XENSTORE 1
/* NR_GRANT_FRAMES must be less than or equal to that configured in Xen */ /* NR_GRANT_FRAMES must be less than or equal to that configured in Xen */
#define NR_GRANT_FRAMES 4 #define NR_GRANT_FRAMES 4
......
This diff is collapsed.
...@@ -72,9 +72,8 @@ typedef unsigned int RING_IDX; ...@@ -72,9 +72,8 @@ typedef unsigned int RING_IDX;
* of the shared memory area (PAGE_SIZE, for instance). To initialise * of the shared memory area (PAGE_SIZE, for instance). To initialise
* the front half: * the front half:
* *
* mytag_front_ring_t front_ring; * mytag_front_ring_t ring;
* SHARED_RING_INIT((mytag_sring_t *)shared_page); * XEN_FRONT_RING_INIT(&ring, (mytag_sring_t *)shared_page, PAGE_SIZE);
* FRONT_RING_INIT(&front_ring, (mytag_sring_t *)shared_page, PAGE_SIZE);
* *
* Initializing the back follows similarly (note that only the front * Initializing the back follows similarly (note that only the front
* initializes the shared ring): * initializes the shared ring):
...@@ -146,6 +145,11 @@ struct __name##_back_ring { \ ...@@ -146,6 +145,11 @@ struct __name##_back_ring { \
#define FRONT_RING_INIT(_r, _s, __size) FRONT_RING_ATTACH(_r, _s, 0, __size) #define FRONT_RING_INIT(_r, _s, __size) FRONT_RING_ATTACH(_r, _s, 0, __size)
#define XEN_FRONT_RING_INIT(r, s, size) do { \
SHARED_RING_INIT(s); \
FRONT_RING_INIT(r, s, size); \
} while (0)
#define BACK_RING_ATTACH(_r, _s, _i, __size) do { \ #define BACK_RING_ATTACH(_r, _s, _i, __size) do { \
(_r)->rsp_prod_pvt = (_i); \ (_r)->rsp_prod_pvt = (_i); \
(_r)->req_cons = (_i); \ (_r)->req_cons = (_i); \
...@@ -170,16 +174,21 @@ struct __name##_back_ring { \ ...@@ -170,16 +174,21 @@ struct __name##_back_ring { \
(RING_FREE_REQUESTS(_r) == 0) (RING_FREE_REQUESTS(_r) == 0)
/* Test if there are outstanding messages to be processed on a ring. */ /* Test if there are outstanding messages to be processed on a ring. */
#define RING_HAS_UNCONSUMED_RESPONSES(_r) \ #define XEN_RING_NR_UNCONSUMED_RESPONSES(_r) \
((_r)->sring->rsp_prod - (_r)->rsp_cons) ((_r)->sring->rsp_prod - (_r)->rsp_cons)
#define RING_HAS_UNCONSUMED_REQUESTS(_r) ({ \ #define XEN_RING_NR_UNCONSUMED_REQUESTS(_r) ({ \
unsigned int req = (_r)->sring->req_prod - (_r)->req_cons; \ unsigned int req = (_r)->sring->req_prod - (_r)->req_cons; \
unsigned int rsp = RING_SIZE(_r) - \ unsigned int rsp = RING_SIZE(_r) - \
((_r)->req_cons - (_r)->rsp_prod_pvt); \ ((_r)->req_cons - (_r)->rsp_prod_pvt); \
req < rsp ? req : rsp; \ req < rsp ? req : rsp; \
}) })
#define RING_HAS_UNCONSUMED_RESPONSES(_r) \
(!!XEN_RING_NR_UNCONSUMED_RESPONSES(_r))
#define RING_HAS_UNCONSUMED_REQUESTS(_r) \
(!!XEN_RING_NR_UNCONSUMED_REQUESTS(_r))
/* Direct access to individual ring elements, by index. */ /* Direct access to individual ring elements, by index. */
#define RING_GET_REQUEST(_r, _idx) \ #define RING_GET_REQUEST(_r, _idx) \
(&((_r)->sring->ring[((_idx) & (RING_SIZE(_r) - 1))].req)) (&((_r)->sring->ring[((_idx) & (RING_SIZE(_r) - 1))].req))
......
...@@ -43,7 +43,7 @@ ...@@ -43,7 +43,7 @@
* *
* A string specifying the backend device: either a 4-tuple "h:c:t:l" * A string specifying the backend device: either a 4-tuple "h:c:t:l"
* (host, controller, target, lun, all integers), or a WWN (e.g. * (host, controller, target, lun, all integers), or a WWN (e.g.
* "naa.60014054ac780582"). * "naa.60014054ac780582:0").
* *
* v-dev * v-dev
* Values: string * Values: string
...@@ -87,6 +87,75 @@ ...@@ -87,6 +87,75 @@
* response structures. * response structures.
*/ */
/*
* Xenstore format in practice
* ===========================
*
* The backend driver uses a single_host:many_devices notation to manage domU
* devices. Everything is stored in /local/domain/<backend_domid>/backend/vscsi/.
* The xenstore layout looks like this (dom0 is assumed to be the backend_domid):
*
* <domid>/<vhost>/feature-host = "0"
* <domid>/<vhost>/frontend = "/local/domain/<domid>/device/vscsi/0"
* <domid>/<vhost>/frontend-id = "<domid>"
* <domid>/<vhost>/online = "1"
* <domid>/<vhost>/state = "4"
* <domid>/<vhost>/vscsi-devs/dev-0/p-dev = "8:0:2:1" or "naa.wwn:lun"
* <domid>/<vhost>/vscsi-devs/dev-0/state = "4"
* <domid>/<vhost>/vscsi-devs/dev-0/v-dev = "0:0:0:0"
* <domid>/<vhost>/vscsi-devs/dev-1/p-dev = "8:0:2:2"
* <domid>/<vhost>/vscsi-devs/dev-1/state = "4"
* <domid>/<vhost>/vscsi-devs/dev-1/v-dev = "0:0:1:0"
*
* The frontend driver maintains its state in
* /local/domain/<domid>/device/vscsi/.
*
* <vhost>/backend = "/local/domain/0/backend/vscsi/<domid>/<vhost>"
* <vhost>/backend-id = "0"
* <vhost>/event-channel = "20"
* <vhost>/ring-ref = "43"
* <vhost>/state = "4"
* <vhost>/vscsi-devs/dev-0/state = "4"
* <vhost>/vscsi-devs/dev-1/state = "4"
*
* In addition to the entries for backend and frontend these flags are stored
* for the toolstack:
*
* <domid>/<vhost>/vscsi-devs/dev-1/p-devname = "/dev/$device"
* <domid>/<vhost>/libxl_ctrl_index = "0"
*
*
* Backend/frontend protocol
* =========================
*
* To create a vhost along with a device:
* <domid>/<vhost>/feature-host = "0"
* <domid>/<vhost>/frontend = "/local/domain/<domid>/device/vscsi/0"
* <domid>/<vhost>/frontend-id = "<domid>"
* <domid>/<vhost>/online = "1"
* <domid>/<vhost>/state = "1"
* <domid>/<vhost>/vscsi-devs/dev-0/p-dev = "8:0:2:1"
* <domid>/<vhost>/vscsi-devs/dev-0/state = "1"
* <domid>/<vhost>/vscsi-devs/dev-0/v-dev = "0:0:0:0"
* Wait for <domid>/<vhost>/state + <domid>/<vhost>/vscsi-devs/dev-0/state become 4
*
* To add another device to a vhost:
* <domid>/<vhost>/state = "7"
* <domid>/<vhost>/vscsi-devs/dev-1/p-dev = "8:0:2:2"
* <domid>/<vhost>/vscsi-devs/dev-1/state = "1"
* <domid>/<vhost>/vscsi-devs/dev-1/v-dev = "0:0:1:0"
* Wait for <domid>/<vhost>/state + <domid>/<vhost>/vscsi-devs/dev-1/state become 4
*
* To remove a device from a vhost:
* <domid>/<vhost>/state = "7"
* <domid>/<vhost>/vscsi-devs/dev-1/state = "5"
* Wait for <domid>/<vhost>/state to become 4
* Wait for <domid>/<vhost>/vscsi-devs/dev-1/state become 6
* Remove <domid>/<vhost>/vscsi-devs/dev-1/{state,p-dev,v-dev,p-devname}
* Remove <domid>/<vhost>/vscsi-devs/dev-1/
*
*/
/* Requests from the frontend to the backend */ /* Requests from the frontend to the backend */
/* /*
...@@ -117,7 +186,8 @@ ...@@ -117,7 +186,8 @@
* (plus the set VSCSIIF_SG_GRANT bit), the number of scsiif_request_segment * (plus the set VSCSIIF_SG_GRANT bit), the number of scsiif_request_segment
* elements referencing the target data buffers is calculated from the lengths * elements referencing the target data buffers is calculated from the lengths
* of the seg[] elements (the sum of all valid seg[].length divided by the * of the seg[] elements (the sum of all valid seg[].length divided by the
* size of one scsiif_request_segment structure). * size of one scsiif_request_segment structure). The frontend may use a mix of
* direct and indirect requests.
*/ */
#define VSCSIIF_ACT_SCSI_CDB 1 #define VSCSIIF_ACT_SCSI_CDB 1
...@@ -154,12 +224,14 @@ ...@@ -154,12 +224,14 @@
/* /*
* based on Linux kernel 2.6.18, still valid * based on Linux kernel 2.6.18, still valid
*
* Changing these values requires support of multiple protocols via the rings * Changing these values requires support of multiple protocols via the rings
* as "old clients" will blindly use these values and the resulting structure * as "old clients" will blindly use these values and the resulting structure
* sizes. * sizes.
*/ */
#define VSCSIIF_MAX_COMMAND_SIZE 16 #define VSCSIIF_MAX_COMMAND_SIZE 16
#define VSCSIIF_SENSE_BUFFERSIZE 96 #define VSCSIIF_SENSE_BUFFERSIZE 96
#define VSCSIIF_PAGE_SIZE 4096
struct scsiif_request_segment { struct scsiif_request_segment {
grant_ref_t gref; grant_ref_t gref;
...@@ -167,7 +239,8 @@ struct scsiif_request_segment { ...@@ -167,7 +239,8 @@ struct scsiif_request_segment {
uint16_t length; uint16_t length;
}; };
#define VSCSIIF_SG_PER_PAGE (PAGE_SIZE / sizeof(struct scsiif_request_segment)) #define VSCSIIF_SG_PER_PAGE (VSCSIIF_PAGE_SIZE / \
sizeof(struct scsiif_request_segment))
/* Size of one request is 252 bytes */ /* Size of one request is 252 bytes */
struct vscsiif_request { struct vscsiif_request {
...@@ -207,6 +280,58 @@ struct vscsiif_response { ...@@ -207,6 +280,58 @@ struct vscsiif_response {
uint32_t reserved[36]; uint32_t reserved[36];
}; };
/* SCSI I/O status from vscsiif_response->rslt */
#define XEN_VSCSIIF_RSLT_STATUS(x) ((x) & 0x00ff)
/* Host I/O status from vscsiif_response->rslt */
#define XEN_VSCSIIF_RSLT_HOST(x) (((x) & 0x00ff0000) >> 16)
#define XEN_VSCSIIF_RSLT_HOST_OK 0
/* Couldn't connect before timeout */
#define XEN_VSCSIIF_RSLT_HOST_NO_CONNECT 1
/* Bus busy through timeout */
#define XEN_VSCSIIF_RSLT_HOST_BUS_BUSY 2
/* Timed out for other reason */
#define XEN_VSCSIIF_RSLT_HOST_TIME_OUT 3
/* Bad target */
#define XEN_VSCSIIF_RSLT_HOST_BAD_TARGET 4
/* Abort for some other reason */
#define XEN_VSCSIIF_RSLT_HOST_ABORT 5
/* Parity error */
#define XEN_VSCSIIF_RSLT_HOST_PARITY 6
/* Internal error */
#define XEN_VSCSIIF_RSLT_HOST_ERROR 7
/* Reset by somebody */
#define XEN_VSCSIIF_RSLT_HOST_RESET 8
/* Unexpected interrupt */
#define XEN_VSCSIIF_RSLT_HOST_BAD_INTR 9
/* Force command past mid-layer */
#define XEN_VSCSIIF_RSLT_HOST_PASSTHROUGH 10
/* Retry requested */
#define XEN_VSCSIIF_RSLT_HOST_SOFT_ERROR 11
/* Hidden retry requested */
#define XEN_VSCSIIF_RSLT_HOST_IMM_RETRY 12
/* Requeue command requested */
#define XEN_VSCSIIF_RSLT_HOST_REQUEUE 13
/* Transport error disrupted I/O */
#define XEN_VSCSIIF_RSLT_HOST_TRANSPORT_DISRUPTED 14
/* Transport class fastfailed */
#define XEN_VSCSIIF_RSLT_HOST_TRANSPORT_FAILFAST 15
/* Permanent target failure */
#define XEN_VSCSIIF_RSLT_HOST_TARGET_FAILURE 16
/* Permanent nexus failure on path */
#define XEN_VSCSIIF_RSLT_HOST_NEXUS_FAILURE 17
/* Space allocation on device failed */
#define XEN_VSCSIIF_RSLT_HOST_ALLOC_FAILURE 18
/* Medium error */
#define XEN_VSCSIIF_RSLT_HOST_MEDIUM_ERROR 19
/* Transport marginal errors */
#define XEN_VSCSIIF_RSLT_HOST_TRANSPORT_MARGINAL 20
/* Result values of reset operations */
#define XEN_VSCSIIF_RSLT_RESET_SUCCESS 0x2002
#define XEN_VSCSIIF_RSLT_RESET_FAILED 0x2003
DEFINE_RING_TYPES(vscsiif, struct vscsiif_request, struct vscsiif_response); DEFINE_RING_TYPES(vscsiif, struct vscsiif_request, struct vscsiif_response);
#endif /*__XEN__PUBLIC_IO_SCSI_H__*/ #endif /*__XEN__PUBLIC_IO_SCSI_H__*/
...@@ -10,7 +10,8 @@ ...@@ -10,7 +10,8 @@
enum xsd_sockmsg_type enum xsd_sockmsg_type
{ {
XS_DEBUG, XS_CONTROL,
#define XS_DEBUG XS_CONTROL
XS_DIRECTORY, XS_DIRECTORY,
XS_READ, XS_READ,
XS_GET_PERMS, XS_GET_PERMS,
...@@ -30,8 +31,13 @@ enum xsd_sockmsg_type ...@@ -30,8 +31,13 @@ enum xsd_sockmsg_type
XS_IS_DOMAIN_INTRODUCED, XS_IS_DOMAIN_INTRODUCED,
XS_RESUME, XS_RESUME,
XS_SET_TARGET, XS_SET_TARGET,
XS_RESTRICT, /* XS_RESTRICT has been removed */
XS_RESET_WATCHES, XS_RESET_WATCHES = XS_SET_TARGET + 2,
XS_DIRECTORY_PART,
XS_TYPE_COUNT, /* Number of valid types. */
XS_INVALID = 0xffff /* Guaranteed to remain an invalid type */
}; };
#define XS_WRITE_NONE "NONE" #define XS_WRITE_NONE "NONE"
...@@ -59,7 +65,8 @@ static struct xsd_errors xsd_errors[] __attribute__((unused)) = { ...@@ -59,7 +65,8 @@ static struct xsd_errors xsd_errors[] __attribute__((unused)) = {
XSD_ERROR(EROFS), XSD_ERROR(EROFS),
XSD_ERROR(EBUSY), XSD_ERROR(EBUSY),
XSD_ERROR(EAGAIN), XSD_ERROR(EAGAIN),
XSD_ERROR(EISCONN) XSD_ERROR(EISCONN),
XSD_ERROR(E2BIG)
}; };
struct xsd_sockmsg struct xsd_sockmsg
...@@ -87,9 +94,31 @@ struct xenstore_domain_interface { ...@@ -87,9 +94,31 @@ struct xenstore_domain_interface {
char rsp[XENSTORE_RING_SIZE]; /* Replies and async watch events. */ char rsp[XENSTORE_RING_SIZE]; /* Replies and async watch events. */
XENSTORE_RING_IDX req_cons, req_prod; XENSTORE_RING_IDX req_cons, req_prod;
XENSTORE_RING_IDX rsp_cons, rsp_prod; XENSTORE_RING_IDX rsp_cons, rsp_prod;
uint32_t server_features; /* Bitmap of features supported by the server */
uint32_t connection;
uint32_t error;
}; };
/* Violating this is very bad. See docs/misc/xenstore.txt. */ /* Violating this is very bad. See docs/misc/xenstore.txt. */
#define XENSTORE_PAYLOAD_MAX 4096 #define XENSTORE_PAYLOAD_MAX 4096
/* Violating these just gets you an error back */
#define XENSTORE_ABS_PATH_MAX 3072
#define XENSTORE_REL_PATH_MAX 2048
/* The ability to reconnect a ring */
#define XENSTORE_SERVER_FEATURE_RECONNECTION 1
/* The presence of the "error" field in the ring page */
#define XENSTORE_SERVER_FEATURE_ERROR 2
/* Valid values for the connection field */
#define XENSTORE_CONNECTED 0 /* the steady-state */
#define XENSTORE_RECONNECT 1 /* guest has initiated a reconnect */
/* Valid values for the error field */
#define XENSTORE_ERROR_NONE 0 /* No error */
#define XENSTORE_ERROR_COMM 1 /* Communication problem */
#define XENSTORE_ERROR_RINGIDX 2 /* Invalid ring index */
#define XENSTORE_ERROR_PROTO 3 /* Protocol violation (payload too long) */
#endif /* _XS_WIRE_H */ #endif /* _XS_WIRE_H */
...@@ -224,8 +224,10 @@ int xenbus_watch_pathfmt(struct xenbus_device *dev, struct xenbus_watch *watch, ...@@ -224,8 +224,10 @@ int xenbus_watch_pathfmt(struct xenbus_device *dev, struct xenbus_watch *watch,
const char *pathfmt, ...); const char *pathfmt, ...);
int xenbus_switch_state(struct xenbus_device *dev, enum xenbus_state new_state); int xenbus_switch_state(struct xenbus_device *dev, enum xenbus_state new_state);
int xenbus_grant_ring(struct xenbus_device *dev, void *vaddr, int xenbus_setup_ring(struct xenbus_device *dev, gfp_t gfp, void **vaddr,
unsigned int nr_pages, grant_ref_t *grefs); unsigned int nr_pages, grant_ref_t *grefs);
void xenbus_teardown_ring(void **vaddr, unsigned int nr_pages,
grant_ref_t *grefs);
int xenbus_map_ring_valloc(struct xenbus_device *dev, grant_ref_t *gnt_refs, int xenbus_map_ring_valloc(struct xenbus_device *dev, grant_ref_t *gnt_refs,
unsigned int nr_grefs, void **vaddr); unsigned int nr_grefs, void **vaddr);
......
...@@ -143,12 +143,12 @@ void xen_snd_front_evtchnl_flush(struct xen_snd_front_evtchnl *channel) ...@@ -143,12 +143,12 @@ void xen_snd_front_evtchnl_flush(struct xen_snd_front_evtchnl *channel)
static void evtchnl_free(struct xen_snd_front_info *front_info, static void evtchnl_free(struct xen_snd_front_info *front_info,
struct xen_snd_front_evtchnl *channel) struct xen_snd_front_evtchnl *channel)
{ {
unsigned long page = 0; void *page = NULL;
if (channel->type == EVTCHNL_TYPE_REQ) if (channel->type == EVTCHNL_TYPE_REQ)
page = (unsigned long)channel->u.req.ring.sring; page = channel->u.req.ring.sring;
else if (channel->type == EVTCHNL_TYPE_EVT) else if (channel->type == EVTCHNL_TYPE_EVT)
page = (unsigned long)channel->u.evt.page; page = channel->u.evt.page;
if (!page) if (!page)
return; return;
...@@ -167,10 +167,7 @@ static void evtchnl_free(struct xen_snd_front_info *front_info, ...@@ -167,10 +167,7 @@ static void evtchnl_free(struct xen_snd_front_info *front_info,
xenbus_free_evtchn(front_info->xb_dev, channel->port); xenbus_free_evtchn(front_info->xb_dev, channel->port);
/* End access and free the page. */ /* End access and free the page. */
if (channel->gref != GRANT_INVALID_REF) xenbus_teardown_ring(&page, 1, &channel->gref);
gnttab_end_foreign_access(channel->gref, page);
else
free_page(page);
memset(channel, 0, sizeof(*channel)); memset(channel, 0, sizeof(*channel));
} }
...@@ -196,8 +193,7 @@ static int evtchnl_alloc(struct xen_snd_front_info *front_info, int index, ...@@ -196,8 +193,7 @@ static int evtchnl_alloc(struct xen_snd_front_info *front_info, int index,
enum xen_snd_front_evtchnl_type type) enum xen_snd_front_evtchnl_type type)
{ {
struct xenbus_device *xb_dev = front_info->xb_dev; struct xenbus_device *xb_dev = front_info->xb_dev;
unsigned long page; void *page;
grant_ref_t gref;
irq_handler_t handler; irq_handler_t handler;
char *handler_name = NULL; char *handler_name = NULL;
int ret; int ret;
...@@ -207,12 +203,9 @@ static int evtchnl_alloc(struct xen_snd_front_info *front_info, int index, ...@@ -207,12 +203,9 @@ static int evtchnl_alloc(struct xen_snd_front_info *front_info, int index,
channel->index = index; channel->index = index;
channel->front_info = front_info; channel->front_info = front_info;
channel->state = EVTCHNL_STATE_DISCONNECTED; channel->state = EVTCHNL_STATE_DISCONNECTED;
channel->gref = GRANT_INVALID_REF; ret = xenbus_setup_ring(xb_dev, GFP_KERNEL, &page, 1, &channel->gref);
page = get_zeroed_page(GFP_KERNEL); if (ret)
if (!page) {
ret = -ENOMEM;
goto fail; goto fail;
}
handler_name = kasprintf(GFP_KERNEL, "%s-%s", XENSND_DRIVER_NAME, handler_name = kasprintf(GFP_KERNEL, "%s-%s", XENSND_DRIVER_NAME,
type == EVTCHNL_TYPE_REQ ? type == EVTCHNL_TYPE_REQ ?
...@@ -226,33 +219,18 @@ static int evtchnl_alloc(struct xen_snd_front_info *front_info, int index, ...@@ -226,33 +219,18 @@ static int evtchnl_alloc(struct xen_snd_front_info *front_info, int index,
mutex_init(&channel->ring_io_lock); mutex_init(&channel->ring_io_lock);
if (type == EVTCHNL_TYPE_REQ) { if (type == EVTCHNL_TYPE_REQ) {
struct xen_sndif_sring *sring = (struct xen_sndif_sring *)page; struct xen_sndif_sring *sring = page;
init_completion(&channel->u.req.completion); init_completion(&channel->u.req.completion);
mutex_init(&channel->u.req.req_io_lock); mutex_init(&channel->u.req.req_io_lock);
SHARED_RING_INIT(sring); XEN_FRONT_RING_INIT(&channel->u.req.ring, sring, XEN_PAGE_SIZE);
FRONT_RING_INIT(&channel->u.req.ring, sring, XEN_PAGE_SIZE);
ret = xenbus_grant_ring(xb_dev, sring, 1, &gref);
if (ret < 0) {
channel->u.req.ring.sring = NULL;
goto fail;
}
handler = evtchnl_interrupt_req; handler = evtchnl_interrupt_req;
} else { } else {
ret = gnttab_grant_foreign_access(xb_dev->otherend_id, channel->u.evt.page = page;
virt_to_gfn((void *)page), 0);
if (ret < 0)
goto fail;
channel->u.evt.page = (struct xensnd_event_page *)page;
gref = ret;
handler = evtchnl_interrupt_evt; handler = evtchnl_interrupt_evt;
} }
channel->gref = gref;
ret = xenbus_alloc_evtchn(xb_dev, &channel->port); ret = xenbus_alloc_evtchn(xb_dev, &channel->port);
if (ret < 0) if (ret < 0)
goto fail; goto fail;
...@@ -279,8 +257,6 @@ static int evtchnl_alloc(struct xen_snd_front_info *front_info, int index, ...@@ -279,8 +257,6 @@ static int evtchnl_alloc(struct xen_snd_front_info *front_info, int index,
return 0; return 0;
fail: fail:
if (page)
free_page(page);
kfree(handler_name); kfree(handler_name);
dev_err(&xb_dev->dev, "Failed to allocate ring: %d\n", ret); dev_err(&xb_dev->dev, "Failed to allocate ring: %d\n", ret);
return ret; return ret;
......
...@@ -15,15 +15,6 @@ ...@@ -15,15 +15,6 @@
struct xen_snd_front_info; struct xen_snd_front_info;
#ifndef GRANT_INVALID_REF
/*
* FIXME: usage of grant reference 0 as invalid grant reference:
* grant reference 0 is valid, but never exposed to a PV driver,
* because of the fact it is already in use/reserved by the PV console.
*/
#define GRANT_INVALID_REF 0
#endif
/* Timeout in ms to wait for backend to respond. */ /* Timeout in ms to wait for backend to respond. */
#define VSND_WAIT_BACK_MS 3000 #define VSND_WAIT_BACK_MS 3000
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment