uint16_t rqid;
        uint16_t ref_rqid;
 
+       bool inflight;
+
        unsigned int nr_grants;         /* number of grants in gref[] */
        struct scsiif_request_segment *sg;      /* scatter/gather elements */
        struct scsiif_request_segment seg[VSCSIIF_SG_TABLESIZE];
        struct xenbus_device *dev;
 
        struct Scsi_Host *host;
-       int host_active;
+       enum {
+               STATE_INACTIVE,
+               STATE_ACTIVE,
+               STATE_ERROR
+       }  host_active;
 
        unsigned int evtchn;
        unsigned int irq;
        for (i = 0; i < (shadow->nr_segments & ~VSCSIIF_SG_GRANT); i++)
                ring_req->seg[i] = shadow->seg[i];
 
+       shadow->inflight = true;
+
        RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(ring, notify);
        if (notify)
                notify_remote_via_irq(info->irq);
        return 0;
 }
 
+static void scsifront_set_error(struct vscsifrnt_info *info, const char *msg)
+{
+       shost_printk(KERN_ERR, info->host, KBUILD_MODNAME "%s\n"
+                    "Disabling device for further use\n", msg);
+       info->host_active = STATE_ERROR;
+}
+
 static void scsifront_gnttab_done(struct vscsifrnt_info *info,
                                  struct vscsifrnt_shadow *shadow)
 {
 
        for (i = 0; i < shadow->nr_grants; i++) {
                if (unlikely(!gnttab_try_end_foreign_access(shadow->gref[i]))) {
-                       shost_printk(KERN_ALERT, info->host, KBUILD_MODNAME
-                                    "grant still in use by backend\n");
-                       BUG();
+                       scsifront_set_error(info, "grant still in use by backend");
+                       return;
                }
        }
 
        BUG_ON(sc == NULL);
 
        scsifront_gnttab_done(info, shadow);
+       if (info->host_active == STATE_ERROR)
+               return;
        scsifront_put_rqid(info, id);
 
        set_host_byte(sc, scsifront_host_byte(ring_rsp->rslt));
                        scsifront_wake_up(info);
                return;
        default:
-               shost_printk(KERN_ERR, info->host, KBUILD_MODNAME
-                            "bad reset state %d, possibly leaking %u\n",
-                            shadow->rslt_reset, id);
+               scsifront_set_error(info, "bad reset state");
                break;
        }
        spin_unlock_irqrestore(&info->shadow_lock, flags);
 static void scsifront_do_response(struct vscsifrnt_info *info,
                                  struct vscsiif_response *ring_rsp)
 {
-       if (WARN(ring_rsp->rqid >= VSCSIIF_MAX_REQS ||
-                test_bit(ring_rsp->rqid, info->shadow_free_bitmap),
-                "illegal rqid %u returned by backend!\n", ring_rsp->rqid))
+       struct vscsifrnt_shadow *shadow;
+
+       if (ring_rsp->rqid >= VSCSIIF_MAX_REQS ||
+           !info->shadow[ring_rsp->rqid]->inflight) {
+               scsifront_set_error(info, "illegal rqid returned by backend!");
                return;
+       }
+       shadow = info->shadow[ring_rsp->rqid];
+       shadow->inflight = false;
 
-       if (info->shadow[ring_rsp->rqid]->act == VSCSIIF_ACT_SCSI_CDB)
+       if (shadow->act == VSCSIIF_ACT_SCSI_CDB)
                scsifront_cdb_cmd_done(info, ring_rsp);
        else
                scsifront_sync_cmd_done(info, ring_rsp);
 }
 
-static int scsifront_ring_drain(struct vscsifrnt_info *info)
+static int scsifront_ring_drain(struct vscsifrnt_info *info,
+                               unsigned int *eoiflag)
 {
-       struct vscsiif_response *ring_rsp;
+       struct vscsiif_response ring_rsp;
        RING_IDX i, rp;
        int more_to_do = 0;
 
-       rp = info->ring.sring->rsp_prod;
-       rmb();  /* ordering required respective to dom0 */
+       rp = READ_ONCE(info->ring.sring->rsp_prod);
+       virt_rmb();     /* ordering required respective to backend */
+       if (RING_RESPONSE_PROD_OVERFLOW(&info->ring, rp)) {
+               scsifront_set_error(info, "illegal number of responses");
+               return 0;
+       }
        for (i = info->ring.rsp_cons; i != rp; i++) {
-               ring_rsp = RING_GET_RESPONSE(&info->ring, i);
-               scsifront_do_response(info, ring_rsp);
+               RING_COPY_RESPONSE(&info->ring, i, &ring_rsp);
+               scsifront_do_response(info, &ring_rsp);
+               if (info->host_active == STATE_ERROR)
+                       return 0;
+               *eoiflag &= ~XEN_EOI_FLAG_SPURIOUS;
        }
 
        info->ring.rsp_cons = i;
        return more_to_do;
 }
 
