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

Commit 83262d63 authored by Peter Oberparleiter's avatar Peter Oberparleiter Committed by Heiko Carstens
Browse files

[S390] cio: provide functions for fcx enabled I/O



Provide functions for assembling and starting fcx enabled I/O request
blocks.

Signed-off-by: default avatarPeter Oberparleiter <peter.oberparleiter@de.ibm.com>
Signed-off-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
Signed-off-by: default avatarHeiko Carstens <heiko.carstens@de.ibm.com>
parent 23d805b6
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -2,7 +2,7 @@
# Makefile for the S/390 common i/o drivers
#

obj-y += airq.o blacklist.o chsc.o cio.o css.o chp.o idset.o scsw.o
obj-y += airq.o blacklist.o chsc.o cio.o css.o chp.o idset.o scsw.o fcx.o
ccw_device-objs += device.o device_fsm.o device_ops.o
ccw_device-objs += device_id.o device_pgid.o device_status.o
obj-y += ccw_device.o cmf.o
+70 −11
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@
#include <asm/chpid.h>
#include <asm/airq.h>
#include <asm/cpu.h>
#include <asm/fcx.h>
#include "cio.h"
#include "css.h"
#include "chsc.h"
@@ -167,30 +168,30 @@ cio_start_key (struct subchannel *sch, /* subchannel structure */
{
	char dbf_txt[15];
	int ccode;
	struct orb *orb;
	union orb *orb;

	CIO_TRACE_EVENT(4, "stIO");
	CIO_TRACE_EVENT(4, sch->dev.bus_id);

	orb = &to_io_private(sch)->orb;
	/* sch is always under 2G. */
	orb->intparm = (u32)(addr_t)sch;
	orb->fmt = 1;
	orb->cmd.intparm = (u32)(addr_t)sch;
	orb->cmd.fmt = 1;

	orb->pfch = sch->options.prefetch == 0;
	orb->spnd = sch->options.suspend;
	orb->ssic = sch->options.suspend && sch->options.inter;
	orb->lpm = (lpm != 0) ? lpm : sch->lpm;
	orb->cmd.pfch = sch->options.prefetch == 0;
	orb->cmd.spnd = sch->options.suspend;
	orb->cmd.ssic = sch->options.suspend && sch->options.inter;
	orb->cmd.lpm = (lpm != 0) ? lpm : sch->lpm;
#ifdef CONFIG_64BIT
	/*
	 * for 64 bit we always support 64 bit IDAWs with 4k page size only
	 */
	orb->c64 = 1;
	orb->i2k = 0;
	orb->cmd.c64 = 1;
	orb->cmd.i2k = 0;
#endif
	orb->key = key >> 4;
	orb->cmd.key = key >> 4;
	/* issue "Start Subchannel" */
	orb->cpa = (__u32) __pa(cpa);
	orb->cmd.cpa = (__u32) __pa(cpa);
	ccode = ssch(sch->schid, orb);

	/* process condition code */
@@ -1067,3 +1068,61 @@ int __init cio_get_iplinfo(struct cio_iplinfo *iplinfo)
	iplinfo->is_qdio = schib.pmcw.qf;
	return 0;
}

/**
 * cio_tm_start_key - perform start function
 * @sch: subchannel on which to perform the start function
 * @tcw: transport-command word to be started
 * @lpm: mask of paths to use
 * @key: storage key to use for storage access
 *
 * Start the tcw on the given subchannel. Return zero on success, non-zero
 * otherwise.
 */
int cio_tm_start_key(struct subchannel *sch, struct tcw *tcw, u8 lpm, u8 key)
{
	int cc;
	union orb *orb = &to_io_private(sch)->orb;

	memset(orb, 0, sizeof(union orb));
	orb->tm.intparm = (u32) (addr_t) sch;
	orb->tm.key = key >> 4;
	orb->tm.b = 1;
	orb->tm.lpm = lpm ? lpm : sch->lpm;
	orb->tm.tcw = (u32) (addr_t) tcw;
	cc = ssch(sch->schid, orb);
	switch (cc) {
	case 0:
		return 0;
	case 1:
	case 2:
		return -EBUSY;
	default:
		return cio_start_handle_notoper(sch, lpm);
	}
}

/**
 * cio_tm_intrg - perform interrogate function
 * @sch - subchannel on which to perform the interrogate function
 *
 * If the specified subchannel is running in transport-mode, perform the
 * interrogate function. Return zero on success, non-zero otherwie.
 */
int cio_tm_intrg(struct subchannel *sch)
{
	int cc;

	if (!to_io_private(sch)->orb.tm.b)
		return -EINVAL;
	cc = xsch(sch->schid);
	switch (cc) {
	case 0:
	case 2:
		return 0;
	case 1:
		return -EBUSY;
	default:
		return -ENODEV;
	}
}
+5 −0
Original line number Diff line number Diff line
@@ -5,6 +5,8 @@
#include <linux/device.h>
#include <linux/mod_devicetable.h>
#include <asm/chpid.h>
#include <asm/cio.h>
#include <asm/fcx.h>
#include "chsc.h"
#include "schid.h"

@@ -100,6 +102,9 @@ extern int cio_set_options (struct subchannel *, int);
extern int cio_get_options (struct subchannel *);
extern int cio_modify (struct subchannel *);

int cio_tm_start_key(struct subchannel *sch, struct tcw *tcw, u8 lpm, u8 key);
int cio_tm_intrg(struct subchannel *sch);

int cio_create_sch_lock(struct subchannel *);
void do_adapter_IO(void);
void do_IRQ(struct pt_regs *);
+33 −16
Original line number Diff line number Diff line
@@ -39,31 +39,43 @@ static void ccw_timeout_log(struct ccw_device *cdev)
	struct schib schib;
	struct subchannel *sch;
	struct io_subchannel_private *private;
	union orb *orb;
	int cc;

	sch = to_subchannel(cdev->dev.parent);
	private = to_io_private(sch);
	orb = &private->orb;
	cc = stsch(sch->schid, &schib);

	printk(KERN_WARNING "cio: ccw device timeout occurred at %llx, "
	       "device information:\n", get_clock());
	printk(KERN_WARNING "cio: orb:\n");
	print_hex_dump(KERN_WARNING, "cio:  ", DUMP_PREFIX_NONE, 16, 1,
		       &private->orb, sizeof(private->orb), 0);
		       orb, sizeof(*orb), 0);
	printk(KERN_WARNING "cio: ccw device bus id: %s\n", cdev->dev.bus_id);
	printk(KERN_WARNING "cio: subchannel bus id: %s\n", sch->dev.bus_id);
	printk(KERN_WARNING "cio: subchannel lpm: %02x, opm: %02x, "
	       "vpm: %02x\n", sch->lpm, sch->opm, sch->vpm);

	if ((void *)(addr_t)private->orb.cpa == &private->sense_ccw ||
	    (void *)(addr_t)private->orb.cpa == cdev->private->iccws)
		printk(KERN_WARNING "cio: last channel program (intern):\n");
	if (orb->tm.b) {
		printk(KERN_WARNING "cio: orb indicates transport mode\n");
		printk(KERN_WARNING "cio: last tcw:\n");
		print_hex_dump(KERN_WARNING, "cio:  ", DUMP_PREFIX_NONE, 16, 1,
			       (void *)(addr_t)orb->tm.tcw,
			       sizeof(struct tcw), 0);
	} else {
		printk(KERN_WARNING "cio: orb indicates command mode\n");
		if ((void *)(addr_t)orb->cmd.cpa == &private->sense_ccw ||
		    (void *)(addr_t)orb->cmd.cpa == cdev->private->iccws)
			printk(KERN_WARNING "cio: last channel program "
			       "(intern):\n");
		else
			printk(KERN_WARNING "cio: last channel program:\n");

		print_hex_dump(KERN_WARNING, "cio:  ", DUMP_PREFIX_NONE, 16, 1,
		       (void *)(addr_t)private->orb.cpa,
			       (void *)(addr_t)orb->cmd.cpa,
			       sizeof(struct ccw1), 0);
	}
	printk(KERN_WARNING "cio: ccw device state: %d\n",
	       cdev->private->state);
	printk(KERN_WARNING "cio: store subchannel returned: cc=%d\n", cc);
