From: plc@novell.com
Subject: add support for new operation type BLKIF_OP_PACKET
Patch-mainline: Never, SUSE-Xen specific
References: fate#300964

--- a/drivers/xen/blkback/blkback.c
+++ b/drivers/xen/blkback/blkback.c
@@ -207,10 +207,11 @@ static void fast_flush_area(pending_req_
 static void print_stats(blkif_t *blkif)
 {
 	printk(KERN_DEBUG "%s: oo %3d  |  rd %4d  |  wr %4d  |  br %4d"
-	       "  |  fl %4d  |  ds %4d\n",
+	       "  |  fl %4d  |  ds %4d  |  pk %4d\n",
 	       current->comm, blkif->st_oo_req,
 	       blkif->st_rd_req, blkif->st_wr_req,
-	       blkif->st_br_req, blkif->st_fl_req, blkif->st_ds_req);
+	       blkif->st_br_req, blkif->st_fl_req,
+	       blkif->st_ds_req, blkif->st_pk_req);
 	blkif->st_print = jiffies + msecs_to_jiffies(10 * 1000);
 	blkif->st_rd_req = 0;
 	blkif->st_wr_req = 0;
@@ -218,6 +219,7 @@ static void print_stats(blkif_t *blkif)
 	blkif->st_br_req = 0;
 	blkif->st_fl_req = 0;
 	blkif->st_ds_req = 0;
+	blkif->st_pk_req = 0;
 }
 
 int blkif_schedule(void *arg)