-static int scsifront_cmd_done(struct vscsifrnt_info *info)
+static int scsifront_cmd_done(struct vscsifrnt_info *info,
+                             unsigned int *eoiflag)
 {
        int more_to_do;
        unsigned long flags;
 
        spin_lock_irqsave(info->host->host_lock, flags);
 
-       more_to_do = scsifront_ring_drain(info);
+       more_to_do = scsifront_ring_drain(info, eoiflag);
 
        info->wait_ring_available = 0;
 
 static irqreturn_t scsifront_irq_fn(int irq, void *dev_id)
 {
        struct vscsifrnt_info *info = dev_id;
+       unsigned int eoiflag = XEN_EOI_FLAG_SPURIOUS;
+
+       if (info->host_active == STATE_ERROR) {
+               xen_irq_lateeoi(irq, XEN_EOI_FLAG_SPURIOUS);
+               return IRQ_HANDLED;
+       }
 
-       while (scsifront_cmd_done(info))
+       while (scsifront_cmd_done(info, &eoiflag))
                /* Yield point for this unbounded loop. */
                cond_resched();
 
+       xen_irq_lateeoi(irq, eoiflag);
+
        return IRQ_HANDLED;
 }
 
 static void scsifront_finish_all(struct vscsifrnt_info *info)
 {
-       unsigned i;
+       unsigned int i, dummy;
        struct vscsiif_response resp;
 
-       scsifront_ring_drain(info);
+       scsifront_ring_drain(info, &dummy);
 
        for (i = 0; i < VSCSIIF_MAX_REQS; i++) {
                if (test_bit(i, info->shadow_free_bitmap))
        unsigned long flags;
        int err;
 
+       if (info->host_active == STATE_ERROR)
+               return SCSI_MLQUEUE_HOST_BUSY;
+
        sc->result = 0;
 
        shadow->sc  = sc;
        struct vscsifrnt_shadow *shadow, *s = scsi_cmd_priv(sc);
        int err = 0;
 
+       if (info->host_active == STATE_ERROR)
+               return FAILED;
+
        shadow = kzalloc(sizeof(*shadow), GFP_NOIO);
        if (!shadow)
                return FAILED;
        struct vscsifrnt_info *info = shost_priv(sdev->host);
        int err;
 
+       if (info->host_active == STATE_ERROR)
+               return -EIO;
+
        if (info && current == info->curr) {
                err = xenbus_printf(XBT_NIL, info->dev->nodename,
                              info->dev_state_path, "%d", XenbusStateConnected);
                goto free_gnttab;
        }
 
-       err = bind_evtchn_to_irq(info->evtchn);
+       err = bind_evtchn_to_irq_lateeoi(info->evtchn);
        if (err <= 0) {
                xenbus_dev_fatal(dev, err, "bind_evtchn_to_irq");
                goto free_gnttab;
                goto free_sring;
        }
        info->host = host;
-       info->host_active = 1;
+       info->host_active = STATE_ACTIVE;
 
        xenbus_switch_state(dev, XenbusStateInitialised);
 
        pr_debug("%s: %s removed\n", __func__, dev->nodename);
 
        mutex_lock(&scsifront_mutex);
-       if (info->host_active) {
+       if (info->host_active != STATE_INACTIVE) {
                /* Scsi_host not yet removed */
                scsi_remove_host(info->host);
-               info->host_active = 0;
+               info->host_active = STATE_INACTIVE;
        }
        mutex_unlock(&scsifront_mutex);
 
         */
 
        mutex_lock(&scsifront_mutex);
-       if (info->host_active) {
+       if (info->host_active != STATE_INACTIVE) {
                scsi_remove_host(host);
-               info->host_active = 0;
+               info->host_active = STATE_INACTIVE;
        }
        mutex_unlock(&scsifront_mutex);
 
        unsigned int hst, chn, tgt, lun;
        struct scsi_device *sdev;
 
+       if (info->host_active == STATE_ERROR)
+               return;
+
        dir = xenbus_directory(XBT_NIL, dev->otherend, "vscsi-devs", &dir_n);
        if (IS_ERR(dir))
                return;