mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-08-30 10:00:03 -04:00
s390/dasd: Extend prepare_itcw() to support WRITE_FULL_TRACK
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 <hoeppner@linux.ibm.com> Signed-off-by: Stefan Haberland <sth@linux.ibm.com> Link: https://patch.msgid.link/20260805111612.1285190-11-sth@linux.ibm.com Signed-off-by: Jens Axboe <axboe@kernel.dk>
This commit is contained in:
committed by
Jens Axboe
parent
0569784929
commit
44f9bf4798
@@ -4385,11 +4385,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;
|
||||
@@ -4399,26 +4401,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) {
|
||||
@@ -4448,7 +4455,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:
|
||||
@@ -4527,7 +4565,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);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user