s390/dasd: Refactor prefix_LRE() and related functions

We already have define_extent() that prepares necessary data for the
Define Extent CCW. The exact same thing is done in prefix_LRE().

Remove the duplicate code and move commands that were only used in
combination with the Prefix command to define_extent(). One of these
commands needs the blocksize to be specified. Add the blksize parameter
to define_extent() to account for that.

In addition, the check_XRC() function can be made more generic. Do this
and remove the Prefix-specific check_XRC_on_prefix() function.

Furthermore, prefix_LRE() uses fill_LRE_data() to prepare Locate Record
Extended data. Rename the function to fit the scheme better and make it
usable outside of the Prefix context by adding the corresponding CCW
command.

Reviewed-by: Stefan Haberland <sth@linux.vnet.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.vnet.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
This commit is contained in:
Jan Höppner 2017-03-14 11:10:16 +01:00 committed by Martin Schwidefsky
parent dd1023c89e
commit 45f186becf
2 changed files with 78 additions and 140 deletions

View File

@ -213,10 +213,8 @@ static void set_ch_t(struct ch_t *geo, __u32 cyl, __u8 head)
geo->head |= head; geo->head |= head;
} }
static int static int check_XRC(struct ccw1 *ccw, struct DE_eckd_data *data,
check_XRC (struct ccw1 *de_ccw, struct dasd_device *device)
struct DE_eckd_data *data,
struct dasd_device *device)
{ {
struct dasd_eckd_private *private = device->private; struct dasd_eckd_private *private = device->private;
int rc; int rc;
@ -224,7 +222,7 @@ check_XRC (struct ccw1 *de_ccw,
if (!private->rdc_data.facilities.XRC_supported) if (!private->rdc_data.facilities.XRC_supported)
return 0; return 0;
/* switch on System Time Stamp - needed for XRC Support */ /* switch on System Time Stamp - needed for XRC Support */
data->ga_extended |= 0x08; /* switch on 'Time Stamp Valid' */ data->ga_extended |= 0x08; /* switch on 'Time Stamp Valid' */
data->ga_extended |= 0x02; /* switch on 'Extended Parameter' */ data->ga_extended |= 0x02; /* switch on 'Extended Parameter' */
@ -233,24 +231,30 @@ check_XRC (struct ccw1 *de_ccw,
if (rc == -EOPNOTSUPP || rc == -EACCES) if (rc == -EOPNOTSUPP || rc == -EACCES)
rc = 0; rc = 0;
de_ccw->count = sizeof(struct DE_eckd_data); if (ccw) {
de_ccw->flags |= CCW_FLAG_SLI; ccw->count = sizeof(struct DE_eckd_data);
ccw->flags |= CCW_FLAG_SLI;
}
return rc; return rc;
} }
static int static int
define_extent(struct ccw1 *ccw, struct DE_eckd_data *data, unsigned int trk, define_extent(struct ccw1 *ccw, struct DE_eckd_data *data, unsigned int trk,
unsigned int totrk, int cmd, struct dasd_device *device) unsigned int totrk, int cmd, struct dasd_device *device,
int blksize)
{ {
struct dasd_eckd_private *private = device->private; struct dasd_eckd_private *private = device->private;
u32 begcyl, endcyl;
u16 heads, beghead, endhead; u16 heads, beghead, endhead;
u32 begcyl, endcyl;
int rc = 0; int rc = 0;
ccw->cmd_code = DASD_ECKD_CCW_DEFINE_EXTENT; if (ccw) {
ccw->flags = 0; ccw->cmd_code = DASD_ECKD_CCW_DEFINE_EXTENT;
ccw->count = 16; ccw->flags = 0;
ccw->cda = (__u32) __pa(data); ccw->count = 16;
ccw->cda = (__u32)__pa(data);
}
memset(data, 0, sizeof(struct DE_eckd_data)); memset(data, 0, sizeof(struct DE_eckd_data));
switch (cmd) { switch (cmd) {
@ -269,18 +273,24 @@ define_extent(struct ccw1 *ccw, struct DE_eckd_data *data, unsigned int trk,
data->mask.perm = 0x1; data->mask.perm = 0x1;
data->attributes.operation = DASD_BYPASS_CACHE; data->attributes.operation = DASD_BYPASS_CACHE;
break; break;
case DASD_ECKD_CCW_READ_TRACK:
case DASD_ECKD_CCW_READ_TRACK_DATA:
data->mask.perm = 0x1;
data->attributes.operation = private->attrib.operation;
data->blk_size = 0;
break;
case DASD_ECKD_CCW_WRITE: case DASD_ECKD_CCW_WRITE:
case DASD_ECKD_CCW_WRITE_MT: case DASD_ECKD_CCW_WRITE_MT:
case DASD_ECKD_CCW_WRITE_KD: case DASD_ECKD_CCW_WRITE_KD:
case DASD_ECKD_CCW_WRITE_KD_MT: case DASD_ECKD_CCW_WRITE_KD_MT:
data->mask.perm = 0x02; data->mask.perm = 0x02;
data->attributes.operation = private->attrib.operation; data->attributes.operation = private->attrib.operation;
rc = check_XRC (ccw, data, device); rc = check_XRC(ccw, data, device);
break; break;
case DASD_ECKD_CCW_WRITE_CKD: case DASD_ECKD_CCW_WRITE_CKD:
case DASD_ECKD_CCW_WRITE_CKD_MT: case DASD_ECKD_CCW_WRITE_CKD_MT:
data->attributes.operation = DASD_BYPASS_CACHE; data->attributes.operation = DASD_BYPASS_CACHE;
rc = check_XRC (ccw, data, device); rc = check_XRC(ccw, data, device);
break; break;
case DASD_ECKD_CCW_ERASE: case DASD_ECKD_CCW_ERASE:
case DASD_ECKD_CCW_WRITE_HOME_ADDRESS: case DASD_ECKD_CCW_WRITE_HOME_ADDRESS:
@ -288,7 +298,18 @@ define_extent(struct ccw1 *ccw, struct DE_eckd_data *data, unsigned int trk,
data->mask.perm = 0x3; data->mask.perm = 0x3;
data->mask.auth = 0x1; data->mask.auth = 0x1;
data->attributes.operation = DASD_BYPASS_CACHE; data->attributes.operation = DASD_BYPASS_CACHE;
rc = check_XRC (ccw, data, device); rc = check_XRC(ccw, data, device);
break;
case DASD_ECKD_CCW_WRITE_FULL_TRACK:
data->mask.perm = 0x03;
data->attributes.operation = private->attrib.operation;
data->blk_size = 0;
break;
case DASD_ECKD_CCW_WRITE_TRACK_DATA:
data->mask.perm = 0x02;
data->attributes.operation = private->attrib.operation;
data->blk_size = blksize;
rc = check_XRC(ccw, data, device);
break; break;
default: default:
dev_err(&device->cdev->dev, dev_err(&device->cdev->dev,
@ -325,36 +346,26 @@ define_extent(struct ccw1 *ccw, struct DE_eckd_data *data, unsigned int trk,
return rc; return rc;
} }
static int check_XRC_on_prefix(struct PFX_eckd_data *pfxdata,
struct dasd_device *device)
{
struct dasd_eckd_private *private = device->private;
int rc;
if (!private->rdc_data.facilities.XRC_supported) static void locate_record_ext(struct ccw1 *ccw, struct LRE_eckd_data *data,
return 0; unsigned int trk, unsigned int rec_on_trk,
int count, int cmd, struct dasd_device *device,
/* switch on System Time Stamp - needed for XRC Support */ unsigned int reclen, unsigned int tlf)
pfxdata->define_extent.ga_extended |= 0x08; /* 'Time Stamp Valid' */
pfxdata->define_extent.ga_extended |= 0x02; /* 'Extended Parameter' */
pfxdata->validity.time_stamp = 1; /* 'Time Stamp Valid' */
rc = get_phys_clock(&pfxdata->define_extent.ep_sys_time);
/* Ignore return code if sync clock is switched off. */
if (rc == -EOPNOTSUPP || rc == -EACCES)
rc = 0;
return rc;
}
static void fill_LRE_data(struct LRE_eckd_data *data, unsigned int trk,
unsigned int rec_on_trk, int count, int cmd,
struct dasd_device *device, unsigned int reclen,
unsigned int tlf)
{ {
struct dasd_eckd_private *private = device->private; struct dasd_eckd_private *private = device->private;
int sector; int sector;
int dn, d; int dn, d;
if (ccw) {
ccw->cmd_code = DASD_ECKD_CCW_LOCATE_RECORD_EXT;
ccw->flags = 0;
if (cmd == DASD_ECKD_CCW_WRITE_FULL_TRACK)
ccw->count = 22;
else
ccw->count = 20;
ccw->cda = (__u32)__pa(data);
}
memset(data, 0, sizeof(*data)); memset(data, 0, sizeof(*data));
sector = 0; sector = 0;
if (rec_on_trk) { if (rec_on_trk) {
@ -481,14 +492,12 @@ static void fill_LRE_data(struct LRE_eckd_data *data, unsigned int trk,
static int prefix_LRE(struct ccw1 *ccw, struct PFX_eckd_data *pfxdata, static int prefix_LRE(struct ccw1 *ccw, struct PFX_eckd_data *pfxdata,
unsigned int trk, unsigned int totrk, int cmd, unsigned int trk, unsigned int totrk, int cmd,
struct dasd_device *basedev, struct dasd_device *startdev, struct dasd_device *basedev, struct dasd_device *startdev,
unsigned char format, unsigned int rec_on_trk, int count, unsigned int format, unsigned int rec_on_trk, int count,
unsigned int blksize, unsigned int tlf) unsigned int blksize, unsigned int tlf)
{ {
struct dasd_eckd_private *basepriv, *startpriv; struct dasd_eckd_private *basepriv, *startpriv;
struct DE_eckd_data *dedata;
struct LRE_eckd_data *lredata; struct LRE_eckd_data *lredata;
u32 begcyl, endcyl; struct DE_eckd_data *dedata;
u16 heads, beghead, endhead;
int rc = 0; int rc = 0;
basepriv = basedev->private; basepriv = basedev->private;
@ -527,98 +536,19 @@ static int prefix_LRE(struct ccw1 *ccw, struct PFX_eckd_data *pfxdata,
pfxdata->validity.hyper_pav = 1; pfxdata->validity.hyper_pav = 1;
} }
/* define extend data (mostly)*/ rc = define_extent(NULL, dedata, trk, totrk, cmd, basedev, blksize);
switch (cmd) {
case DASD_ECKD_CCW_READ_HOME_ADDRESS:
case DASD_ECKD_CCW_READ_RECORD_ZERO:
case DASD_ECKD_CCW_READ:
case DASD_ECKD_CCW_READ_MT:
case DASD_ECKD_CCW_READ_CKD:
case DASD_ECKD_CCW_READ_CKD_MT:
case DASD_ECKD_CCW_READ_KD:
case DASD_ECKD_CCW_READ_KD_MT:
dedata->mask.perm = 0x1;
dedata->attributes.operation = basepriv->attrib.operation;
break;
case DASD_ECKD_CCW_READ_COUNT:
dedata->mask.perm = 0x1;
dedata->attributes.operation = DASD_BYPASS_CACHE;
break;
case DASD_ECKD_CCW_READ_TRACK:
case DASD_ECKD_CCW_READ_TRACK_DATA:
dedata->mask.perm = 0x1;
dedata->attributes.operation = basepriv->attrib.operation;
dedata->blk_size = 0;
break;
case DASD_ECKD_CCW_WRITE:
case DASD_ECKD_CCW_WRITE_MT:
case DASD_ECKD_CCW_WRITE_KD:
case DASD_ECKD_CCW_WRITE_KD_MT:
dedata->mask.perm = 0x02;
dedata->attributes.operation = basepriv->attrib.operation;
rc = check_XRC_on_prefix(pfxdata, basedev);
break;
case DASD_ECKD_CCW_WRITE_CKD:
case DASD_ECKD_CCW_WRITE_CKD_MT:
dedata->attributes.operation = DASD_BYPASS_CACHE;
rc = check_XRC_on_prefix(pfxdata, basedev);
break;
case DASD_ECKD_CCW_ERASE:
case DASD_ECKD_CCW_WRITE_HOME_ADDRESS:
case DASD_ECKD_CCW_WRITE_RECORD_ZERO:
dedata->mask.perm = 0x3;
dedata->mask.auth = 0x1;
dedata->attributes.operation = DASD_BYPASS_CACHE;
rc = check_XRC_on_prefix(pfxdata, basedev);
break;
case DASD_ECKD_CCW_WRITE_FULL_TRACK:
dedata->mask.perm = 0x03;
dedata->attributes.operation = basepriv->attrib.operation;
dedata->blk_size = 0;
break;
case DASD_ECKD_CCW_WRITE_TRACK_DATA:
dedata->mask.perm = 0x02;
dedata->attributes.operation = basepriv->attrib.operation;
dedata->blk_size = blksize;
rc = check_XRC_on_prefix(pfxdata, basedev);
break;
default:
DBF_DEV_EVENT(DBF_ERR, basedev,
"PFX LRE unknown opcode 0x%x", cmd);
BUG();
return -EINVAL;
}
dedata->attributes.mode = 0x3; /* ECKD */ /*
* For some commands the System Time Stamp is set in the define extent
if ((basepriv->rdc_data.cu_type == 0x2105 || * data when XRC is supported. The validity of the time stamp must be
basepriv->rdc_data.cu_type == 0x2107 || * reflected in the prefix data as well.
basepriv->rdc_data.cu_type == 0x1750) */
&& !(basepriv->uses_cdl && trk < 2)) if (dedata->ga_extended & 0x08 && dedata->ga_extended & 0x02)
dedata->ga_extended |= 0x40; /* Regular Data Format Mode */ pfxdata->validity.time_stamp = 1; /* 'Time Stamp Valid' */
heads = basepriv->rdc_data.trk_per_cyl;
begcyl = trk / heads;
beghead = trk % heads;
endcyl = totrk / heads;
endhead = totrk % heads;
/* check for sequential prestage - enhance cylinder range */
if (dedata->attributes.operation == DASD_SEQ_PRESTAGE ||
dedata->attributes.operation == DASD_SEQ_ACCESS) {
if (endcyl + basepriv->attrib.nr_cyl < basepriv->real_cyl)
endcyl += basepriv->attrib.nr_cyl;
else
endcyl = (basepriv->real_cyl - 1);
}
set_ch_t(&dedata->beg_ext, begcyl, beghead);
set_ch_t(&dedata->end_ext, endcyl, endhead);
if (format == 1) { if (format == 1) {
fill_LRE_data(lredata, trk, rec_on_trk, count, cmd, locate_record_ext(NULL, lredata, trk, rec_on_trk, count, cmd,
basedev, blksize, tlf); basedev, blksize, tlf);
} }
return rc; return rc;
@ -1887,7 +1817,7 @@ dasd_eckd_analysis_ccw(struct dasd_device *device)
ccw = cqr->cpaddr; ccw = cqr->cpaddr;
/* Define extent for the first 3 tracks. */ /* Define extent for the first 3 tracks. */
define_extent(ccw++, cqr->data, 0, 2, define_extent(ccw++, cqr->data, 0, 2,
DASD_ECKD_CCW_READ_COUNT, device); DASD_ECKD_CCW_READ_COUNT, device, 0);
LO_data = cqr->data + sizeof(struct DE_eckd_data); LO_data = cqr->data + sizeof(struct DE_eckd_data);
/* Locate record for the first 4 records on track 0. */ /* Locate record for the first 4 records on track 0. */
ccw[-1].flags |= CCW_FLAG_CC; ccw[-1].flags |= CCW_FLAG_CC;
@ -2266,7 +2196,7 @@ dasd_eckd_build_check(struct dasd_device *base, struct format_data_t *fdata,
count, 0, 0); count, 0, 0);
} else { } else {
define_extent(ccw++, data, fdata->start_unit, fdata->stop_unit, define_extent(ccw++, data, fdata->start_unit, fdata->stop_unit,
DASD_ECKD_CCW_READ_COUNT, startdev); DASD_ECKD_CCW_READ_COUNT, startdev, 0);
data += sizeof(struct DE_eckd_data); data += sizeof(struct DE_eckd_data);
ccw[-1].flags |= CCW_FLAG_CC; ccw[-1].flags |= CCW_FLAG_CC;
@ -2420,7 +2350,7 @@ dasd_eckd_build_format(struct dasd_device *base,
} else { } else {
define_extent(ccw++, (struct DE_eckd_data *) data, define_extent(ccw++, (struct DE_eckd_data *) data,
fdata->start_unit, fdata->stop_unit, fdata->start_unit, fdata->stop_unit,
DASD_ECKD_CCW_WRITE_CKD, startdev); DASD_ECKD_CCW_WRITE_CKD, startdev, 0);
/* grant subsystem permission to format R0 */ /* grant subsystem permission to format R0 */
if (r0_perm) if (r0_perm)
((struct DE_eckd_data *) data) ((struct DE_eckd_data *) data)
@ -2444,7 +2374,7 @@ dasd_eckd_build_format(struct dasd_device *base,
} else { } else {
define_extent(ccw++, (struct DE_eckd_data *) data, define_extent(ccw++, (struct DE_eckd_data *) data,
fdata->start_unit, fdata->stop_unit, fdata->start_unit, fdata->stop_unit,
DASD_ECKD_CCW_WRITE_RECORD_ZERO, startdev); DASD_ECKD_CCW_WRITE_RECORD_ZERO, startdev, 0);
data += sizeof(struct DE_eckd_data); data += sizeof(struct DE_eckd_data);
} }
ccw[-1].flags |= CCW_FLAG_CC; ccw[-1].flags |= CCW_FLAG_CC;
@ -2463,7 +2393,7 @@ dasd_eckd_build_format(struct dasd_device *base,
} else { } else {
define_extent(ccw++, (struct DE_eckd_data *) data, define_extent(ccw++, (struct DE_eckd_data *) data,
fdata->start_unit, fdata->stop_unit, fdata->start_unit, fdata->stop_unit,
DASD_ECKD_CCW_WRITE_CKD, startdev); DASD_ECKD_CCW_WRITE_CKD, startdev, 0);
data += sizeof(struct DE_eckd_data); data += sizeof(struct DE_eckd_data);
} }
ccw[-1].flags |= CCW_FLAG_CC; ccw[-1].flags |= CCW_FLAG_CC;
@ -3187,7 +3117,7 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_cmd_single(
sizeof(struct PFX_eckd_data)); sizeof(struct PFX_eckd_data));
} else { } else {
if (define_extent(ccw++, cqr->data, first_trk, if (define_extent(ccw++, cqr->data, first_trk,
last_trk, cmd, basedev) == -EAGAIN) { last_trk, cmd, basedev, 0) == -EAGAIN) {
/* Clock not in sync and XRC is enabled. /* Clock not in sync and XRC is enabled.
* Try again later. * Try again later.
*/ */
@ -3509,12 +3439,19 @@ static int prepare_itcw(struct itcw *itcw,
dedata->mask.perm = 0x02; dedata->mask.perm = 0x02;
dedata->attributes.operation = basepriv->attrib.operation; dedata->attributes.operation = basepriv->attrib.operation;
dedata->blk_size = blksize; dedata->blk_size = blksize;
rc = check_XRC_on_prefix(&pfxdata, basedev); rc = check_XRC(NULL, dedata, basedev);
dedata->ga_extended |= 0x42; dedata->ga_extended |= 0x42;
lredata->operation.orientation = 0x0; lredata->operation.orientation = 0x0;
lredata->operation.operation = 0x3F; lredata->operation.operation = 0x3F;
lredata->extended_operation = 0x23; lredata->extended_operation = 0x23;
lredata->auxiliary.check_bytes = 0x2; lredata->auxiliary.check_bytes = 0x2;
/*
* 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; pfx_cmd = DASD_ECKD_CCW_PFX;
break; break;
case DASD_ECKD_CCW_READ_COUNT_MT: case DASD_ECKD_CCW_READ_COUNT_MT:

View File

@ -29,6 +29,7 @@
#define DASD_ECKD_CCW_SNID 0x34 #define DASD_ECKD_CCW_SNID 0x34
#define DASD_ECKD_CCW_RSSD 0x3e #define DASD_ECKD_CCW_RSSD 0x3e
#define DASD_ECKD_CCW_LOCATE_RECORD 0x47 #define DASD_ECKD_CCW_LOCATE_RECORD 0x47
#define DASD_ECKD_CCW_LOCATE_RECORD_EXT 0x4b
#define DASD_ECKD_CCW_SNSS 0x54 #define DASD_ECKD_CCW_SNSS 0x54
#define DASD_ECKD_CCW_DEFINE_EXTENT 0x63 #define DASD_ECKD_CCW_DEFINE_EXTENT 0x63
#define DASD_ECKD_CCW_WRITE_MT 0x85 #define DASD_ECKD_CCW_WRITE_MT 0x85