diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c
index e03304fe25bb5785f71cf873fc4cb734052d9d0f..1c7da4342461f717b96c1604a97c491f2c231847 100644
--- a/drivers/s390/block/dasd.c
+++ b/drivers/s390/block/dasd.c
@@ -120,9 +120,18 @@ struct dasd_device *dasd_alloc_device(void)
 		kfree(device);
 		return ERR_PTR(-ENOMEM);
 	}
+	/* Get two pages for ese format. */
+	device->ese_mem = (void *)__get_free_pages(GFP_ATOMIC | GFP_DMA, 1);
+	if (!device->ese_mem) {
+		free_page((unsigned long) device->erp_mem);
+		free_pages((unsigned long) device->ccw_mem, 1);
+		kfree(device);
+		return ERR_PTR(-ENOMEM);
+	}
 
 	dasd_init_chunklist(&device->ccw_chunks, device->ccw_mem, PAGE_SIZE*2);
 	dasd_init_chunklist(&device->erp_chunks, device->erp_mem, PAGE_SIZE);
+	dasd_init_chunklist(&device->ese_chunks, device->ese_mem, PAGE_SIZE * 2);
 	spin_lock_init(&device->mem_lock);
 	atomic_set(&device->tasklet_scheduled, 0);
 	tasklet_init(&device->tasklet, dasd_device_tasklet,
@@ -146,6 +155,7 @@ struct dasd_device *dasd_alloc_device(void)
 void dasd_free_device(struct dasd_device *device)
 {
 	kfree(device->private);
+	free_pages((unsigned long) device->ese_mem, 1);
 	free_page((unsigned long) device->erp_mem);
 	free_pages((unsigned long) device->ccw_mem, 1);
 	kfree(device);
@@ -1258,6 +1268,49 @@ struct dasd_ccw_req *dasd_smalloc_request(int magic, int cplength, int datasize,
 }
 EXPORT_SYMBOL(dasd_smalloc_request);
 
+struct dasd_ccw_req *dasd_fmalloc_request(int magic, int cplength,
+					  int datasize,
+					  struct dasd_device *device)
+{
+	struct dasd_ccw_req *cqr;
+	unsigned long flags;
+	int size, cqr_size;
+	char *data;
+
+	cqr_size = (sizeof(*cqr) + 7L) & -8L;
+	size = cqr_size;
+	if (cplength > 0)
+		size += cplength * sizeof(struct ccw1);
+	if (datasize > 0)
+		size += datasize;
+
+	spin_lock_irqsave(&device->mem_lock, flags);
+	cqr = dasd_alloc_chunk(&device->ese_chunks, size);
+	spin_unlock_irqrestore(&device->mem_lock, flags);
+	if (!cqr)
+		return ERR_PTR(-ENOMEM);
+	memset(cqr, 0, sizeof(*cqr));
+	data = (char *)cqr + cqr_size;
+	cqr->cpaddr = NULL;
+	if (cplength > 0) {
+		cqr->cpaddr = data;
+		data += cplength * sizeof(struct ccw1);
+		memset(cqr->cpaddr, 0, cplength * sizeof(struct ccw1));
+	}
+	cqr->data = NULL;
+	if (datasize > 0) {
+		cqr->data = data;
+		memset(cqr->data, 0, datasize);
+	}
+
+	cqr->magic = magic;
+	set_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
+	dasd_get_device(device);
+
+	return cqr;
+}
+EXPORT_SYMBOL(dasd_fmalloc_request);
+
 void dasd_sfree_request(struct dasd_ccw_req *cqr, struct dasd_device *device)
 {
 	unsigned long flags;
@@ -1269,6 +1322,17 @@ void dasd_sfree_request(struct dasd_ccw_req *cqr, struct dasd_device *device)
 }
 EXPORT_SYMBOL(dasd_sfree_request);
 
+void dasd_ffree_request(struct dasd_ccw_req *cqr, struct dasd_device *device)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&device->mem_lock, flags);
+	dasd_free_chunk(&device->ese_chunks, cqr);
+	spin_unlock_irqrestore(&device->mem_lock, flags);
+	dasd_put_device(device);
+}
+EXPORT_SYMBOL(dasd_ffree_request);
+
 /*
  * Check discipline magic in cqr.
  */
@@ -1573,13 +1637,35 @@ static int dasd_check_hpf_error(struct irb *irb)
 	     irb->scsw.tm.sesq == SCSW_SESQ_PATH_NOFCX));
 }
 
