in xen-scsiback.c [683:762]
static int scsiback_do_cmd_fn(struct vscsibk_info *info,
unsigned int *eoi_flags)
{
struct vscsiif_back_ring *ring = &info->ring;
struct vscsiif_request ring_req;
struct vscsibk_pend *pending_req;
RING_IDX rc, rp;
int more_to_do;
uint32_t result;
rc = ring->req_cons;
rp = ring->sring->req_prod;
rmb(); /* guest system is accessing ring, too */
if (RING_REQUEST_PROD_OVERFLOW(ring, rp)) {
rc = ring->rsp_prod_pvt;
pr_warn("Dom%d provided bogus ring requests (%#x - %#x = %u). Halting ring processing\n",
info->domid, rp, rc, rp - rc);
return -EINVAL;
}
while ((rc != rp)) {
*eoi_flags &= ~XEN_EOI_FLAG_SPURIOUS;
if (RING_REQUEST_CONS_OVERFLOW(ring, rc))
break;
RING_COPY_REQUEST(ring, rc, &ring_req);
ring->req_cons = ++rc;
pending_req = prepare_pending_reqs(info, ring, &ring_req);
if (IS_ERR(pending_req)) {
switch (PTR_ERR(pending_req)) {
case -ENODEV:
result = DID_NO_CONNECT;
break;
default:
result = DID_ERROR;
break;
}
scsiback_send_response(info, NULL, result << 16, 0,
ring_req.rqid);
return 1;
}
switch (ring_req.act) {
case VSCSIIF_ACT_SCSI_CDB:
if (scsiback_gnttab_data_map(&ring_req, pending_req)) {
scsiback_fast_flush_area(pending_req);
scsiback_do_resp_with_sense(NULL,
DID_ERROR << 16, 0, pending_req);
transport_generic_free_cmd(&pending_req->se_cmd, 0);
} else {
scsiback_cmd_exec(pending_req);
}
break;
case VSCSIIF_ACT_SCSI_ABORT:
scsiback_device_action(pending_req, TMR_ABORT_TASK,
ring_req.ref_rqid);
break;
case VSCSIIF_ACT_SCSI_RESET:
scsiback_device_action(pending_req, TMR_LUN_RESET, 0);
break;
default:
pr_err_ratelimited("invalid request\n");
scsiback_do_resp_with_sense(NULL, DID_ERROR << 16, 0,
pending_req);
transport_generic_free_cmd(&pending_req->se_cmd, 0);
break;
}
/* Yield point for this unbounded loop. */
cond_resched();
}
gnttab_page_cache_shrink(&info->free_pages, scsiback_max_buffer_pages);
RING_FINAL_CHECK_FOR_REQUESTS(&info->ring, more_to_do);
return more_to_do;
}