static int scsiback_do_cmd_fn()

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;
}