+static int dasd_ese_needs_format(struct dasd_block *block, struct irb *irb)
+{
+	struct dasd_device *device = NULL;
+	u8 *sense = NULL;
+
+	if (!block)
+		return 0;
+	device = block->base;
+	if (!device || !device->discipline->is_ese)
+		return 0;
+	if (!device->discipline->is_ese(device))
+		return 0;
+
+	sense = dasd_get_sense(irb);
+	if (!sense)
+		return 0;
+
+	return !!(sense[1] & SNS1_NO_REC_FOUND) ||
+		!!(sense[1] & SNS1_FILE_PROTECTED) ||
+		scsw_cstat(&irb->scsw) == SCHN_STAT_INCORR_LEN;
+}
+
 /*
  * Interrupt handler for "normal" ssch-io based dasd devices.
  */
 void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
 		      struct irb *irb)
 {
-	struct dasd_ccw_req *cqr, *next;
+	struct dasd_ccw_req *cqr, *next, *fcqr;
 	struct dasd_device *device;
 	unsigned long now;
 	int nrf_suppressed = 0;
@@ -1672,6 +1758,31 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
 		return;
 	}
 
+	if (dasd_ese_needs_format(cqr->block, irb)) {
+		if (rq_data_dir((struct request *)cqr->callback_data) == READ) {
+			device->discipline->ese_read(cqr);
+			cqr->status = DASD_CQR_SUCCESS;
+			cqr->stopclk = now;
+			dasd_device_clear_timer(device);
+			dasd_schedule_device_bh(device);
+			return;
+		}
+		fcqr = device->discipline->ese_format(device, cqr);
+		if (IS_ERR(fcqr)) {
+			/*
+			 * If we can't format now, let the request go
+			 * one extra round. Maybe we can format later.
+			 */
+			cqr->status = DASD_CQR_QUEUED;
+		} else {
+			fcqr->status = DASD_CQR_QUEUED;
+			cqr->status = DASD_CQR_QUEUED;
+			list_add(&fcqr->devlist, &device->ccw_queue);
+			dasd_schedule_device_bh(device);
+			return;
+		}
+	}
+
 	/* Check for clear pending */
 	if (cqr->status == DASD_CQR_CLEAR_PENDING &&
 	    scsw_fctl(&irb->scsw) & SCSW_FCTL_CLEAR_FUNC) {
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c
index 67156d46c236fbdb7fd89a80321b183d2ccc913d..6109a0e68911af21fef3ef7b2025cd61a27201a8 100644
--- a/drivers/s390/block/dasd_eckd.c
+++ b/drivers/s390/block/dasd_eckd.c
@@ -2335,8 +2335,7 @@ dasd_eckd_build_check_tcw(struct dasd_device *base, struct format_data_t *fdata,
 	 */
 	itcw_size = itcw_calc_size(0, count, 0);
 
-	cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 0, itcw_size, startdev,
-				   NULL);
+	cqr = dasd_fmalloc_request(DASD_ECKD_MAGIC, 0, itcw_size, startdev);
 	if (IS_ERR(cqr))
 		return cqr;
 
@@ -2429,8 +2428,7 @@ dasd_eckd_build_check(struct dasd_device *base, struct format_data_t *fdata,
 	}
 	cplength += count;
 
-	cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, cplength, datasize,
-				   startdev, NULL);
+	cqr = dasd_fmalloc_request(DASD_ECKD_MAGIC, cplength, datasize, startdev);
 	if (IS_ERR(cqr))
 		return cqr;
 
@@ -2477,13 +2475,11 @@ dasd_eckd_build_check(struct dasd_device *base, struct format_data_t *fdata,
 }
 
 static struct dasd_ccw_req *
-dasd_eckd_build_format(struct dasd_device *base,
-		       struct format_data_t *fdata,
-		       int enable_pav)
+dasd_eckd_build_format(struct dasd_device *base, struct dasd_device *startdev,
+		       struct format_data_t *fdata, int enable_pav)
 {
 	struct dasd_eckd_private *base_priv;
 	struct dasd_eckd_private *start_priv;
-	struct dasd_device *startdev = NULL;
 	struct dasd_ccw_req *fcp;
 	struct eckd_count *ect;
 	struct ch_t address;
@@ -2574,9 +2570,8 @@ dasd_eckd_build_format(struct dasd_device *base,
 			 fdata->intensity);
 		return ERR_PTR(-EINVAL);
 	}
