diff options
Diffstat (limited to 'drivers/s390/block/dasd_eckd.c')
-rw-r--r-- | drivers/s390/block/dasd_eckd.c | 134 |
1 files changed, 121 insertions, 13 deletions
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index 67156d46c236..6109a0e68911 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 @@ out_err: rc = -EIO; } list_del_init(&cqr->blocklist); - dasd_sfree_request(cqr, device); + dasd_ffree_request(cqr, device); private->count--; } @@ -2935,6 +2930,96 @@ static int dasd_eckd_format_device(struct dasd_device *base, } /* + * 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. */ static int dasd_eckd_count_records(struct eckd_count *fmt_buffer, int start, @@ -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 |