|
@@ -213,10 +213,8 @@ static void set_ch_t(struct ch_t *geo, __u32 cyl, __u8 head)
|
|
|
geo->head |= head;
|
|
|
}
|
|
|
|
|
|
-static int
|
|
|
-check_XRC (struct ccw1 *de_ccw,
|
|
|
- struct DE_eckd_data *data,
|
|
|
- struct dasd_device *device)
|
|
|
+static int check_XRC(struct ccw1 *ccw, struct DE_eckd_data *data,
|
|
|
+ struct dasd_device *device)
|
|
|
{
|
|
|
struct dasd_eckd_private *private = device->private;
|
|
|
int rc;
|
|
@@ -224,7 +222,7 @@ check_XRC (struct ccw1 *de_ccw,
|
|
|
if (!private->rdc_data.facilities.XRC_supported)
|
|
|
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 |= 0x02; /* switch on 'Extended Parameter' */
|
|
|
|
|
@@ -233,24 +231,30 @@ check_XRC (struct ccw1 *de_ccw,
|
|
|
if (rc == -EOPNOTSUPP || rc == -EACCES)
|
|
|
rc = 0;
|
|
|
|
|
|
- de_ccw->count = sizeof(struct DE_eckd_data);
|
|
|
- de_ccw->flags |= CCW_FLAG_SLI;
|
|
|
+ if (ccw) {
|
|
|
+ ccw->count = sizeof(struct DE_eckd_data);
|
|
|
+ ccw->flags |= CCW_FLAG_SLI;
|
|
|
+ }
|
|
|
+
|
|
|
return rc;
|
|
|
}
|
|
|
|
|
|
static int
|
|
|
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;
|
|
|
- u32 begcyl, endcyl;
|
|
|
u16 heads, beghead, endhead;
|
|
|
+ u32 begcyl, endcyl;
|
|
|
int rc = 0;
|
|
|
|
|
|
- ccw->cmd_code = DASD_ECKD_CCW_DEFINE_EXTENT;
|
|
|
- ccw->flags = 0;
|
|
|
- ccw->count = 16;
|
|
|
- ccw->cda = (__u32) __pa(data);
|
|
|
+ if (ccw) {
|
|
|
+ ccw->cmd_code = DASD_ECKD_CCW_DEFINE_EXTENT;
|
|
|
+ ccw->flags = 0;
|
|
|
+ ccw->count = 16;
|
|
|
+ ccw->cda = (__u32)__pa(data);
|
|
|
+ }
|
|
|
|
|
|
memset(data, 0, sizeof(struct DE_eckd_data));
|
|
|
switch (cmd) {
|
|
@@ -269,18 +273,24 @@ define_extent(struct ccw1 *ccw, struct DE_eckd_data *data, unsigned int trk,
|
|
|
data->mask.perm = 0x1;
|
|
|
data->attributes.operation = DASD_BYPASS_CACHE;
|
|
|
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_MT:
|
|
|
case DASD_ECKD_CCW_WRITE_KD:
|
|
|
case DASD_ECKD_CCW_WRITE_KD_MT:
|
|
|
data->mask.perm = 0x02;
|
|
|
data->attributes.operation = private->attrib.operation;
|
|
|
- rc = check_XRC (ccw, data, device);
|
|
|
+ rc = check_XRC(ccw, data, device);
|
|
|
break;
|
|
|
case DASD_ECKD_CCW_WRITE_CKD:
|
|
|
case DASD_ECKD_CCW_WRITE_CKD_MT:
|
|
|
data->attributes.operation = DASD_BYPASS_CACHE;
|
|
|
- rc = check_XRC (ccw, data, device);
|
|
|
+ rc = check_XRC(ccw, data, device);
|
|
|
break;
|
|
|
case DASD_ECKD_CCW_ERASE:
|
|
|
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.auth = 0x1;
|
|
|
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;
|
|
|
default:
|
|
|
dev_err(&device->cdev->dev,
|
|
@@ -325,36 +346,26 @@ define_extent(struct ccw1 *ccw, struct DE_eckd_data *data, unsigned int trk,
|
|
|
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)
|
|
|
- return 0;
|
|
|
-
|
|
|
- /* switch on System Time Stamp - needed for XRC Support */
|
|
|
- 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)
|
|
|
+static void locate_record_ext(struct ccw1 *ccw, 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;
|
|
|
int sector;
|
|
|
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));
|
|
|
sector = 0;
|
|
|
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,
|
|
|
unsigned int trk, unsigned int totrk, int cmd,
|
|
|
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)
|
|
|
{
|
|
|
struct dasd_eckd_private *basepriv, *startpriv;
|
|
|
- struct DE_eckd_data *dedata;
|
|
|
struct LRE_eckd_data *lredata;
|
|
|
- u32 begcyl, endcyl;
|
|
|
- u16 heads, beghead, endhead;
|
|
|
+ struct DE_eckd_data *dedata;
|
|
|
int rc = 0;
|
|
|
|
|
|
basepriv = basedev->private;
|
|
@@ -527,98 +536,19 @@ static int prefix_LRE(struct ccw1 *ccw, struct PFX_eckd_data *pfxdata,
|
|
|
pfxdata->validity.hyper_pav = 1;
|
|
|
}
|
|
|
|
|
|
- /* define extend data (mostly)*/
|
|
|
- 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 */
|
|
|
-
|
|
|
- if ((basepriv->rdc_data.cu_type == 0x2105 ||
|
|
|
- basepriv->rdc_data.cu_type == 0x2107 ||
|
|
|
- basepriv->rdc_data.cu_type == 0x1750)
|
|
|
- && !(basepriv->uses_cdl && trk < 2))
|
|
|
- dedata->ga_extended |= 0x40; /* Regular Data Format Mode */
|
|
|
-
|
|
|
- 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);
|
|
|
- }
|
|
|
+ rc = define_extent(NULL, dedata, trk, totrk, cmd, basedev, blksize);
|
|
|
|
|
|
- set_ch_t(&dedata->beg_ext, begcyl, beghead);
|
|
|
- set_ch_t(&dedata->end_ext, endcyl, endhead);
|
|
|
+ /*
|
|
|
+ * For some commands the System Time Stamp is set in the define extent
|
|
|
+ * data when XRC is supported. 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' */
|
|
|
|
|
|
if (format == 1) {
|
|
|
- fill_LRE_data(lredata, trk, rec_on_trk, count, cmd,
|
|
|
- basedev, blksize, tlf);
|
|
|
+ locate_record_ext(NULL, lredata, trk, rec_on_trk, count, cmd,
|
|
|
+ basedev, blksize, tlf);
|
|
|
}
|
|
|
|
|
|
return rc;
|
|
@@ -1887,7 +1817,7 @@ dasd_eckd_analysis_ccw(struct dasd_device *device)
|
|
|
ccw = cqr->cpaddr;
|
|
|
/* Define extent for the first 3 tracks. */
|
|
|
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);
|
|
|
/* Locate record for the first 4 records on track 0. */
|
|
|
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);
|
|
|
} else {
|
|
|
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);
|
|
|
ccw[-1].flags |= CCW_FLAG_CC;
|
|
@@ -2420,7 +2350,7 @@ dasd_eckd_build_format(struct dasd_device *base,
|
|
|
} else {
|
|
|
define_extent(ccw++, (struct DE_eckd_data *) data,
|
|
|
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 */
|
|
|
if (r0_perm)
|
|
|
((struct DE_eckd_data *) data)
|
|
@@ -2444,7 +2374,7 @@ dasd_eckd_build_format(struct dasd_device *base,
|
|
|
} else {
|
|
|
define_extent(ccw++, (struct DE_eckd_data *) data,
|
|
|
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);
|
|
|
}
|
|
|
ccw[-1].flags |= CCW_FLAG_CC;
|
|
@@ -2463,7 +2393,7 @@ dasd_eckd_build_format(struct dasd_device *base,
|
|
|
} else {
|
|
|
define_extent(ccw++, (struct DE_eckd_data *) data,
|
|
|
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);
|
|
|
}
|
|
|
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));
|
|
|
} else {
|
|
|
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.
|
|
|
* Try again later.
|
|
|
*/
|
|
@@ -3509,12 +3439,19 @@ static int prepare_itcw(struct itcw *itcw,
|
|
|
dedata->mask.perm = 0x02;
|
|
|
dedata->attributes.operation = basepriv->attrib.operation;
|
|
|
dedata->blk_size = blksize;
|
|
|
- rc = check_XRC_on_prefix(&pfxdata, basedev);
|
|
|
+ rc = check_XRC(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:
|
|
@@ -3842,25 +3779,28 @@ static struct dasd_ccw_req *dasd_eckd_build_cp(struct dasd_device *startdev,
|
|
|
return cqr;
|
|
|
}
|
|
|
|
|
|
-static struct dasd_ccw_req *dasd_raw_build_cp(struct dasd_device *startdev,
|
|
|
- struct dasd_block *block,
|
|
|
- struct request *req)
|
|
|
+static struct dasd_ccw_req *dasd_eckd_build_cp_raw(struct dasd_device *startdev,
|
|
|
+ struct dasd_block *block,
|
|
|
+ struct request *req)
|
|
|
{
|
|
|
- unsigned long *idaws;
|
|
|
+ sector_t start_padding_sectors, end_sector_offset, end_padding_sectors;
|
|
|
+ unsigned int seg_len, len_to_track_end;
|
|
|
+ unsigned int cidaw, cplength, datasize;
|
|
|
+ sector_t first_trk, last_trk, sectors;
|
|
|
+ struct dasd_eckd_private *base_priv;
|
|
|
struct dasd_device *basedev;
|
|
|
- struct dasd_ccw_req *cqr;
|
|
|
- struct ccw1 *ccw;
|
|
|
struct req_iterator iter;
|
|
|
+ struct dasd_ccw_req *cqr;
|
|
|
+ unsigned int first_offs;
|
|
|
+ unsigned int trkcount;
|
|
|
+ unsigned long *idaws;
|
|
|
+ unsigned int size;
|
|
|
+ unsigned char cmd;
|
|
|
struct bio_vec bv;
|
|
|
+ struct ccw1 *ccw;
|
|
|
+ int use_prefix;
|
|
|
+ void *data;
|
|
|
char *dst;
|
|
|
- unsigned char cmd;
|
|
|
- unsigned int trkcount;
|
|
|
- unsigned int seg_len, len_to_track_end;
|
|
|
- unsigned int first_offs;
|
|
|
- unsigned int cidaw, cplength, datasize;
|
|
|
- sector_t first_trk, last_trk, sectors;
|
|
|
- sector_t start_padding_sectors, end_sector_offset, end_padding_sectors;
|
|
|
- unsigned int pfx_datasize;
|
|
|
|
|
|
/*
|
|
|
* raw track access needs to be mutiple of 64k and on 64k boundary
|
|
@@ -3878,8 +3818,7 @@ static struct dasd_ccw_req *dasd_raw_build_cp(struct dasd_device *startdev,
|
|
|
DBF_DEV_EVENT(DBF_ERR, basedev,
|
|
|
"raw write not track aligned (%lu,%lu) req %p",
|
|
|
start_padding_sectors, end_padding_sectors, req);
|
|
|
- cqr = ERR_PTR(-EINVAL);
|
|
|
- goto out;
|
|
|
+ return ERR_PTR(-EINVAL);
|
|
|
}
|
|
|
|
|
|
first_trk = blk_rq_pos(req) / DASD_RAW_SECTORS_PER_TRACK;
|
|
@@ -3892,10 +3831,8 @@ static struct dasd_ccw_req *dasd_raw_build_cp(struct dasd_device *startdev,
|
|
|
cmd = DASD_ECKD_CCW_READ_TRACK;
|
|
|
else if (rq_data_dir(req) == WRITE)
|
|
|
cmd = DASD_ECKD_CCW_WRITE_FULL_TRACK;
|
|
|
- else {
|
|
|
- cqr = ERR_PTR(-EINVAL);
|
|
|
- goto out;
|
|
|
- }
|
|
|
+ else
|
|
|
+ return ERR_PTR(-EINVAL);
|
|
|
|
|
|
/*
|
|
|
* Raw track based I/O needs IDAWs for each page,
|
|
@@ -3903,38 +3840,46 @@ static struct dasd_ccw_req *dasd_raw_build_cp(struct dasd_device *startdev,
|
|
|
*/
|
|
|
cidaw = trkcount * DASD_RAW_BLOCK_PER_TRACK;
|
|
|
|
|
|
- /* 1x prefix + one read/write ccw per track */
|
|
|
- cplength = 1 + trkcount;
|
|
|
-
|
|
|
/*
|
|
|
- * struct PFX_eckd_data has up to 2 byte as extended parameter
|
|
|
- * this is needed for write full track and has to be mentioned
|
|
|
- * separately
|
|
|
- * add 8 instead of 2 to keep 8 byte boundary
|
|
|
+ * struct PFX_eckd_data and struct LRE_eckd_data can have up to 2 bytes
|
|
|
+ * of extended parameter. This is needed for write full track.
|
|
|
*/
|
|
|
- pfx_datasize = sizeof(struct PFX_eckd_data) + 8;
|
|
|
+ base_priv = basedev->private;
|
|
|
+ use_prefix = base_priv->features.feature[8] & 0x01;
|
|
|
+ if (use_prefix) {
|
|
|
+ cplength = 1 + trkcount;
|
|
|
+ size = sizeof(struct PFX_eckd_data) + 2;
|
|
|
+ } else {
|
|
|
+ cplength = 2 + trkcount;
|
|
|
+ size = sizeof(struct DE_eckd_data) +
|
|
|
+ sizeof(struct LRE_eckd_data) + 2;
|
|
|
+ }
|
|
|
+ size = ALIGN(size, 8);
|
|
|
|
|
|
- datasize = pfx_datasize + cidaw * sizeof(unsigned long long);
|
|
|
+ datasize = size + cidaw * sizeof(unsigned long long);
|
|
|
|
|
|
/* Allocate the ccw request. */
|
|
|
cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, cplength,
|
|
|
datasize, startdev);
|
|
|
if (IS_ERR(cqr))
|
|
|
- goto out;
|
|
|
+ return cqr;
|
|
|
+
|
|
|
ccw = cqr->cpaddr;
|
|
|
+ data = cqr->data;
|
|
|
|
|
|
- if (prefix_LRE(ccw++, cqr->data, first_trk, last_trk, cmd,
|
|
|
- basedev, startdev, 1 /* format */, first_offs + 1,
|
|
|
- trkcount, 0, 0) == -EAGAIN) {
|
|
|
- /* Clock not in sync and XRC is enabled.
|
|
|
- * Try again later.
|
|
|
- */
|
|
|
- dasd_sfree_request(cqr, startdev);
|
|
|
- cqr = ERR_PTR(-EAGAIN);
|
|
|
- goto out;
|
|
|
+ if (use_prefix) {
|
|
|
+ prefix_LRE(ccw++, data, first_trk, last_trk, cmd, basedev,
|
|
|
+ startdev, 1, first_offs + 1, trkcount, 0, 0);
|
|
|
+ } else {
|
|
|
+ define_extent(ccw++, data, first_trk, last_trk, cmd, basedev, 0);
|
|
|
+ ccw[-1].flags |= CCW_FLAG_CC;
|
|
|
+
|
|
|
+ data += sizeof(struct DE_eckd_data);
|
|
|
+ locate_record_ext(ccw++, data, first_trk, first_offs + 1,
|
|
|
+ trkcount, cmd, basedev, 0, 0);
|
|
|
}
|
|
|
|
|
|
- idaws = (unsigned long *)(cqr->data + pfx_datasize);
|
|
|
+ idaws = (unsigned long *)(cqr->data + size);
|
|
|
len_to_track_end = 0;
|
|
|
if (start_padding_sectors) {
|
|
|
ccw[-1].flags |= CCW_FLAG_CC;
|
|
@@ -3984,9 +3929,6 @@ static struct dasd_ccw_req *dasd_raw_build_cp(struct dasd_device *startdev,
|
|
|
cqr->buildclk = get_tod_clock();
|
|
|
cqr->status = DASD_CQR_FILLED;
|
|
|
|
|
|
- if (IS_ERR(cqr) && PTR_ERR(cqr) != -EAGAIN)
|
|
|
- cqr = NULL;
|
|
|
-out:
|
|
|
return cqr;
|
|
|
}
|
|
|
|
|
@@ -4096,7 +4038,7 @@ static struct dasd_ccw_req *dasd_eckd_build_alias_cp(struct dasd_device *base,
|
|
|
spin_lock_irqsave(get_ccwdev_lock(startdev->cdev), flags);
|
|
|
private->count++;
|
|
|
if ((base->features & DASD_FEATURE_USERAW))
|
|
|
- cqr = dasd_raw_build_cp(startdev, block, req);
|
|
|
+ cqr = dasd_eckd_build_cp_raw(startdev, block, req);
|
|
|
else
|
|
|
cqr = dasd_eckd_build_cp(startdev, block, req);
|
|
|
if (IS_ERR(cqr))
|