Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 45f186be authored by Jan Höppner's avatar Jan Höppner Committed by Martin Schwidefsky
Browse files

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: default avatarStefan Haberland <sth@linux.vnet.ibm.com>
Signed-off-by: default avatarJan Höppner <hoeppner@linux.vnet.ibm.com>
Signed-off-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
parent dd1023c8
Loading
Loading
Loading
Loading
+77 −140
Original line number Diff line number Diff line
@@ -213,9 +213,7 @@ 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,
static int check_XRC(struct ccw1 *ccw, struct DE_eckd_data *data,
		     struct dasd_device *device)
{
	struct dasd_eckd_private *private = device->private;
@@ -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;

	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,6 +273,12 @@ 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:
@@ -290,6 +300,17 @@ define_extent(struct ccw1 *ccw, struct DE_eckd_data *data, unsigned int trk,
		data->attributes.operation = DASD_BYPASS_CACHE;
		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,
			"0x%x is not a known command\n", cmd);
@@ -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,97 +536,18 @@ 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,
		locate_record_ext(NULL, lredata, trk, rec_on_trk, count, cmd,
				  basedev, blksize, tlf);
	}

@@ -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:
+1 −0
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@
#define DASD_ECKD_CCW_SNID		 0x34
#define DASD_ECKD_CCW_RSSD		 0x3e
#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_DEFINE_EXTENT	 0x63
#define DASD_ECKD_CCW_WRITE_MT		 0x85