-	/* Allocate the format ccw request. */
-	fcp = dasd_smalloc_request(DASD_ECKD_MAGIC, cplength,
-				   datasize, startdev, NULL);
+
+	fcp = dasd_fmalloc_request(DASD_ECKD_MAGIC, cplength, datasize, startdev);
 	if (IS_ERR(fcp))
 		return fcp;
 
@@ -2749,7 +2744,7 @@ dasd_eckd_format_build_ccw_req(struct dasd_device *base,
 	struct dasd_ccw_req *ccw_req;
 
 	if (!fmt_buffer) {
-		ccw_req = dasd_eckd_build_format(base, fdata, enable_pav);
+		ccw_req = dasd_eckd_build_format(base, NULL, fdata, enable_pav);
 	} else {
 		if (tpm)
 			ccw_req = dasd_eckd_build_check_tcw(base, fdata,
@@ -2895,7 +2890,7 @@ static int dasd_eckd_format_process_data(struct dasd_device *base,
 				rc = -EIO;
 			}
 			list_del_init(&cqr->blocklist);
-			dasd_sfree_request(cqr, device);
+			dasd_ffree_request(cqr, device);
 			private->count--;
 		}
 
@@ -2934,6 +2929,96 @@ static int dasd_eckd_format_device(struct dasd_device *base,
 					     0, NULL);
 }
 
+/*
+ * Callback function to free ESE format requests.
+ */
+static void dasd_eckd_ese_format_cb(struct dasd_ccw_req *cqr, void *data)
+{
+	struct dasd_device *device = cqr->startdev;
+	struct dasd_eckd_private *private = device->private;
+
+	private->count--;
+	dasd_ffree_request(cqr, device);
+}
+
+static struct dasd_ccw_req *
+dasd_eckd_ese_format(struct dasd_device *startdev, struct dasd_ccw_req *cqr)
+{
+	struct dasd_eckd_private *private;
+	struct format_data_t fdata;
+	unsigned int recs_per_trk;
+	struct dasd_ccw_req *fcqr;
+	struct dasd_device *base;
+	struct dasd_block *block;
+	unsigned int blksize;
+	struct request *req;
+	sector_t first_trk;
+	sector_t last_trk;
+	int rc;
+
+	req = cqr->callback_data;
+	base = cqr->block->base;
+	private = base->private;
+	block = base->block;
+	blksize = block->bp_block;
+	recs_per_trk = recs_per_track(&private->rdc_data, 0, blksize);
+
+	first_trk = blk_rq_pos(req) >> block->s2b_shift;
+	sector_div(first_trk, recs_per_trk);
+	last_trk =
+		(blk_rq_pos(req) + blk_rq_sectors(req) - 1) >> block->s2b_shift;
+	sector_div(last_trk, recs_per_trk);
+
+	fdata.start_unit = first_trk;
+	fdata.stop_unit = last_trk;
+	fdata.blksize = blksize;
+	fdata.intensity = private->uses_cdl ? DASD_FMT_INT_COMPAT : 0;
+
+	rc = dasd_eckd_format_sanity_checks(base, &fdata);
+	if (rc)
+		return ERR_PTR(-EINVAL);
+
+	/*
+	 * We're building the request with PAV disabled as we're reusing
+	 * the former startdev.
+	 */
+	fcqr = dasd_eckd_build_format(base, startdev, &fdata, 0);
+	if (IS_ERR(fcqr))
+		return fcqr;
+
+	fcqr->callback = dasd_eckd_ese_format_cb;
+
+	return fcqr;
+}
+
+/*
+ * When data is read from an unformatted area of an ESE volume, this function
+ * returns zeroed data and thereby mimics a read of zero data.
+ */
+static void dasd_eckd_ese_read(struct dasd_ccw_req *cqr)
+{
+	unsigned int blksize, off;
+	struct dasd_device *base;
+	struct req_iterator iter;
+	struct request *req;
+	struct bio_vec bv;
+	char *dst;
+
+	req = (struct request *) cqr->callback_data;
+	base = cqr->block->base;
+	blksize = base->block->bp_block;
+
+	rq_for_each_segment(bv, req, iter) {
+		dst = page_address(bv.bv_page) + bv.bv_offset;
+		for (off = 0; off < bv.bv_len; off += blksize) {
+			if (dst && rq_data_dir(req) == READ) {
+				dst += off;
+				memset(dst, 0, blksize);
+			}
+		}
+	}
+}
+
 /*
  * Helper function to count consecutive records of a single track.
  */
@@ -3450,6 +3535,14 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_cmd_single(
 	cqr->retries = startdev->default_retries;
 	cqr->buildclk = get_tod_clock();
 	cqr->status = DASD_CQR_FILLED;
+
+	/* Set flags to suppress output for expected errors */
+	if (dasd_eckd_is_ese(basedev)) {
+		set_bit(DASD_CQR_SUPPRESS_FP, &cqr->flags);
+		set_bit(DASD_CQR_SUPPRESS_IL, &cqr->flags);
+		set_bit(DASD_CQR_SUPPRESS_NRF, &cqr->flags);
+	}
+
 	return cqr;
 }
 
@@ -3621,6 +3714,11 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_cmd_track(
 	cqr->retries = startdev->default_retries;
 	cqr->buildclk = get_tod_clock();
 	cqr->status = DASD_CQR_FILLED;
+
+	/* Set flags to suppress output for expected errors */
+	if (dasd_eckd_is_ese(basedev))
+		set_bit(DASD_CQR_SUPPRESS_NRF, &cqr->flags);
+
 	return cqr;
 }
 
@@ -3940,6 +4038,14 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_tpm_track(
 	cqr->retries = startdev->default_retries;
 	cqr->buildclk = get_tod_clock();
 	cqr->status = DASD_CQR_FILLED;
+
+	/* Set flags to suppress output for expected errors */
+	if (dasd_eckd_is_ese(basedev)) {
+		set_bit(DASD_CQR_SUPPRESS_FP, &cqr->flags);
+		set_bit(DASD_CQR_SUPPRESS_IL, &cqr->flags);
+		set_bit(DASD_CQR_SUPPRESS_NRF, &cqr->flags);
+	}
+
 	return cqr;
 out_error:
 	dasd_sfree_request(cqr, startdev);
@@ -6061,6 +6167,8 @@ static struct dasd_discipline dasd_eckd_discipline = {
 	.ext_pool_cap_at_warnlevel = dasd_eckd_ext_pool_cap_at_warnlevel,
 	.ext_pool_warn_thrshld = dasd_eckd_ext_pool_warn_thrshld,
 	.ext_pool_oos = dasd_eckd_ext_pool_oos,
+	.ese_format = dasd_eckd_ese_format,
+	.ese_read = dasd_eckd_ese_read,
 };
 
 static int __init
diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h
index 2f7e79d084ca165f86651a09b9ec63ee345549fb..3f7c3b9dcae69fbf6eb3e481b9315500dcfb29a3 100644
--- a/drivers/s390/block/dasd_int.h
+++ b/drivers/s390/block/dasd_int.h
@@ -382,6 +382,8 @@ struct dasd_discipline {
 	int (*ext_pool_cap_at_warnlevel)(struct dasd_device *);
 	int (*ext_pool_warn_thrshld)(struct dasd_device *);
 	int (*ext_pool_oos)(struct dasd_device *);
+	struct dasd_ccw_req *(*ese_format)(struct dasd_device *, struct dasd_ccw_req *);
+	void (*ese_read)(struct dasd_ccw_req *);
 };
 
 extern struct dasd_discipline *dasd_diag_discipline_pointer;
@@ -497,8 +499,10 @@ struct dasd_device {
 	spinlock_t mem_lock;
 	void *ccw_mem;
 	void *erp_mem;
+	void *ese_mem;
 	struct list_head ccw_chunks;
 	struct list_head erp_chunks;
+	struct list_head ese_chunks;
 
 	atomic_t tasklet_scheduled;
         struct tasklet_struct tasklet;
@@ -715,7 +719,9 @@ extern struct kmem_cache *dasd_page_cache;
 
 struct dasd_ccw_req *
 dasd_smalloc_request(int, int, int, struct dasd_device *, struct dasd_ccw_req *);
+struct dasd_ccw_req *dasd_fmalloc_request(int, int, int, struct dasd_device *);
 void dasd_sfree_request(struct dasd_ccw_req *, struct dasd_device *);
+void dasd_ffree_request(struct dasd_ccw_req *, struct dasd_device *);
 void dasd_wakeup_cb(struct dasd_ccw_req *, void *);
 
 struct dasd_device *dasd_alloc_device(void);