@@ -484,6 +486,13 @@ static int _do_block_io_op(blkif_t *blki
 			blk_rings->common.req_cons = rc;
 			dispatch_discard(blkif, (void *)&req);
 			break;
+		case BLKIF_OP_PACKET:
+			blk_rings->common.req_cons = rc;
+			blkif->st_pk_req++;
+			DPRINTK("error: block operation BLKIF_OP_PACKET not implemented\n");
+			make_response(blkif, req.id, req.operation,
+				      BLKIF_RSP_ERROR);
+			break;
 		default:
 			/* A good sign something is wrong: sleep for a while to
 			 * avoid excessive CPU consumption by a bad guest. */
--- a/drivers/xen/blkback/common.h
+++ b/drivers/xen/blkback/common.h
@@ -98,6 +98,7 @@ typedef struct blkif_st {
 	int                 st_br_req;
 	int                 st_fl_req;
 	int                 st_ds_req;
+	int                 st_pk_req;
 	int                 st_rd_sect;
 	int                 st_wr_sect;
 
--- a/drivers/xen/blkfront/blkfront.c
+++ b/drivers/xen/blkfront/blkfront.c
@@ -691,6 +691,7 @@ static const char *op_name(unsigned int 
 		[BLKIF_OP_WRITE] = "write",
 		[BLKIF_OP_WRITE_BARRIER] = "barrier",
 		[BLKIF_OP_FLUSH_DISKCACHE] = "flush",
+		[BLKIF_OP_PACKET] = "packet",
 		[BLKIF_OP_DISCARD] = "discard",
 	};
 
@@ -991,6 +992,8 @@ static int blkif_queue_request(struct re
 	if (req->cmd_flags & REQ_HARDBARRIER)
 #endif
 		ring_req->operation = info->flush_op;
+	if (req->cmd_type == REQ_TYPE_BLOCK_PC)
+		ring_req->operation = BLKIF_OP_PACKET;
 
 	if (unlikely(req->cmd_flags & (REQ_DISCARD | REQ_SECURE))) {
 		struct blkif_request_discard *discard = (void *)ring_req;
@@ -1059,7 +1062,8 @@ void do_blkif_request(struct request_que
 
 		blk_start_request(req);
 
-		if ((req->cmd_type != REQ_TYPE_FS) ||
+		if ((req->cmd_type != REQ_TYPE_FS &&
+		     (req->cmd_type != REQ_TYPE_BLOCK_PC || req->cmd_len)) ||
 		    ((req->cmd_flags & (REQ_FLUSH | REQ_FUA)) &&
 		     !info->flush_op)) {
 			req->errors = (DID_ERROR << 16) |
@@ -1170,6 +1174,7 @@ static irqreturn_t blkif_int(int irq, vo
 			/* fall through */
 		case BLKIF_OP_READ:
 		case BLKIF_OP_WRITE:
+		case BLKIF_OP_PACKET:
 			if (unlikely(bret->status != BLKIF_RSP_OKAY))
 				DPRINTK("Bad return from blkdev %s request: %d\n",
 					op_name(bret->operation),
--- a/drivers/xen/blktap/blktap.c
+++ b/drivers/xen/blktap/blktap.c
@@ -1147,13 +1147,14 @@ static void fast_flush_area(pending_req_
 
 static void print_stats(blkif_t *blkif)
 {
-	printk(KERN_DEBUG "%s: oo %3d  |  rd %4d  |  wr %4d\n",
+	printk(KERN_DEBUG "%s: oo %3d  |  rd %4d  |  wr %4d |  pk %4d\n",
 	       current->comm, blkif->st_oo_req,
-	       blkif->st_rd_req, blkif->st_wr_req);
+	       blkif->st_rd_req, blkif->st_wr_req, blkif->st_pk_req);
 	blkif->st_print = jiffies + msecs_to_jiffies(10 * 1000);
 	blkif->st_rd_req = 0;
 	blkif->st_wr_req = 0;
 	blkif->st_oo_req = 0;
+	blkif->st_pk_req = 0;
 }
 
 int tap_blkif_schedule(void *arg)
@@ -1408,6 +1409,11 @@ static int _do_block_io_op(blkif_t *blki
 			dispatch_rw_block_io(blkif, &req, pending_req);
 			break;
 
+		case BLKIF_OP_PACKET:
+			blkif->st_pk_req++;
+			dispatch_rw_block_io(blkif, &req, pending_req);
+			break;
+
 		default:
 			/* A good sign something is wrong: sleep for a while to
 			 * avoid excessive CPU consumption by a bad guest. */
--- a/drivers/xen/blktap/common.h
+++ b/drivers/xen/blktap/common.h
@@ -71,6 +71,7 @@ typedef struct blkif_st {
 	int                 st_rd_req;
 	int                 st_wr_req;
 	int                 st_oo_req;
+	int                 st_pk_req;
 	int                 st_rd_sect;
 	int                 st_wr_sect;
 
--- a/drivers/xen/blktap2/blktap.h
+++ b/drivers/xen/blktap2/blktap.h
@@ -141,6 +141,7 @@ struct blktap_statistics {
 	int                            st_rd_req;
 	int                            st_wr_req;
 	int                            st_oo_req;
+	int                            st_pk_req;
 	int                            st_rd_sect;
 	int                            st_wr_sect;
 	s64                            st_rd_cnt;
--- a/drivers/xen/blktap2/device.c
+++ b/drivers/xen/blktap2/device.c
@@ -344,7 +344,8 @@ blktap_device_fail_pending_requests(stru
 
 		BTERR("%u:%u: failing pending %s of %d pages\n",
 		      blktap_device_major, tap->minor,
-		      (request->operation == BLKIF_OP_READ ?
+		      (request->operation == BLKIF_OP_PACKET ?
+		       "packet" : request->operation == BLKIF_OP_READ ?
 		       "read" : "write"), request->nr_pages);
 
 		blktap_unmap(tap, request);
@@ -385,6 +386,7 @@ blktap_device_finish_request(struct blkt
 	switch (request->operation) {
 	case BLKIF_OP_READ:
 	case BLKIF_OP_WRITE:
+	case BLKIF_OP_PACKET:
 		if (unlikely(res->status != BLKIF_RSP_OKAY))
 			BTERR("Bad return from device data "
 				"request: %x\n", res->status);
@@ -622,6 +624,8 @@ blktap_device_process_request(struct blk
 	blkif_req.handle = 0;
 	blkif_req.operation = rq_data_dir(req) ?
 		BLKIF_OP_WRITE : BLKIF_OP_READ;
+	if (unlikely(req->cmd_type == REQ_TYPE_BLOCK_PC))
+		blkif_req.operation = BLKIF_OP_PACKET;
 
 	request->id        = (unsigned long)req;
 	request->operation = blkif_req.operation;
@@ -687,7 +691,9 @@ blktap_device_process_request(struct blk
 	wmb(); /* blktap_poll() reads req_prod_pvt asynchronously */
 	ring->ring.req_prod_pvt++;
 
-	if (rq_data_dir(req)) {
+	if (unlikely(req->cmd_type == REQ_TYPE_BLOCK_PC))
+		tap->stats.st_pk_req++;
+	else if (rq_data_dir(req)) {
 		tap->stats.st_wr_sect += nr_sects;
 		tap->stats.st_wr_req++;
 	} else {
--- a/drivers/xen/blktap2-new/blktap.h
+++ b/drivers/xen/blktap2-new/blktap.h
@@ -114,6 +114,7 @@ struct blktap_statistics {
 	int                            st_rd_req;
 	int                            st_wr_req;
 	int                            st_oo_req;
+	int                            st_pk_req;
 	int                            st_rd_sect;
 	int                            st_wr_sect;
 	s64                            st_rd_cnt;
--- a/drivers/xen/blktap2-new/device.c
+++ b/drivers/xen/blktap2-new/device.c
@@ -189,6 +189,8 @@ blktap_device_make_request(struct blktap
 
 	request->rq = rq;
 	request->operation = write ? BLKIF_OP_WRITE : BLKIF_OP_READ;
+	if (unlikely(rq->cmd_type == REQ_TYPE_BLOCK_PC))
+		request->operation = BLKIF_OP_PACKET;
 
 	err = blktap_request_get_pages(tap, request, nsegs);
 	if (err)
--- a/drivers/xen/blktap2-new/ring.c
+++ b/drivers/xen/blktap2-new/ring.c
@@ -153,11 +153,11 @@ blktap_ring_map_request(struct blktap *t
 	int seg, err = 0;
 	int write;
 
-	write = request->operation == BLKIF_OP_WRITE;
+	write = request->operation != BLKIF_OP_READ;
 
 	for (seg = 0; seg < request->nr_pages; seg++) {
 		if (write)
-			blktap_request_bounce(tap, request, seg, write);
+			blktap_request_bounce(tap, request, seg, 1);
 
 		err = blktap_ring_map_segment(tap, request, seg);
 		if (err)
@@ -181,11 +181,11 @@ blktap_ring_unmap_request(struct blktap 
 
 	uaddr = MMAP_VADDR(ring->user_vstart, request->usr_idx, 0);
 	size  = request->nr_pages << PAGE_SHIFT;
-	read  = request->operation == BLKIF_OP_READ;
+	read  = request->operation != BLKIF_OP_WRITE;
 
 	if (read)
 		for (seg = 0; seg < request->nr_pages; seg++)
-			blktap_request_bounce(tap, request, seg, !read);
+			blktap_request_bounce(tap, request, seg, 0);
 
 	zap_page_range(ring->vma, uaddr, size, NULL);
 }
@@ -269,14 +269,20 @@ blktap_ring_submit_request(struct blktap
 	do_gettimeofday(&request->time);
 
 
-	if (request->operation == BLKIF_OP_WRITE) {
+	switch (request->operation) {
+	case BLKIF_OP_WRITE:
 		tap->stats.st_wr_sect += nsecs;
 		tap->stats.st_wr_req++;
-	}
+		break;
 
-	if (request->operation == BLKIF_OP_READ) {
+	case BLKIF_OP_READ:
 		tap->stats.st_rd_sect += nsecs;
 		tap->stats.st_rd_req++;
+		break;
+
+	case BLKIF_OP_PACKET:
+		tap->stats.st_pk_req++;
+		break;
 	}
 }
 
@@ -483,20 +489,24 @@ blktap_ring_debug(struct blktap *tap, ch
 	for (usr_idx = 0; usr_idx < MAX_PENDING_REQS; usr_idx++) {
 		struct blktap_request *request;
 		struct timeval *time;
-		int write;
+		char op = '?';
 
 		request = ring->pending[usr_idx];
 		if (!request)
 			continue;
 
-		write = request->operation == BLKIF_OP_WRITE;
+		switch (request->operation) {
+		case BLKIF_OP_WRITE:  op = 'W'; break;
+		case BLKIF_OP_READ:   op = 'R'; break;
+		case BLKIF_OP_PACKET: op = 'P'; break;
+		}
 		time  = &request->time;
 
 		s += snprintf(s, end - s,
 			      "%02d: usr_idx:%02d "
 			      "op:%c nr_pages:%02d time:%lu.%09lu\n",
 			      usr_idx, request->usr_idx,
-			      write ? 'W' : 'R', request->nr_pages,
+			      op, request->nr_pages,
 			      time->tv_sec, time->tv_usec);
 	}
 
--- a/include/xen/interface/io/blkif.h
+++ b/include/xen/interface/io/blkif.h
@@ -436,10 +436,9 @@
  */
 #define BLKIF_OP_FLUSH_DISKCACHE   3
 /*
- * Used in SLES sources for device specific command packet
- * contained within the request. Reserved for that purpose.
+ * Device specific command packet contained within the request
  */
-#define BLKIF_OP_RESERVED_1        4
+#define BLKIF_OP_PACKET            4
 /*
  * Indicate to the backend device that a region of storage is no longer in
  * use, and may be discarded at any time without impact to the client.  If
