Skip to content

Commit

Permalink
s390/dasd: check for availability of prefix command during format
Browse files Browse the repository at this point in the history
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: Stefan Haberland <stefan.haberland@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
  • Loading branch information
Stefan Haberland authored and Martin Schwidefsky committed Oct 15, 2013
1 parent af0ebc4 commit 18d6624
Showing 1 changed file with 71 additions and 27 deletions.
98 changes: 71 additions & 27 deletions drivers/s390/block/dasd_eckd.c
Original file line number Diff line number Diff line change
Expand Up @@ -2077,6 +2077,7 @@ dasd_eckd_build_format(struct dasd_device *base,
int intensity = 0;
int r0_perm;
int nr_tracks;
int use_prefix;

startdev = dasd_alias_get_start_dev(base);
if (!startdev)
Expand Down Expand Up @@ -2106,28 +2107,46 @@ dasd_eckd_build_format(struct dasd_device *base,
intensity = fdata->intensity;
}

use_prefix = base_priv->features.feature[8] & 0x01;

switch (intensity) {
case 0x00: /* Normal format */
case 0x08: /* Normal format, use cdl. */
cplength = 2 + (rpt*nr_tracks);
datasize = sizeof(struct PFX_eckd_data) +
sizeof(struct LO_eckd_data) +
rpt * nr_tracks * sizeof(struct eckd_count);
if (use_prefix)
datasize = sizeof(struct PFX_eckd_data) +
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;
case 0x01: /* Write record zero and format track. */
case 0x09: /* Write record zero and format track, use cdl. */
cplength = 2 + rpt * nr_tracks;
datasize = sizeof(struct PFX_eckd_data) +
sizeof(struct LO_eckd_data) +
sizeof(struct eckd_count) +
rpt * nr_tracks * sizeof(struct eckd_count);
if (use_prefix)
datasize = sizeof(struct PFX_eckd_data) +
sizeof(struct LO_eckd_data) +
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;
case 0x04: /* Invalidate track. */
case 0x0c: /* Invalidate track, use cdl. */
cplength = 3;
datasize = sizeof(struct PFX_eckd_data) +
sizeof(struct LO_eckd_data) +
sizeof(struct eckd_count);
if (use_prefix)
datasize = sizeof(struct PFX_eckd_data) +
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;
default:
dev_warn(&startdev->cdev->dev,
Expand All @@ -2147,14 +2166,25 @@ dasd_eckd_build_format(struct dasd_device *base,

switch (intensity & ~0x08) {
case 0x00: /* Normal format. */
prefix(ccw++, (struct PFX_eckd_data *) data,
fdata->start_unit, fdata->stop_unit,
DASD_ECKD_CCW_WRITE_CKD, base, startdev);
/* grant subsystem permission to format R0 */
if (r0_perm)
((struct PFX_eckd_data *)data)
->define_extent.ga_extended |= 0x04;
data += sizeof(struct PFX_eckd_data);
if (use_prefix) {
prefix(ccw++, (struct PFX_eckd_data *) data,
fdata->start_unit, fdata->stop_unit,
DASD_ECKD_CCW_WRITE_CKD, base, startdev);
/* grant subsystem permission to format R0 */
if (r0_perm)
((struct PFX_eckd_data *)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;
locate_record(ccw++, (struct LO_eckd_data *) data,
fdata->start_unit, 0, rpt*nr_tracks,
Expand All @@ -2163,11 +2193,18 @@ dasd_eckd_build_format(struct dasd_device *base,
data += sizeof(struct LO_eckd_data);
break;
case 0x01: /* Write record zero + format track. */
prefix(ccw++, (struct PFX_eckd_data *) data,
fdata->start_unit, fdata->stop_unit,
DASD_ECKD_CCW_WRITE_RECORD_ZERO,
base, startdev);
data += sizeof(struct PFX_eckd_data);
if (use_prefix) {
prefix(ccw++, (struct PFX_eckd_data *) data,
fdata->start_unit, fdata->stop_unit,
DASD_ECKD_CCW_WRITE_RECORD_ZERO,
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;
locate_record(ccw++, (struct LO_eckd_data *) data,
fdata->start_unit, 0, rpt * nr_tracks + 1,
Expand All @@ -2176,10 +2213,17 @@ dasd_eckd_build_format(struct dasd_device *base,
data += sizeof(struct LO_eckd_data);
break;
case 0x04: /* Invalidate track. */
prefix(ccw++, (struct PFX_eckd_data *) data,
fdata->start_unit, fdata->stop_unit,
DASD_ECKD_CCW_WRITE_CKD, base, startdev);
data += sizeof(struct PFX_eckd_data);
if (use_prefix) {
prefix(ccw++, (struct PFX_eckd_data *) data,
fdata->start_unit, fdata->stop_unit,
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;
locate_record(ccw++, (struct LO_eckd_data *) data,
fdata->start_unit, 0, 1,
Expand Down

0 comments on commit 18d6624

Please sign in to comment.