Commit 18d6624e authored by Stefan Haberland's avatar Stefan Haberland Committed by Martin Schwidefsky

s390/dasd: check for availability of prefix command during format

The prefix command is used instead of a define extent to make use of
PAV alias devices during format. On some older storage servers the
prefix command may not be available and the IO request will fail.
Check for availability of prefix command and use define extent if
not available.
Signed-off-by: default avatarStefan Haberland <stefan.haberland@de.ibm.com>
Signed-off-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
parent af0ebc40
...@@ -2077,6 +2077,7 @@ dasd_eckd_build_format(struct dasd_device *base, ...@@ -2077,6 +2077,7 @@ dasd_eckd_build_format(struct dasd_device *base,
int intensity = 0; int intensity = 0;
int r0_perm; int r0_perm;
int nr_tracks; int nr_tracks;
int use_prefix;
startdev = dasd_alias_get_start_dev(base); startdev = dasd_alias_get_start_dev(base);
if (!startdev) if (!startdev)
...@@ -2106,28 +2107,46 @@ dasd_eckd_build_format(struct dasd_device *base, ...@@ -2106,28 +2107,46 @@ dasd_eckd_build_format(struct dasd_device *base,
intensity = fdata->intensity; intensity = fdata->intensity;
} }
use_prefix = base_priv->features.feature[8] & 0x01;
switch (intensity) { switch (intensity) {
case 0x00: /* Normal format */ case 0x00: /* Normal format */
case 0x08: /* Normal format, use cdl. */ case 0x08: /* Normal format, use cdl. */
cplength = 2 + (rpt*nr_tracks); cplength = 2 + (rpt*nr_tracks);
datasize = sizeof(struct PFX_eckd_data) + if (use_prefix)
sizeof(struct LO_eckd_data) + datasize = sizeof(struct PFX_eckd_data) +
rpt * nr_tracks * sizeof(struct eckd_count); sizeof(struct LO_eckd_data) +
rpt * nr_tracks * sizeof(struct eckd_count);
else
datasize = sizeof(struct DE_eckd_data) +
sizeof(struct LO_eckd_data) +
rpt * nr_tracks * sizeof(struct eckd_count);
break; break;
case 0x01: /* Write record zero and format track. */ case 0x01: /* Write record zero and format track. */
case 0x09: /* Write record zero and format track, use cdl. */ case 0x09: /* Write record zero and format track, use cdl. */
cplength = 2 + rpt * nr_tracks; cplength = 2 + rpt * nr_tracks;
datasize = sizeof(struct PFX_eckd_data) + if (use_prefix)
sizeof(struct LO_eckd_data) + datasize = sizeof(struct PFX_eckd_data) +
sizeof(struct eckd_count) + sizeof(struct LO_eckd_data) +
rpt * nr_tracks * sizeof(struct eckd_count); sizeof(struct eckd_count) +
rpt * nr_tracks * sizeof(struct eckd_count);
else
datasize = sizeof(struct DE_eckd_data) +
sizeof(struct LO_eckd_data) +
sizeof(struct eckd_count) +
rpt * nr_tracks * sizeof(struct eckd_count);
break; break;
case 0x04: /* Invalidate track. */ case 0x04: /* Invalidate track. */
case 0x0c: /* Invalidate track, use cdl. */ case 0x0c: /* Invalidate track, use cdl. */
cplength = 3; cplength = 3;
datasize = sizeof(struct PFX_eckd_data) + if (use_prefix)
sizeof(struct LO_eckd_data) + datasize = sizeof(struct PFX_eckd_data) +
sizeof(struct eckd_count); sizeof(struct LO_eckd_data) +
sizeof(struct eckd_count);
else
datasize = sizeof(struct DE_eckd_data) +
sizeof(struct LO_eckd_data) +
sizeof(struct eckd_count);
break; break;
default: default:
dev_warn(&startdev->cdev->dev, dev_warn(&startdev->cdev->dev,
...@@ -2147,14 +2166,25 @@ dasd_eckd_build_format(struct dasd_device *base, ...@@ -2147,14 +2166,25 @@ dasd_eckd_build_format(struct dasd_device *base,
switch (intensity & ~0x08) { switch (intensity & ~0x08) {
case 0x00: /* Normal format. */ case 0x00: /* Normal format. */
prefix(ccw++, (struct PFX_eckd_data *) data, if (use_prefix) {
fdata->start_unit, fdata->stop_unit, prefix(ccw++, (struct PFX_eckd_data *) data,
DASD_ECKD_CCW_WRITE_CKD, base, startdev); fdata->start_unit, fdata->stop_unit,
/* grant subsystem permission to format R0 */ DASD_ECKD_CCW_WRITE_CKD, base, startdev);
if (r0_perm) /* grant subsystem permission to format R0 */
((struct PFX_eckd_data *)data) if (r0_perm)
->define_extent.ga_extended |= 0x04; ((struct PFX_eckd_data *)data)
data += sizeof(struct PFX_eckd_data); ->define_extent.ga_extended |= 0x04;
data += sizeof(struct PFX_eckd_data);
} else {
define_extent(ccw++, (struct DE_eckd_data *) data,
fdata->start_unit, fdata->stop_unit,
DASD_ECKD_CCW_WRITE_CKD, startdev);
/* grant subsystem permission to format R0 */
if (r0_perm)
((struct DE_eckd_data *) data)
->ga_extended |= 0x04;
data += sizeof(struct DE_eckd_data);
}
ccw[-1].flags |= CCW_FLAG_CC; ccw[-1].flags |= CCW_FLAG_CC;
locate_record(ccw++, (struct LO_eckd_data *) data, locate_record(ccw++, (struct LO_eckd_data *) data,
fdata->start_unit, 0, rpt*nr_tracks, fdata->start_unit, 0, rpt*nr_tracks,
...@@ -2163,11 +2193,18 @@ dasd_eckd_build_format(struct dasd_device *base, ...@@ -2163,11 +2193,18 @@ dasd_eckd_build_format(struct dasd_device *base,
data += sizeof(struct LO_eckd_data); data += sizeof(struct LO_eckd_data);
break; break;
case 0x01: /* Write record zero + format track. */ case 0x01: /* Write record zero + format track. */
prefix(ccw++, (struct PFX_eckd_data *) data, if (use_prefix) {
fdata->start_unit, fdata->stop_unit, prefix(ccw++, (struct PFX_eckd_data *) data,
DASD_ECKD_CCW_WRITE_RECORD_ZERO, fdata->start_unit, fdata->stop_unit,
base, startdev); DASD_ECKD_CCW_WRITE_RECORD_ZERO,
data += sizeof(struct PFX_eckd_data); base, startdev);
data += sizeof(struct PFX_eckd_data);
} else {
define_extent(ccw++, (struct DE_eckd_data *) data,
fdata->start_unit, fdata->stop_unit,
DASD_ECKD_CCW_WRITE_RECORD_ZERO, startdev);
data += sizeof(struct DE_eckd_data);
}
ccw[-1].flags |= CCW_FLAG_CC; ccw[-1].flags |= CCW_FLAG_CC;
locate_record(ccw++, (struct LO_eckd_data *) data, locate_record(ccw++, (struct LO_eckd_data *) data,
fdata->start_unit, 0, rpt * nr_tracks + 1, fdata->start_unit, 0, rpt * nr_tracks + 1,
...@@ -2176,10 +2213,17 @@ dasd_eckd_build_format(struct dasd_device *base, ...@@ -2176,10 +2213,17 @@ dasd_eckd_build_format(struct dasd_device *base,
data += sizeof(struct LO_eckd_data); data += sizeof(struct LO_eckd_data);
break; break;
case 0x04: /* Invalidate track. */ case 0x04: /* Invalidate track. */
prefix(ccw++, (struct PFX_eckd_data *) data, if (use_prefix) {
fdata->start_unit, fdata->stop_unit, prefix(ccw++, (struct PFX_eckd_data *) data,
DASD_ECKD_CCW_WRITE_CKD, base, startdev); fdata->start_unit, fdata->stop_unit,
data += sizeof(struct PFX_eckd_data); DASD_ECKD_CCW_WRITE_CKD, base, startdev);
data += sizeof(struct PFX_eckd_data);
} else {
define_extent(ccw++, (struct DE_eckd_data *) data,
fdata->start_unit, fdata->stop_unit,
DASD_ECKD_CCW_WRITE_CKD, startdev);
data += sizeof(struct DE_eckd_data);
}
ccw[-1].flags |= CCW_FLAG_CC; ccw[-1].flags |= CCW_FLAG_CC;
locate_record(ccw++, (struct LO_eckd_data *) data, locate_record(ccw++, (struct LO_eckd_data *) data,
fdata->start_unit, 0, 1, fdata->start_unit, 0, 1,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment