18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *    Copyright IBM Corp. 2002
48c2ecf20Sopenharmony_ci *    Author(s): Cornelia Huck (cornelia.huck@de.ibm.com)
58c2ecf20Sopenharmony_ci *		 Martin Schwidefsky (schwidefsky@de.ibm.com)
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Status accumulation and basic sense functions.
88c2ecf20Sopenharmony_ci */
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include <linux/module.h>
118c2ecf20Sopenharmony_ci#include <linux/init.h>
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci#include <asm/ccwdev.h>
148c2ecf20Sopenharmony_ci#include <asm/cio.h>
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ci#include "cio.h"
178c2ecf20Sopenharmony_ci#include "cio_debug.h"
188c2ecf20Sopenharmony_ci#include "css.h"
198c2ecf20Sopenharmony_ci#include "device.h"
208c2ecf20Sopenharmony_ci#include "ioasm.h"
218c2ecf20Sopenharmony_ci#include "io_sch.h"
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci/*
248c2ecf20Sopenharmony_ci * Check for any kind of channel or interface control check but don't
258c2ecf20Sopenharmony_ci * issue the message for the console device
268c2ecf20Sopenharmony_ci */
278c2ecf20Sopenharmony_cistatic void
288c2ecf20Sopenharmony_ciccw_device_msg_control_check(struct ccw_device *cdev, struct irb *irb)
298c2ecf20Sopenharmony_ci{
308c2ecf20Sopenharmony_ci	struct subchannel *sch = to_subchannel(cdev->dev.parent);
318c2ecf20Sopenharmony_ci	char dbf_text[15];
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci	if (!scsw_is_valid_cstat(&irb->scsw) ||
348c2ecf20Sopenharmony_ci	    !(scsw_cstat(&irb->scsw) & (SCHN_STAT_CHN_DATA_CHK |
358c2ecf20Sopenharmony_ci	      SCHN_STAT_CHN_CTRL_CHK | SCHN_STAT_INTF_CTRL_CHK)))
368c2ecf20Sopenharmony_ci		return;
378c2ecf20Sopenharmony_ci	CIO_MSG_EVENT(0, "Channel-Check or Interface-Control-Check "
388c2ecf20Sopenharmony_ci		      "received"
398c2ecf20Sopenharmony_ci		      " ... device %04x on subchannel 0.%x.%04x, dev_stat "
408c2ecf20Sopenharmony_ci		      ": %02X sch_stat : %02X\n",
418c2ecf20Sopenharmony_ci		      cdev->private->dev_id.devno, sch->schid.ssid,
428c2ecf20Sopenharmony_ci		      sch->schid.sch_no,
438c2ecf20Sopenharmony_ci		      scsw_dstat(&irb->scsw), scsw_cstat(&irb->scsw));
448c2ecf20Sopenharmony_ci	sprintf(dbf_text, "chk%x", sch->schid.sch_no);
458c2ecf20Sopenharmony_ci	CIO_TRACE_EVENT(0, dbf_text);
468c2ecf20Sopenharmony_ci	CIO_HEX_EVENT(0, irb, sizeof(struct irb));
478c2ecf20Sopenharmony_ci}
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci/*
508c2ecf20Sopenharmony_ci * Some paths became not operational (pno bit in scsw is set).
518c2ecf20Sopenharmony_ci */
528c2ecf20Sopenharmony_cistatic void
538c2ecf20Sopenharmony_ciccw_device_path_notoper(struct ccw_device *cdev)
548c2ecf20Sopenharmony_ci{
558c2ecf20Sopenharmony_ci	struct subchannel *sch;
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci	sch = to_subchannel(cdev->dev.parent);
588c2ecf20Sopenharmony_ci	if (cio_update_schib(sch))
598c2ecf20Sopenharmony_ci		goto doverify;
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci	CIO_MSG_EVENT(0, "%s(0.%x.%04x) - path(s) %02x are "
628c2ecf20Sopenharmony_ci		      "not operational \n", __func__,
638c2ecf20Sopenharmony_ci		      sch->schid.ssid, sch->schid.sch_no,
648c2ecf20Sopenharmony_ci		      sch->schib.pmcw.pnom);
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci	sch->lpm &= ~sch->schib.pmcw.pnom;
678c2ecf20Sopenharmony_cidoverify:
688c2ecf20Sopenharmony_ci	cdev->private->flags.doverify = 1;
698c2ecf20Sopenharmony_ci}
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci/*
728c2ecf20Sopenharmony_ci * Copy valid bits from the extended control word to device irb.
738c2ecf20Sopenharmony_ci */
748c2ecf20Sopenharmony_cistatic void
758c2ecf20Sopenharmony_ciccw_device_accumulate_ecw(struct ccw_device *cdev, struct irb *irb)
768c2ecf20Sopenharmony_ci{
778c2ecf20Sopenharmony_ci	/*
788c2ecf20Sopenharmony_ci	 * Copy extended control bit if it is valid... yes there
798c2ecf20Sopenharmony_ci	 * are condition that have to be met for the extended control
808c2ecf20Sopenharmony_ci	 * bit to have meaning. Sick.
818c2ecf20Sopenharmony_ci	 */
828c2ecf20Sopenharmony_ci	cdev->private->dma_area->irb.scsw.cmd.ectl = 0;
838c2ecf20Sopenharmony_ci	if ((irb->scsw.cmd.stctl & SCSW_STCTL_ALERT_STATUS) &&
848c2ecf20Sopenharmony_ci	    !(irb->scsw.cmd.stctl & SCSW_STCTL_INTER_STATUS))
858c2ecf20Sopenharmony_ci		cdev->private->dma_area->irb.scsw.cmd.ectl = irb->scsw.cmd.ectl;
868c2ecf20Sopenharmony_ci	/* Check if extended control word is valid. */
878c2ecf20Sopenharmony_ci	if (!cdev->private->dma_area->irb.scsw.cmd.ectl)
888c2ecf20Sopenharmony_ci		return;
898c2ecf20Sopenharmony_ci	/* Copy concurrent sense / model dependent information. */
908c2ecf20Sopenharmony_ci	memcpy(&cdev->private->dma_area->irb.ecw, irb->ecw, sizeof(irb->ecw));
918c2ecf20Sopenharmony_ci}
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci/*
948c2ecf20Sopenharmony_ci * Check if extended status word is valid.
958c2ecf20Sopenharmony_ci */
968c2ecf20Sopenharmony_cistatic int
978c2ecf20Sopenharmony_ciccw_device_accumulate_esw_valid(struct irb *irb)
988c2ecf20Sopenharmony_ci{
998c2ecf20Sopenharmony_ci	if (!irb->scsw.cmd.eswf &&
1008c2ecf20Sopenharmony_ci	    (irb->scsw.cmd.stctl == SCSW_STCTL_STATUS_PEND))
1018c2ecf20Sopenharmony_ci		return 0;
1028c2ecf20Sopenharmony_ci	if (irb->scsw.cmd.stctl ==
1038c2ecf20Sopenharmony_ci			(SCSW_STCTL_INTER_STATUS|SCSW_STCTL_STATUS_PEND) &&
1048c2ecf20Sopenharmony_ci	    !(irb->scsw.cmd.actl & SCSW_ACTL_SUSPENDED))
1058c2ecf20Sopenharmony_ci		return 0;
1068c2ecf20Sopenharmony_ci	return 1;
1078c2ecf20Sopenharmony_ci}
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci/*
1108c2ecf20Sopenharmony_ci * Copy valid bits from the extended status word to device irb.
1118c2ecf20Sopenharmony_ci */
1128c2ecf20Sopenharmony_cistatic void
1138c2ecf20Sopenharmony_ciccw_device_accumulate_esw(struct ccw_device *cdev, struct irb *irb)
1148c2ecf20Sopenharmony_ci{
1158c2ecf20Sopenharmony_ci	struct irb *cdev_irb;
1168c2ecf20Sopenharmony_ci	struct sublog *cdev_sublog, *sublog;
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci	if (!ccw_device_accumulate_esw_valid(irb))
1198c2ecf20Sopenharmony_ci		return;
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci	cdev_irb = &cdev->private->dma_area->irb;
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci	/* Copy last path used mask. */
1248c2ecf20Sopenharmony_ci	cdev_irb->esw.esw1.lpum = irb->esw.esw1.lpum;
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci	/* Copy subchannel logout information if esw is of format 0. */
1278c2ecf20Sopenharmony_ci	if (irb->scsw.cmd.eswf) {
1288c2ecf20Sopenharmony_ci		cdev_sublog = &cdev_irb->esw.esw0.sublog;
1298c2ecf20Sopenharmony_ci		sublog = &irb->esw.esw0.sublog;
1308c2ecf20Sopenharmony_ci		/* Copy extended status flags. */
1318c2ecf20Sopenharmony_ci		cdev_sublog->esf = sublog->esf;
1328c2ecf20Sopenharmony_ci		/*
1338c2ecf20Sopenharmony_ci		 * Copy fields that have a meaning for channel data check
1348c2ecf20Sopenharmony_ci		 * channel control check and interface control check.
1358c2ecf20Sopenharmony_ci		 */
1368c2ecf20Sopenharmony_ci		if (irb->scsw.cmd.cstat & (SCHN_STAT_CHN_DATA_CHK |
1378c2ecf20Sopenharmony_ci				       SCHN_STAT_CHN_CTRL_CHK |
1388c2ecf20Sopenharmony_ci				       SCHN_STAT_INTF_CTRL_CHK)) {
1398c2ecf20Sopenharmony_ci			/* Copy ancillary report bit. */
1408c2ecf20Sopenharmony_ci			cdev_sublog->arep = sublog->arep;
1418c2ecf20Sopenharmony_ci			/* Copy field-validity-flags. */
1428c2ecf20Sopenharmony_ci			cdev_sublog->fvf = sublog->fvf;
1438c2ecf20Sopenharmony_ci			/* Copy storage access code. */
1448c2ecf20Sopenharmony_ci			cdev_sublog->sacc = sublog->sacc;
1458c2ecf20Sopenharmony_ci			/* Copy termination code. */
1468c2ecf20Sopenharmony_ci			cdev_sublog->termc = sublog->termc;
1478c2ecf20Sopenharmony_ci			/* Copy sequence code. */
1488c2ecf20Sopenharmony_ci			cdev_sublog->seqc = sublog->seqc;
1498c2ecf20Sopenharmony_ci		}
1508c2ecf20Sopenharmony_ci		/* Copy device status check. */
1518c2ecf20Sopenharmony_ci		cdev_sublog->devsc = sublog->devsc;
1528c2ecf20Sopenharmony_ci		/* Copy secondary error. */
1538c2ecf20Sopenharmony_ci		cdev_sublog->serr = sublog->serr;
1548c2ecf20Sopenharmony_ci		/* Copy i/o-error alert. */
1558c2ecf20Sopenharmony_ci		cdev_sublog->ioerr = sublog->ioerr;
1568c2ecf20Sopenharmony_ci		/* Copy channel path timeout bit. */
1578c2ecf20Sopenharmony_ci		if (irb->scsw.cmd.cstat & SCHN_STAT_INTF_CTRL_CHK)
1588c2ecf20Sopenharmony_ci			cdev_irb->esw.esw0.erw.cpt = irb->esw.esw0.erw.cpt;
1598c2ecf20Sopenharmony_ci		/* Copy failing storage address validity flag. */
1608c2ecf20Sopenharmony_ci		cdev_irb->esw.esw0.erw.fsavf = irb->esw.esw0.erw.fsavf;
1618c2ecf20Sopenharmony_ci		if (cdev_irb->esw.esw0.erw.fsavf) {
1628c2ecf20Sopenharmony_ci			/* ... and copy the failing storage address. */
1638c2ecf20Sopenharmony_ci			memcpy(cdev_irb->esw.esw0.faddr, irb->esw.esw0.faddr,
1648c2ecf20Sopenharmony_ci			       sizeof (irb->esw.esw0.faddr));
1658c2ecf20Sopenharmony_ci			/* ... and copy the failing storage address format. */
1668c2ecf20Sopenharmony_ci			cdev_irb->esw.esw0.erw.fsaf = irb->esw.esw0.erw.fsaf;
1678c2ecf20Sopenharmony_ci		}
1688c2ecf20Sopenharmony_ci		/* Copy secondary ccw address validity bit. */
1698c2ecf20Sopenharmony_ci		cdev_irb->esw.esw0.erw.scavf = irb->esw.esw0.erw.scavf;
1708c2ecf20Sopenharmony_ci		if (irb->esw.esw0.erw.scavf)
1718c2ecf20Sopenharmony_ci			/* ... and copy the secondary ccw address. */
1728c2ecf20Sopenharmony_ci			cdev_irb->esw.esw0.saddr = irb->esw.esw0.saddr;
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci	}
1758c2ecf20Sopenharmony_ci	/* FIXME: DCTI for format 2? */
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_ci	/* Copy authorization bit. */
1788c2ecf20Sopenharmony_ci	cdev_irb->esw.esw0.erw.auth = irb->esw.esw0.erw.auth;
1798c2ecf20Sopenharmony_ci	/* Copy path verification required flag. */
1808c2ecf20Sopenharmony_ci	cdev_irb->esw.esw0.erw.pvrf = irb->esw.esw0.erw.pvrf;
1818c2ecf20Sopenharmony_ci	if (irb->esw.esw0.erw.pvrf)
1828c2ecf20Sopenharmony_ci		cdev->private->flags.doverify = 1;
1838c2ecf20Sopenharmony_ci	/* Copy concurrent sense bit. */
1848c2ecf20Sopenharmony_ci	cdev_irb->esw.esw0.erw.cons = irb->esw.esw0.erw.cons;
1858c2ecf20Sopenharmony_ci	if (irb->esw.esw0.erw.cons)
1868c2ecf20Sopenharmony_ci		cdev_irb->esw.esw0.erw.scnt = irb->esw.esw0.erw.scnt;
1878c2ecf20Sopenharmony_ci}
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ci/*
1908c2ecf20Sopenharmony_ci * Accumulate status from irb to devstat.
1918c2ecf20Sopenharmony_ci */
1928c2ecf20Sopenharmony_civoid
1938c2ecf20Sopenharmony_ciccw_device_accumulate_irb(struct ccw_device *cdev, struct irb *irb)
1948c2ecf20Sopenharmony_ci{
1958c2ecf20Sopenharmony_ci	struct irb *cdev_irb;
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci	/*
1988c2ecf20Sopenharmony_ci	 * Check if the status pending bit is set in stctl.
1998c2ecf20Sopenharmony_ci	 * If not, the remaining bit have no meaning and we must ignore them.
2008c2ecf20Sopenharmony_ci	 * The esw is not meaningful as well...
2018c2ecf20Sopenharmony_ci	 */
2028c2ecf20Sopenharmony_ci	if (!(scsw_stctl(&irb->scsw) & SCSW_STCTL_STATUS_PEND))
2038c2ecf20Sopenharmony_ci		return;
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci	/* Check for channel checks and interface control checks. */
2068c2ecf20Sopenharmony_ci	ccw_device_msg_control_check(cdev, irb);
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_ci	/* Check for path not operational. */
2098c2ecf20Sopenharmony_ci	if (scsw_is_valid_pno(&irb->scsw) && scsw_pno(&irb->scsw))
2108c2ecf20Sopenharmony_ci		ccw_device_path_notoper(cdev);
2118c2ecf20Sopenharmony_ci	/* No irb accumulation for transport mode irbs. */
2128c2ecf20Sopenharmony_ci	if (scsw_is_tm(&irb->scsw)) {
2138c2ecf20Sopenharmony_ci		memcpy(&cdev->private->dma_area->irb, irb, sizeof(struct irb));
2148c2ecf20Sopenharmony_ci		return;
2158c2ecf20Sopenharmony_ci	}
2168c2ecf20Sopenharmony_ci	/*
2178c2ecf20Sopenharmony_ci	 * Don't accumulate unsolicited interrupts.
2188c2ecf20Sopenharmony_ci	 */
2198c2ecf20Sopenharmony_ci	if (!scsw_is_solicited(&irb->scsw))
2208c2ecf20Sopenharmony_ci		return;
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci	cdev_irb = &cdev->private->dma_area->irb;
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ci	/*
2258c2ecf20Sopenharmony_ci	 * If the clear function had been performed, all formerly pending
2268c2ecf20Sopenharmony_ci	 * status at the subchannel has been cleared and we must not pass
2278c2ecf20Sopenharmony_ci	 * intermediate accumulated status to the device driver.
2288c2ecf20Sopenharmony_ci	 */
2298c2ecf20Sopenharmony_ci	if (irb->scsw.cmd.fctl & SCSW_FCTL_CLEAR_FUNC)
2308c2ecf20Sopenharmony_ci		memset(&cdev->private->dma_area->irb, 0, sizeof(struct irb));
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci	/* Copy bits which are valid only for the start function. */
2338c2ecf20Sopenharmony_ci	if (irb->scsw.cmd.fctl & SCSW_FCTL_START_FUNC) {
2348c2ecf20Sopenharmony_ci		/* Copy key. */
2358c2ecf20Sopenharmony_ci		cdev_irb->scsw.cmd.key = irb->scsw.cmd.key;
2368c2ecf20Sopenharmony_ci		/* Copy suspend control bit. */
2378c2ecf20Sopenharmony_ci		cdev_irb->scsw.cmd.sctl = irb->scsw.cmd.sctl;
2388c2ecf20Sopenharmony_ci		/* Accumulate deferred condition code. */
2398c2ecf20Sopenharmony_ci		cdev_irb->scsw.cmd.cc |= irb->scsw.cmd.cc;
2408c2ecf20Sopenharmony_ci		/* Copy ccw format bit. */
2418c2ecf20Sopenharmony_ci		cdev_irb->scsw.cmd.fmt = irb->scsw.cmd.fmt;
2428c2ecf20Sopenharmony_ci		/* Copy prefetch bit. */
2438c2ecf20Sopenharmony_ci		cdev_irb->scsw.cmd.pfch = irb->scsw.cmd.pfch;
2448c2ecf20Sopenharmony_ci		/* Copy initial-status-interruption-control. */
2458c2ecf20Sopenharmony_ci		cdev_irb->scsw.cmd.isic = irb->scsw.cmd.isic;
2468c2ecf20Sopenharmony_ci		/* Copy address limit checking control. */
2478c2ecf20Sopenharmony_ci		cdev_irb->scsw.cmd.alcc = irb->scsw.cmd.alcc;
2488c2ecf20Sopenharmony_ci		/* Copy suppress suspend bit. */
2498c2ecf20Sopenharmony_ci		cdev_irb->scsw.cmd.ssi = irb->scsw.cmd.ssi;
2508c2ecf20Sopenharmony_ci	}
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ci	/* Take care of the extended control bit and extended control word. */
2538c2ecf20Sopenharmony_ci	ccw_device_accumulate_ecw(cdev, irb);
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_ci	/* Accumulate function control. */
2568c2ecf20Sopenharmony_ci	cdev_irb->scsw.cmd.fctl |= irb->scsw.cmd.fctl;
2578c2ecf20Sopenharmony_ci	/* Copy activity control. */
2588c2ecf20Sopenharmony_ci	cdev_irb->scsw.cmd.actl = irb->scsw.cmd.actl;
2598c2ecf20Sopenharmony_ci	/* Accumulate status control. */
2608c2ecf20Sopenharmony_ci	cdev_irb->scsw.cmd.stctl |= irb->scsw.cmd.stctl;
2618c2ecf20Sopenharmony_ci	/*
2628c2ecf20Sopenharmony_ci	 * Copy ccw address if it is valid. This is a bit simplified
2638c2ecf20Sopenharmony_ci	 * but should be close enough for all practical purposes.
2648c2ecf20Sopenharmony_ci	 */
2658c2ecf20Sopenharmony_ci	if ((irb->scsw.cmd.stctl & SCSW_STCTL_PRIM_STATUS) ||
2668c2ecf20Sopenharmony_ci	    ((irb->scsw.cmd.stctl ==
2678c2ecf20Sopenharmony_ci	      (SCSW_STCTL_INTER_STATUS|SCSW_STCTL_STATUS_PEND)) &&
2688c2ecf20Sopenharmony_ci	     (irb->scsw.cmd.actl & SCSW_ACTL_DEVACT) &&
2698c2ecf20Sopenharmony_ci	     (irb->scsw.cmd.actl & SCSW_ACTL_SCHACT)) ||
2708c2ecf20Sopenharmony_ci	    (irb->scsw.cmd.actl & SCSW_ACTL_SUSPENDED))
2718c2ecf20Sopenharmony_ci		cdev_irb->scsw.cmd.cpa = irb->scsw.cmd.cpa;
2728c2ecf20Sopenharmony_ci	/* Accumulate device status, but not the device busy flag. */
2738c2ecf20Sopenharmony_ci	cdev_irb->scsw.cmd.dstat &= ~DEV_STAT_BUSY;
2748c2ecf20Sopenharmony_ci	/* dstat is not always valid. */
2758c2ecf20Sopenharmony_ci	if (irb->scsw.cmd.stctl &
2768c2ecf20Sopenharmony_ci	    (SCSW_STCTL_PRIM_STATUS | SCSW_STCTL_SEC_STATUS
2778c2ecf20Sopenharmony_ci	     | SCSW_STCTL_INTER_STATUS | SCSW_STCTL_ALERT_STATUS))
2788c2ecf20Sopenharmony_ci		cdev_irb->scsw.cmd.dstat |= irb->scsw.cmd.dstat;
2798c2ecf20Sopenharmony_ci	/* Accumulate subchannel status. */
2808c2ecf20Sopenharmony_ci	cdev_irb->scsw.cmd.cstat |= irb->scsw.cmd.cstat;
2818c2ecf20Sopenharmony_ci	/* Copy residual count if it is valid. */
2828c2ecf20Sopenharmony_ci	if ((irb->scsw.cmd.stctl & SCSW_STCTL_PRIM_STATUS) &&
2838c2ecf20Sopenharmony_ci	    (irb->scsw.cmd.cstat & ~(SCHN_STAT_PCI | SCHN_STAT_INCORR_LEN))
2848c2ecf20Sopenharmony_ci	     == 0)
2858c2ecf20Sopenharmony_ci		cdev_irb->scsw.cmd.count = irb->scsw.cmd.count;
2868c2ecf20Sopenharmony_ci
2878c2ecf20Sopenharmony_ci	/* Take care of bits in the extended status word. */
2888c2ecf20Sopenharmony_ci	ccw_device_accumulate_esw(cdev, irb);
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_ci	/*
2918c2ecf20Sopenharmony_ci	 * Check whether we must issue a SENSE CCW ourselves if there is no
2928c2ecf20Sopenharmony_ci	 * concurrent sense facility installed for the subchannel.
2938c2ecf20Sopenharmony_ci	 * No sense is required if no delayed sense is pending
2948c2ecf20Sopenharmony_ci	 * and we did not get a unit check without sense information.
2958c2ecf20Sopenharmony_ci	 *
2968c2ecf20Sopenharmony_ci	 * Note: We should check for ioinfo[irq]->flags.consns but VM
2978c2ecf20Sopenharmony_ci	 *	 violates the ESA/390 architecture and doesn't present an
2988c2ecf20Sopenharmony_ci	 *	 operand exception for virtual devices without concurrent
2998c2ecf20Sopenharmony_ci	 *	 sense facility available/supported when enabling the
3008c2ecf20Sopenharmony_ci	 *	 concurrent sense facility.
3018c2ecf20Sopenharmony_ci	 */
3028c2ecf20Sopenharmony_ci	if ((cdev_irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK) &&
3038c2ecf20Sopenharmony_ci	    !(cdev_irb->esw.esw0.erw.cons))
3048c2ecf20Sopenharmony_ci		cdev->private->flags.dosense = 1;
3058c2ecf20Sopenharmony_ci}
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ci/*
3088c2ecf20Sopenharmony_ci * Do a basic sense.
3098c2ecf20Sopenharmony_ci */
3108c2ecf20Sopenharmony_ciint
3118c2ecf20Sopenharmony_ciccw_device_do_sense(struct ccw_device *cdev, struct irb *irb)
3128c2ecf20Sopenharmony_ci{
3138c2ecf20Sopenharmony_ci	struct subchannel *sch;
3148c2ecf20Sopenharmony_ci	struct ccw1 *sense_ccw;
3158c2ecf20Sopenharmony_ci	int rc;
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci	sch = to_subchannel(cdev->dev.parent);
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_ci	/* A sense is required, can we do it now ? */
3208c2ecf20Sopenharmony_ci	if (scsw_actl(&irb->scsw) & (SCSW_ACTL_DEVACT | SCSW_ACTL_SCHACT))
3218c2ecf20Sopenharmony_ci		/*
3228c2ecf20Sopenharmony_ci		 * we received an Unit Check but we have no final
3238c2ecf20Sopenharmony_ci		 *  status yet, therefore we must delay the SENSE
3248c2ecf20Sopenharmony_ci		 *  processing. We must not report this intermediate
3258c2ecf20Sopenharmony_ci		 *  status to the device interrupt handler.
3268c2ecf20Sopenharmony_ci		 */
3278c2ecf20Sopenharmony_ci		return -EBUSY;
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_ci	/*
3308c2ecf20Sopenharmony_ci	 * We have ending status but no sense information. Do a basic sense.
3318c2ecf20Sopenharmony_ci	 */
3328c2ecf20Sopenharmony_ci	sense_ccw = &to_io_private(sch)->dma_area->sense_ccw;
3338c2ecf20Sopenharmony_ci	sense_ccw->cmd_code = CCW_CMD_BASIC_SENSE;
3348c2ecf20Sopenharmony_ci	sense_ccw->cda = (__u32) __pa(cdev->private->dma_area->irb.ecw);
3358c2ecf20Sopenharmony_ci	sense_ccw->count = SENSE_MAX_COUNT;
3368c2ecf20Sopenharmony_ci	sense_ccw->flags = CCW_FLAG_SLI;
3378c2ecf20Sopenharmony_ci
3388c2ecf20Sopenharmony_ci	rc = cio_start(sch, sense_ccw, 0xff);
3398c2ecf20Sopenharmony_ci	if (rc == -ENODEV || rc == -EACCES)
3408c2ecf20Sopenharmony_ci		dev_fsm_event(cdev, DEV_EVENT_VERIFY);
3418c2ecf20Sopenharmony_ci	return rc;
3428c2ecf20Sopenharmony_ci}
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_ci/*
3458c2ecf20Sopenharmony_ci * Add information from basic sense to devstat.
3468c2ecf20Sopenharmony_ci */
3478c2ecf20Sopenharmony_civoid
3488c2ecf20Sopenharmony_ciccw_device_accumulate_basic_sense(struct ccw_device *cdev, struct irb *irb)
3498c2ecf20Sopenharmony_ci{
3508c2ecf20Sopenharmony_ci	/*
3518c2ecf20Sopenharmony_ci	 * Check if the status pending bit is set in stctl.
3528c2ecf20Sopenharmony_ci	 * If not, the remaining bit have no meaning and we must ignore them.
3538c2ecf20Sopenharmony_ci	 * The esw is not meaningful as well...
3548c2ecf20Sopenharmony_ci	 */
3558c2ecf20Sopenharmony_ci	if (!(scsw_stctl(&irb->scsw) & SCSW_STCTL_STATUS_PEND))
3568c2ecf20Sopenharmony_ci		return;
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_ci	/* Check for channel checks and interface control checks. */
3598c2ecf20Sopenharmony_ci	ccw_device_msg_control_check(cdev, irb);
3608c2ecf20Sopenharmony_ci
3618c2ecf20Sopenharmony_ci	/* Check for path not operational. */
3628c2ecf20Sopenharmony_ci	if (scsw_is_valid_pno(&irb->scsw) && scsw_pno(&irb->scsw))
3638c2ecf20Sopenharmony_ci		ccw_device_path_notoper(cdev);
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ci	if (!(irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK) &&
3668c2ecf20Sopenharmony_ci	    (irb->scsw.cmd.dstat & DEV_STAT_CHN_END)) {
3678c2ecf20Sopenharmony_ci		cdev->private->dma_area->irb.esw.esw0.erw.cons = 1;
3688c2ecf20Sopenharmony_ci		cdev->private->flags.dosense = 0;
3698c2ecf20Sopenharmony_ci	}
3708c2ecf20Sopenharmony_ci	/* Check if path verification is required. */
3718c2ecf20Sopenharmony_ci	if (ccw_device_accumulate_esw_valid(irb) &&
3728c2ecf20Sopenharmony_ci	    irb->esw.esw0.erw.pvrf)
3738c2ecf20Sopenharmony_ci		cdev->private->flags.doverify = 1;
3748c2ecf20Sopenharmony_ci}
3758c2ecf20Sopenharmony_ci
3768c2ecf20Sopenharmony_ci/*
3778c2ecf20Sopenharmony_ci * This function accumulates the status into the private devstat and
3788c2ecf20Sopenharmony_ci * starts a basic sense if one is needed.
3798c2ecf20Sopenharmony_ci */
3808c2ecf20Sopenharmony_ciint
3818c2ecf20Sopenharmony_ciccw_device_accumulate_and_sense(struct ccw_device *cdev, struct irb *irb)
3828c2ecf20Sopenharmony_ci{
3838c2ecf20Sopenharmony_ci	ccw_device_accumulate_irb(cdev, irb);
3848c2ecf20Sopenharmony_ci	if ((irb->scsw.cmd.actl  & (SCSW_ACTL_DEVACT | SCSW_ACTL_SCHACT)) != 0)
3858c2ecf20Sopenharmony_ci		return -EBUSY;
3868c2ecf20Sopenharmony_ci	/* Check for basic sense. */
3878c2ecf20Sopenharmony_ci	if (cdev->private->flags.dosense &&
3888c2ecf20Sopenharmony_ci	    !(irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK)) {
3898c2ecf20Sopenharmony_ci		cdev->private->dma_area->irb.esw.esw0.erw.cons = 1;
3908c2ecf20Sopenharmony_ci		cdev->private->flags.dosense = 0;
3918c2ecf20Sopenharmony_ci		return 0;
3928c2ecf20Sopenharmony_ci	}
3938c2ecf20Sopenharmony_ci	if (cdev->private->flags.dosense) {
3948c2ecf20Sopenharmony_ci		ccw_device_do_sense(cdev, irb);
3958c2ecf20Sopenharmony_ci		return -EBUSY;
3968c2ecf20Sopenharmony_ci	}
3978c2ecf20Sopenharmony_ci	return 0;
3988c2ecf20Sopenharmony_ci}
3998c2ecf20Sopenharmony_ci
400