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:
What: /sys/module/xen_blkback/parameters/buffer_squeeze_duration_ms
Date: December 2019
KernelVersion: 5.6
Contact: SeongJae Park <sj@kernel.org>
Contact: Maximilian Heyne <mheyne@amazon.de>
Description:
When memory pressure is reported to blkback this option
controls the duration in milliseconds that blkback will not
......@@ -39,7 +39,7 @@ Description:
What: /sys/module/xen_blkback/parameters/feature_persistent
Date: September 2020
KernelVersion: 5.10
Contact: SeongJae Park <sj@kernel.org>
Contact: Maximilian Heyne <mheyne@amazon.de>
Description:
Whether to enable the persistent grants feature or not. Note
that this option only takes effect on newly created backends.
......
......@@ -12,7 +12,7 @@ Description:
What: /sys/module/xen_blkfront/parameters/feature_persistent
Date: September 2020
KernelVersion: 5.10
Contact: SeongJae Park <sj@kernel.org>
Contact: Maximilian Heyne <mheyne@amazon.de>
Description:
Whether to enable the persistent grants feature or not. Note
that this option only takes effect on newly created frontends.
......
......@@ -30,7 +30,6 @@
#include <linux/pci.h>
#include <linux/gfp.h>
#include <linux/edd.h>
#include <linux/objtool.h>
#include <xen/xen.h>
#include <xen/events.h>
......@@ -165,7 +164,6 @@ static void xen_cpuid(unsigned int *ax, unsigned int *bx,
*bx &= maskebx;
}
STACK_FRAME_NON_STANDARD(xen_cpuid); /* XEN_EMULATE_PREFIX */
static bool __init xen_check_mwait(void)
{
......
......@@ -229,8 +229,6 @@ static unsigned int nr_minors;
static unsigned long *minors;
static DEFINE_SPINLOCK(minor_lock);
#define GRANT_INVALID_REF 0
#define PARTS_PER_DISK 16
#define PARTS_PER_EXT_DISK 256
......@@ -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->gref = GRANT_INVALID_REF;
gnt_list_entry->gref = INVALID_GRANT_REF;
list_add(&gnt_list_entry->node, &rinfo->grants);
i++;
}
......@@ -350,7 +348,7 @@ static struct grant *get_free_grant(struct blkfront_ring_info *rinfo)
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--;
return gnt_list_entry;
......@@ -372,7 +370,7 @@ static struct grant *get_grant(grant_ref_t *gref_head,
struct grant *gnt_list_entry = get_free_grant(rinfo);
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;
/* Assign a gref to this page */
......@@ -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 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;
/* Assign a gref to this page */
......@@ -1221,7 +1219,7 @@ static void blkif_free_ring(struct blkfront_ring_info *rinfo)
list_for_each_entry_safe(persistent_gnt, n,
&rinfo->grants, 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,
0UL);
rinfo->persistent_gnts_c--;
......@@ -1282,15 +1280,8 @@ static void blkif_free_ring(struct blkfront_ring_info *rinfo)
flush_work(&rinfo->work);
/* Free resources associated with old device channel. */
for (i = 0; i < info->nr_ring_pages; i++) {
if (rinfo->ring_ref[i] != GRANT_INVALID_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;
xenbus_teardown_ring((void **)&rinfo->ring.sring, info->nr_ring_pages,
rinfo->ring_ref);
if (rinfo->irq)
unbind_from_irqhandler(rinfo->irq, rinfo);
......@@ -1475,7 +1466,7 @@ static int blkif_completion(unsigned long *id,
* to the tail of the list, so it will not be picked
* 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);
}
}
......@@ -1500,7 +1491,7 @@ static int blkif_completion(unsigned long *id,
indirect_page = s->indirect_grants[i]->page;
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);
}
}
......@@ -1681,30 +1672,16 @@ static int setup_blkring(struct xenbus_device *dev,
struct blkfront_ring_info *rinfo)
{
struct blkif_sring *sring;
int err, i;
int err;
struct blkfront_info *info = rinfo->dev_info;
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);
if (!sring) {
xenbus_dev_fatal(dev, -ENOMEM, "allocating shared ring");
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;
err = xenbus_setup_ring(dev, GFP_NOIO, (void **)&sring,
info->nr_ring_pages, rinfo->ring_ref);
if (err)
goto fail;
}
for (i = 0; i < info->nr_ring_pages; i++)
rinfo->ring_ref[i] = gref[i];
XEN_FRONT_RING_INIT(&rinfo->ring, sring, ring_size);
err = xenbus_alloc_evtchn(dev, &rinfo->evtchn);
if (err)
......@@ -2544,13 +2521,13 @@ static void purge_persistent_grants(struct blkfront_info *info)
list_for_each_entry_safe(gnt_list_entry, tmp, &rinfo->grants,
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))
continue;
list_del(&gnt_list_entry->node);
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);
}
......
......@@ -253,20 +253,12 @@ static int setup_ring(struct xenbus_device *dev, struct tpm_private *priv)
struct xenbus_transaction xbt;
const char *message = NULL;
int rv;
grant_ref_t gref;
priv->shr = (void *)__get_free_page(GFP_KERNEL|__GFP_ZERO);
if (!priv->shr) {
xenbus_dev_fatal(dev, -ENOMEM, "allocating shared ring");
return -ENOMEM;
}
rv = xenbus_grant_ring(dev, priv->shr, 1, &gref);
rv = xenbus_setup_ring(dev, GFP_KERNEL, (void **)&priv->shr, 1,
&priv->ring_ref);
if (rv < 0)
return rv;
priv->ring_ref = gref;
rv = xenbus_alloc_evtchn(dev, &priv->evtchn);
if (rv)
return rv;
......@@ -331,11 +323,7 @@ static void ring_free(struct tpm_private *priv)
if (!priv)
return;
if (priv->ring_ref)
gnttab_end_foreign_access(priv->ring_ref,
(unsigned long)priv->shr);
else
free_page((unsigned long)priv->shr);
xenbus_teardown_ring((void **)&priv->shr, 1, &priv->ring_ref);
if (priv->irq)
unbind_from_irqhandler(priv->irq, priv);
......
......@@ -80,15 +80,6 @@ struct drm_pending_vblank_event;
/* timeout in ms to wait for backend to respond */
#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 xenbus_device *xb_dev;
struct xen_drm_front_drm_info *drm_info;
......
......@@ -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,
struct xen_drm_front_evtchnl *evtchnl)
{
unsigned long page = 0;
void *page = NULL;
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)
page = (unsigned long)evtchnl->u.evt.page;
page = evtchnl->u.evt.page;
if (!page)
return;
......@@ -147,8 +147,7 @@ static void evtchnl_free(struct xen_drm_front_info *front_info,
xenbus_free_evtchn(front_info->xb_dev, evtchnl->port);
/* end access and free the page */
if (evtchnl->gref != GRANT_INVALID_REF)
gnttab_end_foreign_access(evtchnl->gref, page);
xenbus_teardown_ring(&page, 1, &evtchnl->gref);
memset(evtchnl, 0, sizeof(*evtchnl));
}
......@@ -158,8 +157,7 @@ static int evtchnl_alloc(struct xen_drm_front_info *front_info, int index,
enum xen_drm_front_evtchnl_type type)
{
struct xenbus_device *xb_dev = front_info->xb_dev;
unsigned long page;
grant_ref_t gref;
void *page;
irq_handler_t handler;
int ret;
......@@ -168,44 +166,25 @@ static int evtchnl_alloc(struct xen_drm_front_info *front_info, int index,
evtchnl->index = index;
evtchnl->front_info = front_info;
evtchnl->state = EVTCHNL_STATE_DISCONNECTED;
evtchnl->gref = GRANT_INVALID_REF;
page = get_zeroed_page(GFP_NOIO | __GFP_HIGH);
if (!page) {
ret = -ENOMEM;
ret = xenbus_setup_ring(xb_dev, GFP_NOIO | __GFP_HIGH, &page,
1, &evtchnl->gref);
if (ret)
goto fail;
}
if (type == EVTCHNL_TYPE_REQ) {
struct xen_displif_sring *sring;
init_completion(&evtchnl->u.req.completion);
mutex_init(&evtchnl->u.req.req_io_lock);
sring = (struct xen_displif_sring *)page;
SHARED_RING_INIT(sring);
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;
}
sring = page;
XEN_FRONT_RING_INIT(&evtchnl->u.req.ring, sring, XEN_PAGE_SIZE);
handler = evtchnl_interrupt_ctrl;
} else {
ret = gnttab_grant_foreign_access(xb_dev->otherend_id,
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;
evtchnl->u.evt.page = page;
handler = evtchnl_interrupt_evt;
}
evtchnl->gref = gref;
ret = xenbus_alloc_evtchn(xb_dev, &evtchnl->port);
if (ret < 0)
......
......@@ -78,8 +78,6 @@ struct netfront_cb {
#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_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,
{
int i = xennet_rxidx(ri);
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;
}
......@@ -432,7 +430,7 @@ static bool xennet_tx_buf_gc(struct netfront_queue *queue)
}
gnttab_release_grant_reference(
&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;
add_id_to_list(&queue->tx_skb_freelist, queue->tx_link, id);
dev_kfree_skb_irq(skb);
......@@ -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);
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);
}
......@@ -1021,7 +1019,7 @@ static int xennet_get_responses(struct netfront_queue *queue,
* the backend driver. In future this should flag the bad
* situation to the system controller to reboot the backend.
*/
if (ref == GRANT_INVALID_REF) {
if (ref == INVALID_GRANT_REF) {
if (net_ratelimit())
dev_warn(dev, "Bad rx response id %d.\n",
rx->id);
......@@ -1390,7 +1388,7 @@ static void xennet_release_tx_bufs(struct netfront_queue *queue)
gnttab_end_foreign_access(queue->grant_tx_ref[i],
(unsigned long)page_address(queue->grant_tx_page[i]));
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);
dev_kfree_skb_irq(skb);
}
......@@ -1411,7 +1409,7 @@ static void xennet_release_rx_bufs(struct netfront_queue *queue)
continue;
ref = queue->grant_rx_ref[id];
if (ref == GRANT_INVALID_REF)
if (ref == INVALID_GRANT_REF)
continue;
page = skb_frag_page(&skb_shinfo(skb)->frags[0]);
......@@ -1422,7 +1420,7 @@ static void xennet_release_rx_bufs(struct netfront_queue *queue)
get_page(page);
gnttab_end_foreign_access(ref,
(unsigned long)page_address(page));
queue->grant_rx_ref[id] = GRANT_INVALID_REF;
queue->grant_rx_ref[id] = INVALID_GRANT_REF;
kfree_skb(skb);
}
......@@ -1500,7 +1498,7 @@ static bool xennet_handle_rx(struct netfront_queue *queue, unsigned int *eoi)
return false;
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) {
queue->rx_rsp_unconsumed = work_queued;
*eoi = 0;
......@@ -1761,7 +1759,7 @@ static int netfront_probe(struct xenbus_device *dev,
static void xennet_end_access(int ref, void *page)
{
/* 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);
}
......@@ -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->rx_ring_ref, queue->rx.sring);
queue->tx_ring_ref = GRANT_INVALID_REF;
queue->rx_ring_ref = GRANT_INVALID_REF;
queue->tx_ring_ref = INVALID_GRANT_REF;
queue->rx_ring_ref = INVALID_GRANT_REF;
queue->tx.sring = NULL;
queue->rx.sring = NULL;
......@@ -1923,42 +1921,27 @@ static int setup_netfront(struct xenbus_device *dev,
struct netfront_queue *queue, unsigned int feature_split_evtchn)
{
struct xen_netif_tx_sring *txs;
struct xen_netif_rx_sring *rxs = NULL;
grant_ref_t gref;
struct xen_netif_rx_sring *rxs;
int err;
queue->tx_ring_ref = GRANT_INVALID_REF;
queue->rx_ring_ref = GRANT_INVALID_REF;
queue->tx_ring_ref = INVALID_GRANT_REF;
queue->rx_ring_ref = INVALID_GRANT_REF;
queue->rx.sring = NULL;
queue->tx.sring = NULL;
txs = (struct xen_netif_tx_sring *)get_zeroed_page(GFP_NOIO | __GFP_HIGH);
if (!txs) {
err = -ENOMEM;
xenbus_dev_fatal(dev, err, "allocating tx ring page");
err = xenbus_setup_ring(dev, GFP_NOIO | __GFP_HIGH, (void **)&txs,
1, &queue->tx_ring_ref);
if (err)
goto fail;
}
SHARED_RING_INIT(txs);
FRONT_RING_INIT(&queue->tx, txs, XEN_PAGE_SIZE);
err = xenbus_grant_ring(dev, txs, 1, &gref);
if (err < 0)
goto fail;
queue->tx_ring_ref = gref;
XEN_FRONT_RING_INIT(&queue->tx, txs, XEN_PAGE_SIZE);
rxs = (struct xen_netif_rx_sring *)get_zeroed_page(GFP_NOIO | __GFP_HIGH);
if (!rxs) {
err = -ENOMEM;
xenbus_dev_fatal(dev, err, "allocating rx ring page");
err = xenbus_setup_ring(dev, GFP_NOIO | __GFP_HIGH, (void **)&rxs,
1, &queue->rx_ring_ref);
if (err)
goto fail;
}
SHARED_RING_INIT(rxs);
FRONT_RING_INIT(&queue->rx, rxs, XEN_PAGE_SIZE);
err = xenbus_grant_ring(dev, rxs, 1, &gref);
if (err < 0)
goto fail;
queue->rx_ring_ref = gref;
XEN_FRONT_RING_INIT(&queue->rx, rxs, XEN_PAGE_SIZE);
if (feature_split_evtchn)
err = setup_netfront_split(queue);
......@@ -1974,24 +1957,10 @@ static int setup_netfront(struct xenbus_device *dev,
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:
if (queue->rx_ring_ref != GRANT_INVALID_REF) {
gnttab_end_foreign_access(queue->rx_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);
}
xenbus_teardown_ring((void **)&queue->rx.sring, 1, &queue->rx_ring_ref);
xenbus_teardown_ring((void **)&queue->tx.sring, 1, &queue->tx_ring_ref);
return err;
}
......@@ -2020,7 +1989,7 @@ static int xennet_init_queue(struct netfront_queue *queue)
queue->tx_pend_queue = TX_LINK_NONE;
for (i = 0; i < NET_TX_RING_SIZE; i++) {
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->tx_link[NET_TX_RING_SIZE - 1] = TX_LINK_NONE;
......@@ -2028,7 +1997,7 @@ static int xennet_init_queue(struct netfront_queue *queue)
/* Clear out rx_skbs */
for (i = 0; i < NET_RX_RING_SIZE; i++) {
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 */
......
......@@ -709,9 +709,8 @@ static struct pcifront_device *alloc_pdev(struct xenbus_device *xdev)
if (pdev == NULL)
goto out;
pdev->sh_info =
(struct xen_pci_sharedinfo *)__get_free_page(GFP_KERNEL);
if (pdev->sh_info == NULL) {
if (xenbus_setup_ring(xdev, GFP_KERNEL, (void **)&pdev->sh_info, 1,
&pdev->gnt_ref)) {
kfree(pdev);
pdev = NULL;
goto out;
......@@ -729,7 +728,6 @@ static struct pcifront_device *alloc_pdev(struct xenbus_device *xdev)
spin_lock_init(&pdev->sh_info_lock);
pdev->evtchn = INVALID_EVTCHN;
pdev->gnt_ref = INVALID_GRANT_REF;
pdev->irq = -1;
INIT_WORK(&pdev->op_work, pcifront_do_aer);
......@@ -754,11 +752,7 @@ static void free_pdev(struct pcifront_device *pdev)
if (pdev->evtchn != INVALID_EVTCHN)
xenbus_free_evtchn(pdev->xdev, pdev->evtchn);
if (pdev->gnt_ref != INVALID_GRANT_REF)
gnttab_end_foreign_access(pdev->gnt_ref,
(unsigned long)pdev->sh_info);
else
free_page((unsigned long)pdev->sh_info);
xenbus_teardown_ring((void **)&pdev->sh_info, 1, &pdev->gnt_ref);
dev_set_drvdata(&pdev->xdev->dev, NULL);
......@@ -769,13 +763,6 @@ static int pcifront_publish_info(struct pcifront_device *pdev)
{
int err = 0;
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);
if (err)
......
This diff is collapsed.
......@@ -87,8 +87,6 @@ struct xenhcd_info {
bool error;
};
#define GRANT_INVALID_REF 0
#define XENHCD_RING_JIFFIES (HZ/200)
#define XENHCD_SCAN_JIFFIES 1
......@@ -1100,19 +1098,10 @@ static void xenhcd_destroy_rings(struct xenhcd_info *info)
unbind_from_irqhandler(info->irq, info);
info->irq = 0;
if (info->urb_ring_ref != GRANT_INVALID_REF) {
gnttab_end_foreign_access(info->urb_ring_ref,
(unsigned long)info->urb_ring.sring);
info->urb_ring_ref = GRANT_INVALID_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;
xenbus_teardown_ring((void **)&info->urb_ring.sring, 1,
&info->urb_ring_ref);
xenbus_teardown_ring((void **)&info->conn_ring.sring, 1,
&info->conn_ring_ref);
}
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_conn_sring *conn_sring;
grant_ref_t gref;
int err;
info->urb_ring_ref = GRANT_INVALID_REF;
info->conn_ring_ref = GRANT_INVALID_REF;
urb_sring = (struct xenusb_urb_sring *)get_zeroed_page(
GFP_NOIO | __GFP_HIGH);
if (!urb_sring) {
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;
info->conn_ring_ref = INVALID_GRANT_REF;
err = xenbus_setup_ring(dev, GFP_NOIO | __GFP_HIGH,
(void **)&urb_sring, 1, &info->urb_ring_ref);
if (err) {
xenbus_dev_fatal(dev, err, "allocating urb ring");
return err;
}
SHARED_RING_INIT(conn_sring);
FRONT_RING_INIT(&info->conn_ring, conn_sring, PAGE_SIZE);
XEN_FRONT_RING_INIT(&info->urb_ring, urb_sring, PAGE_SIZE);
err = xenbus_grant_ring(dev, conn_sring, 1, &gref);
if (err < 0) {
free_page((unsigned long)conn_sring);
info->conn_ring.sring = NULL;
err = xenbus_setup_ring(dev, GFP_NOIO | __GFP_HIGH,
(void **)&conn_sring, 1, &info->conn_ring_ref);
if (err) {
xenbus_dev_fatal(dev, err, "allocating conn ring");
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);
if (err) {
......
......@@ -24,15 +24,6 @@
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_priv *priv;
struct dma_buf *dmabuf;
......@@ -532,7 +523,7 @@ static void dmabuf_imp_end_foreign_access(u32 *refs, int count)
int 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);
}
......@@ -567,7 +558,7 @@ static struct gntdev_dmabuf *dmabuf_imp_alloc_storage(int count)
gntdev_dmabuf->nr_pages = count;
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;
......
......@@ -66,8 +66,6 @@
#include <asm/sync_bitops.h>
/* External tools reserve first few grant table entries. */
#define NR_RESERVED_ENTRIES 8
#define GNTTAB_LIST_END 0xffffffff
static grant_ref_t **gnttab_list;
......@@ -209,6 +207,10 @@ static inline void check_free_callbacks(void)
static void put_free_entry(grant_ref_t ref)
{
unsigned long flags;
if (unlikely(ref < GNTTAB_NR_RESERVED_ENTRIES))
return;
spin_lock_irqsave(&gnttab_list_lock, flags);
gnttab_entry(ref) = gnttab_free_head;
gnttab_free_head = ref;
......@@ -1465,12 +1467,12 @@ int gnttab_init(void)
nr_init_grefs = nr_grant_frames *
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(nr_init_grefs - 1) = GNTTAB_LIST_END;
gnttab_free_count = nr_init_grefs - NR_RESERVED_ENTRIES;
gnttab_free_head = NR_RESERVED_ENTRIES;
gnttab_free_count = nr_init_grefs - GNTTAB_NR_RESERVED_ENTRIES;
gnttab_free_head = GNTTAB_NR_RESERVED_ENTRIES;
printk("Grant table initialized\n");
return 0;
......
......@@ -21,15 +21,6 @@
#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
* that contains grant references to the pages of the shared
......@@ -38,6 +29,7 @@
*/
struct xen_page_directory {
grant_ref_t gref_dir_next_page;
#define XEN_GREF_LIST_END 0
grant_ref_t gref[1]; /* Variable length */
};
......@@ -83,7 +75,7 @@ grant_ref_t
xen_front_pgdir_shbuf_get_dir_start(struct xen_front_pgdir_shbuf *buf)
{
if (!buf->grefs)
return GRANT_INVALID_REF;
return INVALID_GRANT_REF;
return buf->grefs[0];
}
......@@ -142,7 +134,7 @@ void xen_front_pgdir_shbuf_free(struct xen_front_pgdir_shbuf *buf)
int 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);
}
kfree(buf->grefs);
......@@ -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. */
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)
if (grefs_left <= XEN_NUM_GREFS_PER_PAGE) {
to_copy = grefs_left;
page_dir->gref_dir_next_page = GRANT_INVALID_REF;
page_dir->gref_dir_next_page = XEN_GREF_LIST_END;
} else {
to_copy = XEN_NUM_GREFS_PER_PAGE;
page_dir->gref_dir_next_page = buf->grefs[i + 1];
......
......@@ -280,6 +280,82 @@ static void scsiback_free_translation_entry(struct kref *kref)
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,
char *sense_buffer, int32_t result, uint32_t resid,
uint16_t rqid)
......@@ -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);
info->ring.rsp_prod_pvt++;
ring_res->rslt = result;
ring_res->rslt = scsiback_result(result);
ring_res->rqid = rqid;
if (sense_buffer != NULL &&
......@@ -555,7 +631,7 @@ static void scsiback_device_action(struct vscsibk_pend *pending_req,
struct scsiback_nexus *nexus = tpg->tpg_nexus;
struct se_cmd *se_cmd = &pending_req->se_cmd;
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);
......@@ -569,7 +645,7 @@ static void scsiback_device_action(struct vscsibk_pend *pending_req,
wait_for_completion(&pending_req->tmr_done);
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);
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,
__xenbus_switch_state(dev, XenbusStateClosing, 1);
}
/**
* xenbus_grant_ring
/*
* xenbus_setup_ring
* @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
* @grefs: grant reference array to be filled in
*
* Grant access to the given @vaddr to the peer of the given device.
* Then fill in @grefs with grant references. Return 0 on success, or
* -errno on error. On error, the device will switch to
* XenbusStateClosing, and the error will be saved in the store.
* Allocate physically contiguous pages for a shared ring buffer and grant it
* to the peer of the given device. The ring buffer is initially filled with
* zeroes. The virtual address of the ring is stored at @vaddr and the
* 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)
{
int err;
unsigned int i;
unsigned long ring_size = nr_pages * XEN_PAGE_SIZE;
grant_ref_t gref_head;
unsigned int i;
int ret;
err = gnttab_alloc_grant_references(nr_pages, &gref_head);
if (err) {
xenbus_dev_fatal(dev, err, "granting access to ring page");
return err;
*vaddr = alloc_pages_exact(ring_size, gfp | __GFP_ZERO);
if (!*vaddr) {
ret = -ENOMEM;
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++) {
unsigned long gfn;
if (is_vmalloc_addr(vaddr))
gfn = pfn_to_gfn(vmalloc_to_pfn(vaddr));
if (is_vmalloc_addr(*vaddr))
gfn = pfn_to_gfn(vmalloc_to_pfn(vaddr[i]));
else
gfn = virt_to_gfn(vaddr);
gfn = virt_to_gfn(vaddr[i]);
grefs[i] = gnttab_claim_grant_reference(&gref_head);
gnttab_grant_foreign_access_ref(grefs[i], dev->otherend_id,
gfn, 0);
vaddr = vaddr + XEN_PAGE_SIZE;
}
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
......
......@@ -65,6 +65,7 @@
#include "xenbus.h"
static int xs_init_irq;
int xen_store_evtchn;
EXPORT_SYMBOL_GPL(xen_store_evtchn);
......@@ -750,6 +751,20 @@ static void xenbus_probe(void)
{
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
* xs_init() in case callbacks were not operational yet.
......@@ -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
* 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 ||
(xen_store_domain_type == XS_HVM &&
!xs_hvm_defer_init_for_callback()))
!xs_hvm_defer_init_for_callback() &&
xen_store_interface != NULL))
xenbus_probe();
/*
* For XS_LOCAL, spawn a thread which will wait for xenstored
* or a xenstore-stubdom to be started, then probe. It will be
* triggered when communication starts happening, by waiting
* on xb_waitq.
* For XS_LOCAL or when xen_store_interface is not ready, spawn a
* thread which will wait for xenstored or a xenstore-stubdom to be
* started, then probe. It will be triggered when communication
* 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;
probe_task = kthread_run(xenbus_probe_thread, NULL,
......@@ -907,10 +924,25 @@ static struct notifier_block xenbus_resume_nb = {
.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)
{
int err;
uint64_t v = 0;
bool wait = false;
xen_store_domain_type = XS_UNKNOWN;
if (!xen_domain())
......@@ -957,25 +989,44 @@ static int __init xenbus_init(void)
* been properly initialized. Instead of attempting to map a
* 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;
goto out_error;
}
/* Avoid truncation on 32-bit. */
if (v == ~0ULL) {
wait = true;
} else {
/* Avoid truncation on 32-bit. */
#if BITS_PER_LONG == 32
if (v > ULONG_MAX) {
pr_err("%s: cannot handle HVM_PARAM_STORE_PFN=%llx > ULONG_MAX\n",
__func__, v);
err = -EINVAL;
goto out_error;
}
if (v > ULONG_MAX) {
pr_err("%s: cannot handle HVM_PARAM_STORE_PFN=%llx > ULONG_MAX\n",
__func__, v);
err = -EINVAL;
goto out_error;
}
#endif
xen_store_gfn = (unsigned long)v;
xen_store_interface =
xen_remap(xen_store_gfn << XEN_PAGE_SHIFT,
XEN_PAGE_SIZE);
xen_store_gfn = (unsigned long)v;
xen_store_interface =
xen_remap(xen_store_gfn << XEN_PAGE_SHIFT,
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;
default:
pr_warn("Xenstore state unknown\n");
......
......@@ -57,8 +57,6 @@
#define INVALID_GRANT_REF ((grant_ref_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 */
#define NR_GRANT_FRAMES 4
......
This diff is collapsed.
......@@ -72,9 +72,8 @@ typedef unsigned int RING_IDX;
* of the shared memory area (PAGE_SIZE, for instance). To initialise
* the front half:
*
* mytag_front_ring_t front_ring;
* SHARED_RING_INIT((mytag_sring_t *)shared_page);
* FRONT_RING_INIT(&front_ring, (mytag_sring_t *)shared_page, PAGE_SIZE);
* mytag_front_ring_t ring;
* XEN_FRONT_RING_INIT(&ring, (mytag_sring_t *)shared_page, PAGE_SIZE);
*
* Initializing the back follows similarly (note that only the front
* initializes the shared ring):
......@@ -146,6 +145,11 @@ struct __name##_back_ring { \
#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 { \
(_r)->rsp_prod_pvt = (_i); \
(_r)->req_cons = (_i); \
......@@ -170,16 +174,21 @@ struct __name##_back_ring { \
(RING_FREE_REQUESTS(_r) == 0)
/* 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)
#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 rsp = RING_SIZE(_r) - \
((_r)->req_cons - (_r)->rsp_prod_pvt); \
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. */
#define RING_GET_REQUEST(_r, _idx) \
(&((_r)->sring->ring[((_idx) & (RING_SIZE(_r) - 1))].req))
......
......@@ -43,7 +43,7 @@
*
* 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.
* "naa.60014054ac780582").
* "naa.60014054ac780582:0").
*
* v-dev
* Values: string
......@@ -87,6 +87,75 @@
* 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 */
/*
......@@ -117,7 +186,8 @@
* (plus the set VSCSIIF_SG_GRANT bit), the number of scsiif_request_segment
* 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
* 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
......@@ -154,12 +224,14 @@
/*
* based on Linux kernel 2.6.18, still valid
*
* Changing these values requires support of multiple protocols via the rings
* as "old clients" will blindly use these values and the resulting structure
* sizes.
*/
#define VSCSIIF_MAX_COMMAND_SIZE 16
#define VSCSIIF_SENSE_BUFFERSIZE 96
#define VSCSIIF_PAGE_SIZE 4096
struct scsiif_request_segment {
grant_ref_t gref;
......@@ -167,7 +239,8 @@ struct scsiif_request_segment {
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 */
struct vscsiif_request {
......@@ -207,6 +280,58 @@ struct vscsiif_response {
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);
#endif /*__XEN__PUBLIC_IO_SCSI_H__*/
#endif /*__XEN__PUBLIC_IO_SCSI_H__*/
......@@ -10,7 +10,8 @@
enum xsd_sockmsg_type
{
XS_DEBUG,
XS_CONTROL,
#define XS_DEBUG XS_CONTROL
XS_DIRECTORY,
XS_READ,
XS_GET_PERMS,
......@@ -30,8 +31,13 @@ enum xsd_sockmsg_type
XS_IS_DOMAIN_INTRODUCED,
XS_RESUME,
XS_SET_TARGET,
XS_RESTRICT,
XS_RESET_WATCHES,
/* XS_RESTRICT has been removed */
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"
......@@ -59,7 +65,8 @@ static struct xsd_errors xsd_errors[] __attribute__((unused)) = {
XSD_ERROR(EROFS),
XSD_ERROR(EBUSY),
XSD_ERROR(EAGAIN),
XSD_ERROR(EISCONN)
XSD_ERROR(EISCONN),
XSD_ERROR(E2BIG)
};
struct xsd_sockmsg
......@@ -87,9 +94,31 @@ struct xenstore_domain_interface {
char rsp[XENSTORE_RING_SIZE]; /* Replies and async watch events. */
XENSTORE_RING_IDX req_cons, req_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. */
#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 */
......@@ -224,8 +224,10 @@ int xenbus_watch_pathfmt(struct xenbus_device *dev, struct xenbus_watch *watch,
const char *pathfmt, ...);
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);
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,
unsigned int nr_grefs, void **vaddr);
......
......@@ -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,
struct xen_snd_front_evtchnl *channel)
{
unsigned long page = 0;
void *page = NULL;
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)
page = (unsigned long)channel->u.evt.page;
page = channel->u.evt.page;
if (!page)
return;
......@@ -167,10 +167,7 @@ static void evtchnl_free(struct xen_snd_front_info *front_info,
xenbus_free_evtchn(front_info->xb_dev, channel->port);
/* End access and free the page. */
if (channel->gref != GRANT_INVALID_REF)
gnttab_end_foreign_access(channel->gref, page);
else
free_page(page);
xenbus_teardown_ring(&page, 1, &channel->gref);
memset(channel, 0, sizeof(*channel));
}
......@@ -196,8 +193,7 @@ static int evtchnl_alloc(struct xen_snd_front_info *front_info, int index,
enum xen_snd_front_evtchnl_type type)
{
struct xenbus_device *xb_dev = front_info->xb_dev;
unsigned long page;
grant_ref_t gref;
void *page;
irq_handler_t handler;
char *handler_name = NULL;
int ret;
......@@ -207,12 +203,9 @@ static int evtchnl_alloc(struct xen_snd_front_info *front_info, int index,
channel->index = index;
channel->front_info = front_info;
channel->state = EVTCHNL_STATE_DISCONNECTED;
channel->gref = GRANT_INVALID_REF;
page = get_zeroed_page(GFP_KERNEL);
if (!page) {
ret = -ENOMEM;
ret = xenbus_setup_ring(xb_dev, GFP_KERNEL, &page, 1, &channel->gref);
if (ret)
goto fail;
}
handler_name = kasprintf(GFP_KERNEL, "%s-%s", XENSND_DRIVER_NAME,
type == EVTCHNL_TYPE_REQ ?
......@@ -226,33 +219,18 @@ static int evtchnl_alloc(struct xen_snd_front_info *front_info, int index,
mutex_init(&channel->ring_io_lock);
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);
mutex_init(&channel->u.req.req_io_lock);
SHARED_RING_INIT(sring);
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;
}
XEN_FRONT_RING_INIT(&channel->u.req.ring, sring, XEN_PAGE_SIZE);
handler = evtchnl_interrupt_req;
} else {
ret = gnttab_grant_foreign_access(xb_dev->otherend_id,
virt_to_gfn((void *)page), 0);
if (ret < 0)
goto fail;
channel->u.evt.page = (struct xensnd_event_page *)page;
gref = ret;
channel->u.evt.page = page;
handler = evtchnl_interrupt_evt;
}
channel->gref = gref;
ret = xenbus_alloc_evtchn(xb_dev, &channel->port);
if (ret < 0)
goto fail;
......@@ -279,8 +257,6 @@ static int evtchnl_alloc(struct xen_snd_front_info *front_info, int index,
return 0;
fail:
if (page)
free_page(page);
kfree(handler_name);
dev_err(&xb_dev->dev, "Failed to allocate ring: %d\n", ret);
return ret;
......
......@@ -15,15 +15,6 @@
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. */
#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