return 0;
 }
 
+static struct dasd_device
+*copy_relation_find_device(struct dasd_copy_relation *copy,
+                          char *busid)
+{
+       int i;
+
+       for (i = 0; i < DASD_CP_ENTRIES; i++) {
+               if (copy->entry[i].configured &&
+                   strncmp(copy->entry[i].busid, busid, DASD_BUS_ID_SIZE) == 0)
+                       return copy->entry[i].device;
+       }
+       return NULL;
+}
+
+/*
+ * set the new active/primary device
+ */
+static void copy_pair_set_active(struct dasd_copy_relation *copy, char *new_busid,
+                                char *old_busid)
+{
+       int i;
+
+       for (i = 0; i < DASD_CP_ENTRIES; i++) {
+               if (copy->entry[i].configured &&
+                   strncmp(copy->entry[i].busid, new_busid,
+                           DASD_BUS_ID_SIZE) == 0) {
+                       copy->active = ©->entry[i];
+                       copy->entry[i].primary = true;
+               } else if (copy->entry[i].configured &&
+                          strncmp(copy->entry[i].busid, old_busid,
+                                  DASD_BUS_ID_SIZE) == 0) {
+                       copy->entry[i].primary = false;
+               }
+       }
+}
+
+/*
+ * The function will swap the role of a given copy pair.
+ * During the swap operation the relation of the blockdevice is disconnected
+ * from the old primary and connected to the new.
+ *
+ * IO is paused on the block queue before swap and may be resumed afterwards.
+ */
+static int dasd_eckd_copy_pair_swap(struct dasd_device *device, char *prim_busid,
+                                   char *sec_busid)
+{
+       struct dasd_device *primary, *secondary;
+       struct dasd_copy_relation *copy;
+       struct dasd_block *block;
+       struct gendisk *gdp;
+
+       copy = device->copy;
+       if (!copy)
+               return DASD_COPYPAIRSWAP_INVALID;
+       primary = copy->active->device;
+       if (!primary)
+               return DASD_COPYPAIRSWAP_INVALID;
+       /* double check if swap has correct primary */
+       if (strncmp(dev_name(&primary->cdev->dev), prim_busid, DASD_BUS_ID_SIZE) != 0)
+               return DASD_COPYPAIRSWAP_PRIMARY;
+
+       secondary = copy_relation_find_device(copy, sec_busid);
+       if (!secondary)
+               return DASD_COPYPAIRSWAP_SECONDARY;
+
+       /*
+        * usually the device should be quiesced for swap
+        * for paranoia stop device and requeue requests again
+        */
+       dasd_device_set_stop_bits(primary, DASD_STOPPED_PPRC);
+       dasd_device_set_stop_bits(secondary, DASD_STOPPED_PPRC);
+       dasd_generic_requeue_all_requests(primary);
+
+       /* swap DASD internal device <> block assignment */
+       block = primary->block;
+       primary->block = NULL;
+       secondary->block = block;
+       block->base = secondary;
+       /* set new primary device in COPY relation */
+       copy_pair_set_active(copy, sec_busid, prim_busid);
+
+       /* swap blocklayer device link */
+       gdp = block->gdp;
+       dasd_add_link_to_gendisk(gdp, secondary);
+
+       /* re-enable device */
+       dasd_device_remove_stop_bits(primary, DASD_STOPPED_PPRC);
+       dasd_device_remove_stop_bits(secondary, DASD_STOPPED_PPRC);
+       dasd_schedule_device_bh(secondary);
+
+       return DASD_COPYPAIRSWAP_SUCCESS;
+}
+
 /*
  * Perform Subsystem Function - Peer-to-Peer Remote Copy Extended Query
  */
        .ese_read = dasd_eckd_ese_read,
        .pprc_status = dasd_eckd_query_pprc_status,
        .pprc_enabled = dasd_eckd_pprc_enabled,
+       .copy_pair_swap = dasd_eckd_copy_pair_swap,
 };
 
 static int __init
 
        int (*ese_read)(struct dasd_ccw_req *, struct irb *);
        int (*pprc_status)(struct dasd_device *, struct dasd_pprc_data_sc4 *);
        bool (*pprc_enabled)(struct dasd_device *);
+       int (*copy_pair_swap)(struct dasd_device *, char *, char *);
 };
 
 extern struct dasd_discipline *dasd_diag_discipline_pointer;
 #define DASD_STOPPED_PENDING 4         /* long busy */
 #define DASD_STOPPED_DC_WAIT 8         /* disconnected, wait */
 #define DASD_STOPPED_SU      16        /* summary unit check handling */
+#define DASD_STOPPED_PPRC    32        /* PPRC swap */
 #define DASD_STOPPED_NOSPC   128       /* no space left */
 
 /* per device flags */
 
 void dasd_put_device_wake(struct dasd_device *);
 
+/*
+ * return values to be returned from the copy pair swap function
+ * 0x00: swap successful
+ * 0x01: swap data invalid
+ * 0x02: no active device found
+ * 0x03: wrong primary specified
+ * 0x04: secondary device not found
+ * 0x05: swap already running
+ */
+#define DASD_COPYPAIRSWAP_SUCCESS      0
+#define DASD_COPYPAIRSWAP_INVALID      1
+#define DASD_COPYPAIRSWAP_NOACTIVE     2
+#define DASD_COPYPAIRSWAP_PRIMARY      3
+#define DASD_COPYPAIRSWAP_SECONDARY    4
+#define DASD_COPYPAIRSWAP_MULTIPLE     5
+
 /*
  * Reference count inliners
  */
 void dasd_generic_space_exhaust(struct dasd_device *, struct dasd_ccw_req *);
 void dasd_generic_space_avail(struct dasd_device *);
 
+int dasd_generic_requeue_all_requests(struct dasd_device *);
+
 int dasd_generic_read_dev_chars(struct dasd_device *, int, void *, int);
 char *dasd_get_sense(struct irb *);