@@ -135,10 +147,13 @@ ccw_device_cancel_halt_clear(struct ccw_device *cdev)
	/* Stage 1: cancel io. */
	if (!(scsw_actl(&sch->schib.scsw) & SCSW_ACTL_HALT_PEND) &&
	    !(scsw_actl(&sch->schib.scsw) & SCSW_ACTL_CLEAR_PEND)) {
		if (!scsw_is_tm(&sch->schib.scsw)) {
			ret = cio_cancel(sch);
			if (ret != -EINVAL)
				return ret;
		/* cancel io unsuccessful. From now on it is asynchronous. */
		}
		/* cancel io unsuccessful or not applicable (transport mode).
		 * Continue with asynchronous instructions. */
		cdev->private->iretry = 3;	/* 3 halt retries. */
	}
	if (!(scsw_actl(&sch->schib.scsw) & SCSW_ACTL_CLEAR_PEND)) {
@@ -751,11 +766,13 @@ static void
ccw_device_irq(struct ccw_device *cdev, enum dev_event dev_event)
{
	struct irb *irb;
	int is_cmd;

	irb = (struct irb *) __LC_IRB;
	is_cmd = !scsw_is_tm(&irb->scsw);
	/* Check for unsolicited interrupt. */
	if (!scsw_is_solicited(&irb->scsw)) {
		if ((irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK) &&
		if (is_cmd && (irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK) &&
		    !irb->esw.esw0.erw.cons) {
			/* Unit check but no sense data. Need basic sense. */
			if (ccw_device_do_sense(cdev, irb) != 0)
@@ -774,7 +791,7 @@ ccw_device_irq(struct ccw_device *cdev, enum dev_event dev_event)
	}
	/* Accumulate status and find out if a basic sense is needed. */
	ccw_device_accumulate_irb(cdev, irb);
	if (cdev->private->flags.dosense) {
	if (is_cmd && cdev->private->flags.dosense) {
		if (ccw_device_do_sense(cdev, irb) == 0) {
			cdev->private->state = DEV_STATE_W4SENSE;
		}
+1 −1
Original line number Diff line number Diff line
@@ -237,7 +237,7 @@ ccw_device_check_sense_id(struct ccw_device *cdev)
	if (irb->scsw.cmd.cc == 3) {
		u8 lpm;

		lpm = to_io_private(sch)->orb.lpm;
		lpm = to_io_private(sch)->orb.cmd.lpm;
		if ((lpm & sch->schib.pmcw.pim & sch->schib.pmcw.pam) != 0)
			CIO_MSG_EVENT(4, "SenseID : path %02X for device %04x "
				      "on subchannel 0.%x.%04x is "
Loading