in block/dasd_eckd.c [4251:4405]
static int prepare_itcw(struct itcw *itcw,
unsigned int trk, unsigned int totrk, int cmd,
struct dasd_device *basedev,
struct dasd_device *startdev,
unsigned int rec_on_trk, int count,
unsigned int blksize,
unsigned int total_data_size,
unsigned int tlf,
unsigned int blk_per_trk)
{
struct PFX_eckd_data pfxdata;
struct dasd_eckd_private *basepriv, *startpriv;
struct DE_eckd_data *dedata;
struct LRE_eckd_data *lredata;
struct dcw *dcw;
u32 begcyl, endcyl;
u16 heads, beghead, endhead;
u8 pfx_cmd;
int rc = 0;
int sector = 0;
int dn, d;
/* setup prefix data */
basepriv = basedev->private;
startpriv = startdev->private;
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;
/* 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;
if (startpriv->uid.type == UA_HYPER_PAV_ALIAS) {
pfxdata.validity.verify_base = 1;
pfxdata.validity.hyper_pav = 1;
}
switch (cmd) {
case DASD_ECKD_CCW_READ_TRACK_DATA:
dedata->mask.perm = 0x1;
dedata->attributes.operation = basepriv->attrib.operation;
dedata->blk_size = blksize;
dedata->ga_extended |= 0x42;
lredata->operation.orientation = 0x0;
lredata->operation.operation = 0x0C;
lredata->auxiliary.check_bytes = 0x01;
pfx_cmd = DASD_ECKD_CCW_PFX_READ;
break;
case DASD_ECKD_CCW_WRITE_TRACK_DATA:
dedata->mask.perm = 0x02;
dedata->attributes.operation = basepriv->attrib.operation;
dedata->blk_size = blksize;
rc = set_timestamp(NULL, dedata, basedev);
dedata->ga_extended |= 0x42;
lredata->operation.orientation = 0x0;
lredata->operation.operation = 0x3F;
lredata->extended_operation = 0x23;
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;
break;
case DASD_ECKD_CCW_READ_COUNT_MT:
dedata->mask.perm = 0x1;
dedata->attributes.operation = DASD_BYPASS_CACHE;
dedata->ga_extended |= 0x42;
dedata->blk_size = blksize;
lredata->operation.orientation = 0x2;
lredata->operation.operation = 0x16;
lredata->auxiliary.check_bytes = 0x01;
pfx_cmd = DASD_ECKD_CCW_PFX_READ;
break;
default:
DBF_DEV_EVENT(DBF_ERR, basedev,
"prepare itcw, unknown opcode 0x%x", cmd);
BUG();
break;
}
if (rc)
return rc;
dedata->attributes.mode = 0x3; /* ECKD */
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);
dedata->ep_format = 0x20; /* records per track is valid */
dedata->ep_rec_per_track = blk_per_trk;
if (rec_on_trk) {
switch (basepriv->rdc_data.dev_type) {
case 0x3390:
dn = ceil_quot(blksize + 6, 232);
d = 9 + ceil_quot(blksize + 6 * (dn + 1), 34);
sector = (49 + (rec_on_trk - 1) * (10 + d)) / 8;
break;
case 0x3380:
d = 7 + ceil_quot(blksize + 12, 32);
sector = (39 + (rec_on_trk - 1) * (8 + d)) / 7;
break;
}
}
if (cmd == DASD_ECKD_CCW_READ_COUNT_MT) {
lredata->auxiliary.length_valid = 0;
lredata->auxiliary.length_scope = 0;
lredata->sector = 0xff;
} else {
lredata->auxiliary.length_valid = 1;
lredata->auxiliary.length_scope = 1;
lredata->sector = sector;
}
lredata->auxiliary.imbedded_ccw_valid = 1;
lredata->length = tlf;
lredata->imbedded_ccw = cmd;
lredata->count = count;
set_ch_t(&lredata->seek_addr, begcyl, beghead);
lredata->search_arg.cyl = lredata->seek_addr.cyl;
lredata->search_arg.head = lredata->seek_addr.head;
lredata->search_arg.record = rec_on_trk;
dcw = itcw_add_dcw(itcw, pfx_cmd, 0,
&pfxdata, sizeof(pfxdata), total_data_size);
return PTR_ERR_OR_ZERO(dcw);
}