[PATCH 10/19] s390/dasd: Extend prepare_itcw() to support WRITE_FULL_TRACK
Stefan Haberland <[email protected]> Wed, 5 Aug 2026 13:16:03 +0200
| Newsgroups | org.kernel.vger.linux-block,org.kernel.vger.linux-s390 |
|---|---|
| Message-ID | <[email protected]> |
prepare_itcw() builds the FCX prefix block (PFX + LRE) for track-mode I/O. Extend it to handle DASD_ECKD_CCW_WRITE_FULL_TRACK. WRITE_FULL_TRACK needs two extra bytes appended to the LRE for that bitmask. The prefix block is a scratch buffer copied into the TCCB by itcw_add_dcw(), so keep it on the stack (sized for the two extra bytes) rather than allocating it: this runs in the writeback path and must not depend on an allocation that can fail under memory pressure. Reviewed-by: Jan Höppner <[email protected]> Signed-off-by: Stefan Haberland <[email protected]> --- drivers/s390/block/dasd_eckd.c | 64 +++++++++++++++++++++++++++------- 1 file changed, 51 insertions(+), 13 deletions(-) diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index be54c356dc24..ae122fbdca3e 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c @@ -4388,11 +4388,13 @@ static int prepare_itcw(struct itcw *itcw, unsigned int tlf, unsigned int blk_per_trk) { - struct PFX_eckd_data pfxdata; + u8 pfxbuf[sizeof(struct PFX_eckd_data) + 2] __aligned(8); + struct PFX_eckd_data *pfxdata = (struct PFX_eckd_data *)pfxbuf; struct dasd_eckd_private *basepriv, *startpriv; struct DE_eckd_data *dedata; struct LRE_eckd_data *lredata; struct dcw *dcw; + int pfxsize; u32 begcyl, endcyl; u16 heads, beghead, endhead; @@ -4402,26 +4404,31 @@ static int prepare_itcw(struct itcw *itcw, int sector = 0; int dn, d; + pfxsize = sizeof(struct PFX_eckd_data); + /* prefix + LRE extended data */ + if (cmd == DASD_ECKD_CCW_WRITE_FULL_TRACK) + pfxsize += 2; + + memset(pfxbuf, 0, pfxsize); /* setup prefix data */ basepriv = basedev->private; startpriv = startdev->private; - dedata = &pfxdata.define_extent; - lredata = &pfxdata.locate_record; + dedata = &pfxdata->define_extent; + lredata = &pfxdata->locate_record; - memset(&pfxdata, 0, sizeof(pfxdata)); - pfxdata.format = 1; /* PFX with LRE */ - pfxdata.base_address = basepriv->conf.ned->unit_addr; - pfxdata.base_lss = basepriv->conf.ned->ID; - pfxdata.validity.define_extent = 1; + pfxdata->format = 1; /* PFX with LRE */ + pfxdata->base_address = basepriv->conf.ned->unit_addr; + pfxdata->base_lss = basepriv->conf.ned->ID; + pfxdata->validity.define_extent = 1; /* private uid is kept up to date, conf_data may be outdated */ if (startpriv->uid.type == UA_BASE_PAV_ALIAS) - pfxdata.validity.verify_base = 1; + pfxdata->validity.verify_base = 1; if (startpriv->uid.type == UA_HYPER_PAV_ALIAS) { - pfxdata.validity.verify_base = 1; - pfxdata.validity.hyper_pav = 1; + pfxdata->validity.verify_base = 1; + pfxdata->validity.hyper_pav = 1; } switch (cmd) { @@ -4451,7 +4458,38 @@ static int prepare_itcw(struct itcw *itcw, * data as well. */ if (dedata->ga_extended & 0x08 && dedata->ga_extended & 0x02) - pfxdata.validity.time_stamp = 1; /* 'Time Stamp Valid' */ + pfxdata->validity.time_stamp = 1; /* 'Time Stamp Valid' */ + pfx_cmd = DASD_ECKD_CCW_PFX; + break; + case DASD_ECKD_CCW_WRITE_FULL_TRACK: + dedata->mask.perm = 0x3; + dedata->mask.auth = 0x00; + dedata->attributes.operation = basepriv->attrib.operation; + dedata->blk_size = blksize; + dedata->ga_extended |= 0x42; + rc = set_timestamp(NULL, dedata, basedev); + lredata->operation.orientation = 0x0; + lredata->operation.operation = 0x3F; + lredata->extended_operation = 0x11; + lredata->auxiliary.check_bytes = 0x2; + lredata->extended_parameter_length = 0x02; + if (count > 8) { + lredata->extended_parameter[0] = 0xFF; + lredata->extended_parameter[1] = 0xFF; + lredata->extended_parameter[1] <<= (16 - count); + } else { + lredata->extended_parameter[0] = 0xFF; + lredata->extended_parameter[0] <<= (8 - count); + lredata->extended_parameter[1] = 0x00; + } + sector = 0xFF; + /* + * If XRC is supported the System Time Stamp is set. The + * validity of the time stamp must be reflected in the prefix + * data as well. + */ + if (dedata->ga_extended & 0x08 && dedata->ga_extended & 0x02) + pfxdata->validity.time_stamp = 1; /* 'Time Stamp Valid' */ pfx_cmd = DASD_ECKD_CCW_PFX; break; case DASD_ECKD_CCW_READ_COUNT_MT: @@ -4530,7 +4568,7 @@ static int prepare_itcw(struct itcw *itcw, lredata->search_arg.record = rec_on_trk; dcw = itcw_add_dcw(itcw, pfx_cmd, 0, - &pfxdata, sizeof(pfxdata), total_data_size); + pfxdata, pfxsize, total_data_size); return PTR_ERR_OR_ZERO(dcw); } -- 2.53.0