浏览代码

[S390] cio: provide fake irb for transport mode IO

If a driver wants to do command mode IO while CIO is doing
online path verification we ignore this request and provide
a fake irb when we are done and the driver can do IO again.

For transport mode IO we have no such mechanism, giving the
driver no other chance then to retry the action until we are
done. This is not very reliable.

Provide a fake irb for transport mode IO as well.

Signed-off-by: Sebastian Ott <sebott@linux.vnet.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Sebastian Ott 13 年之前
父节点
当前提交
50c8e31f38
共有 3 个文件被更改,包括 37 次插入10 次删除
  1. 22 8
      drivers/s390/cio/device_fsm.c
  2. 11 1
      drivers/s390/cio/device_ops.c
  3. 4 1
      drivers/s390/cio/io_sch.h

+ 22 - 8
drivers/s390/cio/device_fsm.c

@@ -496,8 +496,26 @@ static void ccw_device_reset_path_events(struct ccw_device *cdev)
 	cdev->private->pgid_reset_mask = 0;
 	cdev->private->pgid_reset_mask = 0;
 }
 }
 
 
-void
-ccw_device_verify_done(struct ccw_device *cdev, int err)
+static void create_fake_irb(struct irb *irb, int type)
+{
+	memset(irb, 0, sizeof(*irb));
+	if (type == FAKE_CMD_IRB) {
+		struct cmd_scsw *scsw = &irb->scsw.cmd;
+		scsw->cc = 1;
+		scsw->fctl = SCSW_FCTL_START_FUNC;
+		scsw->actl = SCSW_ACTL_START_PEND;
+		scsw->stctl = SCSW_STCTL_STATUS_PEND;
+	} else if (type == FAKE_TM_IRB) {
+		struct tm_scsw *scsw = &irb->scsw.tm;
+		scsw->x = 1;
+		scsw->cc = 1;
+		scsw->fctl = SCSW_FCTL_START_FUNC;
+		scsw->actl = SCSW_ACTL_START_PEND;
+		scsw->stctl = SCSW_STCTL_STATUS_PEND;
+	}
+}
+
+void ccw_device_verify_done(struct ccw_device *cdev, int err)
 {
 {
 	struct subchannel *sch;
 	struct subchannel *sch;
 
 
@@ -520,12 +538,8 @@ callback:
 		ccw_device_done(cdev, DEV_STATE_ONLINE);
 		ccw_device_done(cdev, DEV_STATE_ONLINE);
 		/* Deliver fake irb to device driver, if needed. */
 		/* Deliver fake irb to device driver, if needed. */
 		if (cdev->private->flags.fake_irb) {
 		if (cdev->private->flags.fake_irb) {
-			memset(&cdev->private->irb, 0, sizeof(struct irb));
-			cdev->private->irb.scsw.cmd.cc = 1;
-			cdev->private->irb.scsw.cmd.fctl = SCSW_FCTL_START_FUNC;
-			cdev->private->irb.scsw.cmd.actl = SCSW_ACTL_START_PEND;
-			cdev->private->irb.scsw.cmd.stctl =
-				SCSW_STCTL_STATUS_PEND;
+			create_fake_irb(&cdev->private->irb,
+					cdev->private->flags.fake_irb);
 			cdev->private->flags.fake_irb = 0;
 			cdev->private->flags.fake_irb = 0;
 			if (cdev->handler)
 			if (cdev->handler)
 				cdev->handler(cdev, cdev->private->intparm,
 				cdev->handler(cdev, cdev->private->intparm,

+ 11 - 1
drivers/s390/cio/device_ops.c

@@ -198,7 +198,7 @@ int ccw_device_start_key(struct ccw_device *cdev, struct ccw1 *cpa,
 	if (cdev->private->state == DEV_STATE_VERIFY) {
 	if (cdev->private->state == DEV_STATE_VERIFY) {
 		/* Remember to fake irb when finished. */
 		/* Remember to fake irb when finished. */
 		if (!cdev->private->flags.fake_irb) {
 		if (!cdev->private->flags.fake_irb) {
-			cdev->private->flags.fake_irb = 1;
+			cdev->private->flags.fake_irb = FAKE_CMD_IRB;
 			cdev->private->intparm = intparm;
 			cdev->private->intparm = intparm;
 			return 0;
 			return 0;
 		} else
 		} else
@@ -605,6 +605,16 @@ int ccw_device_tm_start_key(struct ccw_device *cdev, struct tcw *tcw,
 	sch = to_subchannel(cdev->dev.parent);
 	sch = to_subchannel(cdev->dev.parent);
 	if (!sch->schib.pmcw.ena)
 	if (!sch->schib.pmcw.ena)
 		return -EINVAL;
 		return -EINVAL;
+	if (cdev->private->state == DEV_STATE_VERIFY) {
+		/* Remember to fake irb when finished. */
+		if (!cdev->private->flags.fake_irb) {
+			cdev->private->flags.fake_irb = FAKE_TM_IRB;
+			cdev->private->intparm = intparm;
+			return 0;
+		} else
+			/* There's already a fake I/O around. */
+			return -EBUSY;
+	}
 	if (cdev->private->state != DEV_STATE_ONLINE)
 	if (cdev->private->state != DEV_STATE_ONLINE)
 		return -EIO;
 		return -EIO;
 	/* Adjust requested path mask to exclude unusable paths. */
 	/* Adjust requested path mask to exclude unusable paths. */

+ 4 - 1
drivers/s390/cio/io_sch.h

@@ -111,6 +111,9 @@ enum cdev_todo {
 	CDEV_TODO_UNREG_EVAL,
 	CDEV_TODO_UNREG_EVAL,
 };
 };
 
 
+#define FAKE_CMD_IRB	1
+#define FAKE_TM_IRB	2
+
 struct ccw_device_private {
 struct ccw_device_private {
 	struct ccw_device *cdev;
 	struct ccw_device *cdev;
 	struct subchannel *sch;
 	struct subchannel *sch;
@@ -138,7 +141,7 @@ struct ccw_device_private {
 		unsigned int doverify:1;    /* delayed path verification */
 		unsigned int doverify:1;    /* delayed path verification */
 		unsigned int donotify:1;    /* call notify function */
 		unsigned int donotify:1;    /* call notify function */
 		unsigned int recog_done:1;  /* dev. recog. complete */
 		unsigned int recog_done:1;  /* dev. recog. complete */
-		unsigned int fake_irb:1;    /* deliver faked irb */
+		unsigned int fake_irb:2;    /* deliver faked irb */
 		unsigned int resuming:1;    /* recognition while resume */
 		unsigned int resuming:1;    /* recognition while resume */
 		unsigned int pgroup:1;	    /* pathgroup is set up */
 		unsigned int pgroup:1;	    /* pathgroup is set up */
 		unsigned int mpath:1;	    /* multipathing is set up */
 		unsigned int mpath:1;	    /* multipathing is set up */