if (readonly)
                set_bit(DASD_FLAG_DEVICE_RO, &device->flags);
 
+       if (dasd_eckd_is_ese(device))
+               dasd_set_feature(device->cdev, DASD_FEATURE_DISCARD, 1);
+
        dev_info(&device->cdev->dev, "New DASD %04X/%02X (CU %04X/%02X) "
                 "with %d cylinders, %d heads, %d sectors%s\n",
                 private->rdc_data.dev_type,
                return -EINVAL;
 }
 
+static struct dasd_ccw_req *
+dasd_eckd_build_cp_discard(struct dasd_device *device, struct dasd_block *block,
+                          struct request *req, sector_t first_trk,
+                          sector_t last_trk)
+{
+       return dasd_eckd_dso_ras(device, block, req, first_trk, last_trk, 1);
+}
+
 static struct dasd_ccw_req *dasd_eckd_build_cp_cmd_single(
                                               struct dasd_device *startdev,
                                               struct dasd_block *block,
        cmdwtd = private->features.feature[12] & 0x40;
        use_prefix = private->features.feature[8] & 0x01;
 
+       if (req_op(req) == REQ_OP_DISCARD)
+               return dasd_eckd_build_cp_discard(startdev, block, req,
+                                                 first_trk, last_trk);
+
        cqr = NULL;
        if (cdlspecial || dasd_page_cache) {
                /* do nothing, just fall through to the cmd mode single case */
                                                     struct dasd_block *block,
                                                     struct request *req)
 {
+       struct dasd_device *startdev = NULL;
        struct dasd_eckd_private *private;
-       struct dasd_device *startdev;
-       unsigned long flags;
        struct dasd_ccw_req *cqr;
+       unsigned long flags;
 
-       startdev = dasd_alias_get_start_dev(base);
+       /* Discard requests can only be processed on base devices */
+       if (req_op(req) != REQ_OP_DISCARD)
+               startdev = dasd_alias_get_start_dev(base);
        if (!startdev)
                startdev = base;
        private = startdev->private;
        unsigned int logical_block_size = block->bp_block;
        struct request_queue *q = block->request_queue;
        struct dasd_device *device = block->base;
+       struct dasd_eckd_private *private;
+       unsigned int max_discard_sectors;
+       unsigned int max_bytes;
+       unsigned int ext_bytes; /* Extent Size in Bytes */
+       int recs_per_trk;
+       int trks_per_cyl;
+       int ext_limit;
+       int ext_size; /* Extent Size in Cylinders */
        int max;
 
+       private = device->private;
+       trks_per_cyl = private->rdc_data.trk_per_cyl;
+       recs_per_trk = recs_per_track(&private->rdc_data, 0, logical_block_size);
+
        if (device->features & DASD_FEATURE_USERAW) {
                /*
                 * the max_blocks value for raw_track access is 256
        /* With page sized segments each segment can be translated into one idaw/tidaw */
        blk_queue_max_segment_size(q, PAGE_SIZE);
        blk_queue_segment_boundary(q, PAGE_SIZE - 1);
+
+       if (dasd_eckd_is_ese(device)) {
+               /*
+                * Depending on the extent size, up to UINT_MAX bytes can be
+                * accepted. However, neither DASD_ECKD_RAS_EXTS_MAX nor the
+                * device limits should be exceeded.
+                */
+               ext_size = dasd_eckd_ext_size(device);
+               ext_limit = min(private->real_cyl / ext_size, DASD_ECKD_RAS_EXTS_MAX);
+               ext_bytes = ext_size * trks_per_cyl * recs_per_trk *
+                       logical_block_size;
+               max_bytes = UINT_MAX - (UINT_MAX % ext_bytes);
+               if (max_bytes / ext_bytes > ext_limit)
+                       max_bytes = ext_bytes * ext_limit;
+
+               max_discard_sectors = max_bytes / 512;
+
+               blk_queue_max_discard_sectors(q, max_discard_sectors);
+               blk_queue_flag_set(QUEUE_FLAG_DISCARD, q);
+               q->limits.discard_granularity = ext_bytes;
+               q->limits.discard_alignment = ext_bytes;
+       }
 }
 
 static struct ccw_driver dasd_eckd_driver = {