162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Author(s)......: Horst  Hummel    <Horst.Hummel@de.ibm.com>
462306a36Sopenharmony_ci *		    Holger Smolinski <Holger.Smolinski@de.ibm.com>
562306a36Sopenharmony_ci * Bugreports.to..: <Linux390@de.ibm.com>
662306a36Sopenharmony_ci * Copyright IBM Corp. 2000, 2001
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#define KMSG_COMPONENT "dasd-eckd"
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#include <linux/timer.h>
1362306a36Sopenharmony_ci#include <asm/idals.h>
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#define PRINTK_HEADER "dasd_erp(3990): "
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci#include "dasd_int.h"
1862306a36Sopenharmony_ci#include "dasd_eckd.h"
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_cistruct DCTL_data {
2262306a36Sopenharmony_ci	unsigned char subcommand;  /* e.g Inhibit Write, Enable Write,... */
2362306a36Sopenharmony_ci	unsigned char modifier;	   /* Subcommand modifier */
2462306a36Sopenharmony_ci	unsigned short res;	   /* reserved */
2562306a36Sopenharmony_ci} __attribute__ ((packed));
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci/*
2862306a36Sopenharmony_ci *****************************************************************************
2962306a36Sopenharmony_ci * SECTION ERP HANDLING
3062306a36Sopenharmony_ci *****************************************************************************
3162306a36Sopenharmony_ci */
3262306a36Sopenharmony_ci/*
3362306a36Sopenharmony_ci *****************************************************************************
3462306a36Sopenharmony_ci * 24 and 32 byte sense ERP functions
3562306a36Sopenharmony_ci *****************************************************************************
3662306a36Sopenharmony_ci */
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci/*
3962306a36Sopenharmony_ci * DASD_3990_ERP_CLEANUP
4062306a36Sopenharmony_ci *
4162306a36Sopenharmony_ci * DESCRIPTION
4262306a36Sopenharmony_ci *   Removes the already build but not necessary ERP request and sets
4362306a36Sopenharmony_ci *   the status of the original cqr / erp to the given (final) status
4462306a36Sopenharmony_ci *
4562306a36Sopenharmony_ci *  PARAMETER
4662306a36Sopenharmony_ci *   erp		request to be blocked
4762306a36Sopenharmony_ci *   final_status	either DASD_CQR_DONE or DASD_CQR_FAILED
4862306a36Sopenharmony_ci *
4962306a36Sopenharmony_ci * RETURN VALUES
5062306a36Sopenharmony_ci *   cqr		original cqr
5162306a36Sopenharmony_ci */
5262306a36Sopenharmony_cistatic struct dasd_ccw_req *
5362306a36Sopenharmony_cidasd_3990_erp_cleanup(struct dasd_ccw_req * erp, char final_status)
5462306a36Sopenharmony_ci{
5562306a36Sopenharmony_ci	struct dasd_ccw_req *cqr = erp->refers;
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci	dasd_free_erp_request(erp, erp->memdev);
5862306a36Sopenharmony_ci	cqr->status = final_status;
5962306a36Sopenharmony_ci	return cqr;
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci}				/* end dasd_3990_erp_cleanup */
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci/*
6462306a36Sopenharmony_ci * DASD_3990_ERP_BLOCK_QUEUE
6562306a36Sopenharmony_ci *
6662306a36Sopenharmony_ci * DESCRIPTION
6762306a36Sopenharmony_ci *   Block the given device request queue to prevent from further
6862306a36Sopenharmony_ci *   processing until the started timer has expired or an related
6962306a36Sopenharmony_ci *   interrupt was received.
7062306a36Sopenharmony_ci */
7162306a36Sopenharmony_cistatic void dasd_3990_erp_block_queue(struct dasd_ccw_req *erp, int expires)
7262306a36Sopenharmony_ci{
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci	struct dasd_device *device = erp->startdev;
7562306a36Sopenharmony_ci	unsigned long flags;
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci	DBF_DEV_EVENT(DBF_INFO, device,
7862306a36Sopenharmony_ci		    "blocking request queue for %is", expires/HZ);
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci	spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
8162306a36Sopenharmony_ci	dasd_device_set_stop_bits(device, DASD_STOPPED_PENDING);
8262306a36Sopenharmony_ci	spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
8362306a36Sopenharmony_ci	erp->status = DASD_CQR_FILLED;
8462306a36Sopenharmony_ci	if (erp->block)
8562306a36Sopenharmony_ci		dasd_block_set_timer(erp->block, expires);
8662306a36Sopenharmony_ci	else
8762306a36Sopenharmony_ci		dasd_device_set_timer(device, expires);
8862306a36Sopenharmony_ci}
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci/*
9162306a36Sopenharmony_ci * DASD_3990_ERP_INT_REQ
9262306a36Sopenharmony_ci *
9362306a36Sopenharmony_ci * DESCRIPTION
9462306a36Sopenharmony_ci *   Handles 'Intervention Required' error.
9562306a36Sopenharmony_ci *   This means either device offline or not installed.
9662306a36Sopenharmony_ci *
9762306a36Sopenharmony_ci * PARAMETER
9862306a36Sopenharmony_ci *   erp		current erp
9962306a36Sopenharmony_ci * RETURN VALUES
10062306a36Sopenharmony_ci *   erp		modified erp
10162306a36Sopenharmony_ci */
10262306a36Sopenharmony_cistatic struct dasd_ccw_req *
10362306a36Sopenharmony_cidasd_3990_erp_int_req(struct dasd_ccw_req * erp)
10462306a36Sopenharmony_ci{
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci	struct dasd_device *device = erp->startdev;
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	/* first time set initial retry counter and erp_function */
10962306a36Sopenharmony_ci	/* and retry once without blocking queue		 */
11062306a36Sopenharmony_ci	/* (this enables easier enqueing of the cqr)		 */
11162306a36Sopenharmony_ci	if (erp->function != dasd_3990_erp_int_req) {
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci		erp->retries = 256;
11462306a36Sopenharmony_ci		erp->function = dasd_3990_erp_int_req;
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	} else {
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci		/* issue a message and wait for 'device ready' interrupt */
11962306a36Sopenharmony_ci		dev_err(&device->cdev->dev,
12062306a36Sopenharmony_ci			    "is offline or not installed - "
12162306a36Sopenharmony_ci			    "INTERVENTION REQUIRED!!\n");
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci		dasd_3990_erp_block_queue(erp, 60*HZ);
12462306a36Sopenharmony_ci	}
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci	return erp;
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci}				/* end dasd_3990_erp_int_req */
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci/*
13162306a36Sopenharmony_ci * DASD_3990_ERP_ALTERNATE_PATH
13262306a36Sopenharmony_ci *
13362306a36Sopenharmony_ci * DESCRIPTION
13462306a36Sopenharmony_ci *   Repeat the operation on a different channel path.
13562306a36Sopenharmony_ci *   If all alternate paths have been tried, the request is posted with a
13662306a36Sopenharmony_ci *   permanent error.
13762306a36Sopenharmony_ci *
13862306a36Sopenharmony_ci *  PARAMETER
13962306a36Sopenharmony_ci *   erp		pointer to the current ERP
14062306a36Sopenharmony_ci *
14162306a36Sopenharmony_ci * RETURN VALUES
14262306a36Sopenharmony_ci *   erp		modified pointer to the ERP
14362306a36Sopenharmony_ci */
14462306a36Sopenharmony_cistatic void
14562306a36Sopenharmony_cidasd_3990_erp_alternate_path(struct dasd_ccw_req * erp)
14662306a36Sopenharmony_ci{
14762306a36Sopenharmony_ci	struct dasd_device *device = erp->startdev;
14862306a36Sopenharmony_ci	__u8 opm;
14962306a36Sopenharmony_ci	unsigned long flags;
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci	/* try alternate valid path */
15262306a36Sopenharmony_ci	spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
15362306a36Sopenharmony_ci	opm = ccw_device_get_path_mask(device->cdev);
15462306a36Sopenharmony_ci	spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
15562306a36Sopenharmony_ci	if (erp->lpm == 0)
15662306a36Sopenharmony_ci		erp->lpm = dasd_path_get_opm(device) &
15762306a36Sopenharmony_ci			~(erp->irb.esw.esw0.sublog.lpum);
15862306a36Sopenharmony_ci	else
15962306a36Sopenharmony_ci		erp->lpm &= ~(erp->irb.esw.esw0.sublog.lpum);
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci	if ((erp->lpm & opm) != 0x00) {
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ci		DBF_DEV_EVENT(DBF_WARNING, device,
16462306a36Sopenharmony_ci			    "try alternate lpm=%x (lpum=%x / opm=%x)",
16562306a36Sopenharmony_ci			    erp->lpm, erp->irb.esw.esw0.sublog.lpum, opm);
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci		/* reset status to submit the request again... */
16862306a36Sopenharmony_ci		erp->status = DASD_CQR_FILLED;
16962306a36Sopenharmony_ci		erp->retries = 10;
17062306a36Sopenharmony_ci	} else {
17162306a36Sopenharmony_ci		dev_err(&device->cdev->dev,
17262306a36Sopenharmony_ci			"The DASD cannot be reached on any path (lpum=%x"
17362306a36Sopenharmony_ci			"/opm=%x)\n", erp->irb.esw.esw0.sublog.lpum, opm);
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci		/* post request with permanent error */
17662306a36Sopenharmony_ci		erp->status = DASD_CQR_FAILED;
17762306a36Sopenharmony_ci	}
17862306a36Sopenharmony_ci}				/* end dasd_3990_erp_alternate_path */
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci/*
18162306a36Sopenharmony_ci * DASD_3990_ERP_DCTL
18262306a36Sopenharmony_ci *
18362306a36Sopenharmony_ci * DESCRIPTION
18462306a36Sopenharmony_ci *   Setup cqr to do the Diagnostic Control (DCTL) command with an
18562306a36Sopenharmony_ci *   Inhibit Write subcommand (0x20) and the given modifier.
18662306a36Sopenharmony_ci *
18762306a36Sopenharmony_ci *  PARAMETER
18862306a36Sopenharmony_ci *   erp		pointer to the current (failed) ERP
18962306a36Sopenharmony_ci *   modifier		subcommand modifier
19062306a36Sopenharmony_ci *
19162306a36Sopenharmony_ci * RETURN VALUES
19262306a36Sopenharmony_ci *   dctl_cqr		pointer to NEW dctl_cqr
19362306a36Sopenharmony_ci *
19462306a36Sopenharmony_ci */
19562306a36Sopenharmony_cistatic struct dasd_ccw_req *
19662306a36Sopenharmony_cidasd_3990_erp_DCTL(struct dasd_ccw_req * erp, char modifier)
19762306a36Sopenharmony_ci{
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci	struct dasd_device *device = erp->startdev;
20062306a36Sopenharmony_ci	struct DCTL_data *DCTL_data;
20162306a36Sopenharmony_ci	struct ccw1 *ccw;
20262306a36Sopenharmony_ci	struct dasd_ccw_req *dctl_cqr;
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	dctl_cqr = dasd_alloc_erp_request(erp->magic, 1,
20562306a36Sopenharmony_ci					  sizeof(struct DCTL_data),
20662306a36Sopenharmony_ci					  device);
20762306a36Sopenharmony_ci	if (IS_ERR(dctl_cqr)) {
20862306a36Sopenharmony_ci		dev_err(&device->cdev->dev,
20962306a36Sopenharmony_ci			    "Unable to allocate DCTL-CQR\n");
21062306a36Sopenharmony_ci		erp->status = DASD_CQR_FAILED;
21162306a36Sopenharmony_ci		return erp;
21262306a36Sopenharmony_ci	}
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci	DCTL_data = dctl_cqr->data;
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci	DCTL_data->subcommand = 0x02;	/* Inhibit Write */
21762306a36Sopenharmony_ci	DCTL_data->modifier = modifier;
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci	ccw = dctl_cqr->cpaddr;
22062306a36Sopenharmony_ci	memset(ccw, 0, sizeof(struct ccw1));
22162306a36Sopenharmony_ci	ccw->cmd_code = CCW_CMD_DCTL;
22262306a36Sopenharmony_ci	ccw->count = 4;
22362306a36Sopenharmony_ci	ccw->cda = (__u32)virt_to_phys(DCTL_data);
22462306a36Sopenharmony_ci	dctl_cqr->flags = erp->flags;
22562306a36Sopenharmony_ci	dctl_cqr->function = dasd_3990_erp_DCTL;
22662306a36Sopenharmony_ci	dctl_cqr->refers = erp;
22762306a36Sopenharmony_ci	dctl_cqr->startdev = device;
22862306a36Sopenharmony_ci	dctl_cqr->memdev = device;
22962306a36Sopenharmony_ci	dctl_cqr->magic = erp->magic;
23062306a36Sopenharmony_ci	dctl_cqr->expires = 5 * 60 * HZ;
23162306a36Sopenharmony_ci	dctl_cqr->retries = 2;
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci	dctl_cqr->buildclk = get_tod_clock();
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci	dctl_cqr->status = DASD_CQR_FILLED;
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci	return dctl_cqr;
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci}				/* end dasd_3990_erp_DCTL */
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci/*
24262306a36Sopenharmony_ci * DASD_3990_ERP_ACTION_1
24362306a36Sopenharmony_ci *
24462306a36Sopenharmony_ci * DESCRIPTION
24562306a36Sopenharmony_ci *   Setup ERP to do the ERP action 1 (see Reference manual).
24662306a36Sopenharmony_ci *   Repeat the operation on a different channel path.
24762306a36Sopenharmony_ci *   As deviation from the recommended recovery action, we reset the path mask
24862306a36Sopenharmony_ci *   after we have tried each path and go through all paths a second time.
24962306a36Sopenharmony_ci *   This will cover situations where only one path at a time is actually down,
25062306a36Sopenharmony_ci *   but all paths fail and recover just with the same sequence and timing as
25162306a36Sopenharmony_ci *   we try to use them (flapping links).
25262306a36Sopenharmony_ci *   If all alternate paths have been tried twice, the request is posted with
25362306a36Sopenharmony_ci *   a permanent error.
25462306a36Sopenharmony_ci *
25562306a36Sopenharmony_ci *  PARAMETER
25662306a36Sopenharmony_ci *   erp		pointer to the current ERP
25762306a36Sopenharmony_ci *
25862306a36Sopenharmony_ci * RETURN VALUES
25962306a36Sopenharmony_ci *   erp		pointer to the ERP
26062306a36Sopenharmony_ci *
26162306a36Sopenharmony_ci */
26262306a36Sopenharmony_cistatic struct dasd_ccw_req *dasd_3990_erp_action_1_sec(struct dasd_ccw_req *erp)
26362306a36Sopenharmony_ci{
26462306a36Sopenharmony_ci	erp->function = dasd_3990_erp_action_1_sec;
26562306a36Sopenharmony_ci	dasd_3990_erp_alternate_path(erp);
26662306a36Sopenharmony_ci	return erp;
26762306a36Sopenharmony_ci}
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_cistatic struct dasd_ccw_req *dasd_3990_erp_action_1(struct dasd_ccw_req *erp)
27062306a36Sopenharmony_ci{
27162306a36Sopenharmony_ci	erp->function = dasd_3990_erp_action_1;
27262306a36Sopenharmony_ci	dasd_3990_erp_alternate_path(erp);
27362306a36Sopenharmony_ci	if (erp->status == DASD_CQR_FAILED &&
27462306a36Sopenharmony_ci	    !test_bit(DASD_CQR_VERIFY_PATH, &erp->flags)) {
27562306a36Sopenharmony_ci		erp->status = DASD_CQR_FILLED;
27662306a36Sopenharmony_ci		erp->retries = 10;
27762306a36Sopenharmony_ci		erp->lpm = dasd_path_get_opm(erp->startdev);
27862306a36Sopenharmony_ci		erp->function = dasd_3990_erp_action_1_sec;
27962306a36Sopenharmony_ci	}
28062306a36Sopenharmony_ci	return erp;
28162306a36Sopenharmony_ci}				/* end dasd_3990_erp_action_1(b) */
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci/*
28462306a36Sopenharmony_ci * DASD_3990_ERP_ACTION_4
28562306a36Sopenharmony_ci *
28662306a36Sopenharmony_ci * DESCRIPTION
28762306a36Sopenharmony_ci *   Setup ERP to do the ERP action 4 (see Reference manual).
28862306a36Sopenharmony_ci *   Set the current request to PENDING to block the CQR queue for that device
28962306a36Sopenharmony_ci *   until the state change interrupt appears.
29062306a36Sopenharmony_ci *   Use a timer (20 seconds) to retry the cqr if the interrupt is still
29162306a36Sopenharmony_ci *   missing.
29262306a36Sopenharmony_ci *
29362306a36Sopenharmony_ci *  PARAMETER
29462306a36Sopenharmony_ci *   sense		sense data of the actual error
29562306a36Sopenharmony_ci *   erp		pointer to the current ERP
29662306a36Sopenharmony_ci *
29762306a36Sopenharmony_ci * RETURN VALUES
29862306a36Sopenharmony_ci *   erp		pointer to the ERP
29962306a36Sopenharmony_ci *
30062306a36Sopenharmony_ci */
30162306a36Sopenharmony_cistatic struct dasd_ccw_req *
30262306a36Sopenharmony_cidasd_3990_erp_action_4(struct dasd_ccw_req * erp, char *sense)
30362306a36Sopenharmony_ci{
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_ci	struct dasd_device *device = erp->startdev;
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci	/* first time set initial retry counter and erp_function    */
30862306a36Sopenharmony_ci	/* and retry once without waiting for state change pending  */
30962306a36Sopenharmony_ci	/* interrupt (this enables easier enqueing of the cqr)	    */
31062306a36Sopenharmony_ci	if (erp->function != dasd_3990_erp_action_4) {
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci		DBF_DEV_EVENT(DBF_INFO, device, "%s",
31362306a36Sopenharmony_ci			    "dasd_3990_erp_action_4: first time retry");
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci		erp->retries = 256;
31662306a36Sopenharmony_ci		erp->function = dasd_3990_erp_action_4;
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci	} else {
31962306a36Sopenharmony_ci		if (sense && (sense[25] == 0x1D)) { /* state change pending */
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci			DBF_DEV_EVENT(DBF_INFO, device,
32262306a36Sopenharmony_ci				    "waiting for state change pending "
32362306a36Sopenharmony_ci				    "interrupt, %d retries left",
32462306a36Sopenharmony_ci				    erp->retries);
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci			dasd_3990_erp_block_queue(erp, 30*HZ);
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci		} else if (sense && (sense[25] == 0x1E)) {	/* busy */
32962306a36Sopenharmony_ci			DBF_DEV_EVENT(DBF_INFO, device,
33062306a36Sopenharmony_ci				    "busy - redriving request later, "
33162306a36Sopenharmony_ci				    "%d retries left",
33262306a36Sopenharmony_ci				    erp->retries);
33362306a36Sopenharmony_ci                        dasd_3990_erp_block_queue(erp, HZ);
33462306a36Sopenharmony_ci		} else {
33562306a36Sopenharmony_ci			/* no state change pending - retry */
33662306a36Sopenharmony_ci			DBF_DEV_EVENT(DBF_INFO, device,
33762306a36Sopenharmony_ci				     "redriving request immediately, "
33862306a36Sopenharmony_ci				     "%d retries left",
33962306a36Sopenharmony_ci				     erp->retries);
34062306a36Sopenharmony_ci			erp->status = DASD_CQR_FILLED;
34162306a36Sopenharmony_ci		}
34262306a36Sopenharmony_ci	}
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_ci	return erp;
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci}				/* end dasd_3990_erp_action_4 */
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci/*
34962306a36Sopenharmony_ci *****************************************************************************
35062306a36Sopenharmony_ci * 24 byte sense ERP functions (only)
35162306a36Sopenharmony_ci *****************************************************************************
35262306a36Sopenharmony_ci */
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci/*
35562306a36Sopenharmony_ci * DASD_3990_ERP_ACTION_5
35662306a36Sopenharmony_ci *
35762306a36Sopenharmony_ci * DESCRIPTION
35862306a36Sopenharmony_ci *   Setup ERP to do the ERP action 5 (see Reference manual).
35962306a36Sopenharmony_ci *   NOTE: Further handling is done in xxx_further_erp after the retries.
36062306a36Sopenharmony_ci *
36162306a36Sopenharmony_ci *  PARAMETER
36262306a36Sopenharmony_ci *   erp		pointer to the current ERP
36362306a36Sopenharmony_ci *
36462306a36Sopenharmony_ci * RETURN VALUES
36562306a36Sopenharmony_ci *   erp		pointer to the ERP
36662306a36Sopenharmony_ci *
36762306a36Sopenharmony_ci */
36862306a36Sopenharmony_cistatic struct dasd_ccw_req *
36962306a36Sopenharmony_cidasd_3990_erp_action_5(struct dasd_ccw_req * erp)
37062306a36Sopenharmony_ci{
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci	/* first of all retry */
37362306a36Sopenharmony_ci	erp->retries = 10;
37462306a36Sopenharmony_ci	erp->function = dasd_3990_erp_action_5;
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci	return erp;
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci}				/* end dasd_3990_erp_action_5 */
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci/*
38162306a36Sopenharmony_ci * DASD_3990_HANDLE_ENV_DATA
38262306a36Sopenharmony_ci *
38362306a36Sopenharmony_ci * DESCRIPTION
38462306a36Sopenharmony_ci *   Handles 24 byte 'Environmental data present'.
38562306a36Sopenharmony_ci *   Does a analysis of the sense data (message Format)
38662306a36Sopenharmony_ci *   and prints the error messages.
38762306a36Sopenharmony_ci *
38862306a36Sopenharmony_ci * PARAMETER
38962306a36Sopenharmony_ci *   sense		current sense data
39062306a36Sopenharmony_ci *
39162306a36Sopenharmony_ci * RETURN VALUES
39262306a36Sopenharmony_ci *   void
39362306a36Sopenharmony_ci */
39462306a36Sopenharmony_cistatic void
39562306a36Sopenharmony_cidasd_3990_handle_env_data(struct dasd_ccw_req * erp, char *sense)
39662306a36Sopenharmony_ci{
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_ci	struct dasd_device *device = erp->startdev;
39962306a36Sopenharmony_ci	char msg_format = (sense[7] & 0xF0);
40062306a36Sopenharmony_ci	char msg_no = (sense[7] & 0x0F);
40162306a36Sopenharmony_ci	char errorstring[ERRORLENGTH];
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci	switch (msg_format) {
40462306a36Sopenharmony_ci	case 0x00:		/* Format 0 - Program or System Checks */
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_ci		if (sense[1] & 0x10) {	/* check message to operator bit */
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci			switch (msg_no) {
40962306a36Sopenharmony_ci			case 0x00:	/* No Message */
41062306a36Sopenharmony_ci				break;
41162306a36Sopenharmony_ci			case 0x01:
41262306a36Sopenharmony_ci				dev_warn(&device->cdev->dev,
41362306a36Sopenharmony_ci					    "FORMAT 0 - Invalid Command\n");
41462306a36Sopenharmony_ci				break;
41562306a36Sopenharmony_ci			case 0x02:
41662306a36Sopenharmony_ci				dev_warn(&device->cdev->dev,
41762306a36Sopenharmony_ci					    "FORMAT 0 - Invalid Command "
41862306a36Sopenharmony_ci					    "Sequence\n");
41962306a36Sopenharmony_ci				break;
42062306a36Sopenharmony_ci			case 0x03:
42162306a36Sopenharmony_ci				dev_warn(&device->cdev->dev,
42262306a36Sopenharmony_ci					    "FORMAT 0 - CCW Count less than "
42362306a36Sopenharmony_ci					    "required\n");
42462306a36Sopenharmony_ci				break;
42562306a36Sopenharmony_ci			case 0x04:
42662306a36Sopenharmony_ci				dev_warn(&device->cdev->dev,
42762306a36Sopenharmony_ci					    "FORMAT 0 - Invalid Parameter\n");
42862306a36Sopenharmony_ci				break;
42962306a36Sopenharmony_ci			case 0x05:
43062306a36Sopenharmony_ci				dev_warn(&device->cdev->dev,
43162306a36Sopenharmony_ci					    "FORMAT 0 - Diagnostic of Special"
43262306a36Sopenharmony_ci					    " Command Violates File Mask\n");
43362306a36Sopenharmony_ci				break;
43462306a36Sopenharmony_ci			case 0x07:
43562306a36Sopenharmony_ci				dev_warn(&device->cdev->dev,
43662306a36Sopenharmony_ci					    "FORMAT 0 - Channel Returned with "
43762306a36Sopenharmony_ci					    "Incorrect retry CCW\n");
43862306a36Sopenharmony_ci				break;
43962306a36Sopenharmony_ci			case 0x08:
44062306a36Sopenharmony_ci				dev_warn(&device->cdev->dev,
44162306a36Sopenharmony_ci					    "FORMAT 0 - Reset Notification\n");
44262306a36Sopenharmony_ci				break;
44362306a36Sopenharmony_ci			case 0x09:
44462306a36Sopenharmony_ci				dev_warn(&device->cdev->dev,
44562306a36Sopenharmony_ci					 "FORMAT 0 - Storage Path Restart\n");
44662306a36Sopenharmony_ci				break;
44762306a36Sopenharmony_ci			case 0x0A:
44862306a36Sopenharmony_ci				dev_warn(&device->cdev->dev,
44962306a36Sopenharmony_ci					    "FORMAT 0 - Channel requested "
45062306a36Sopenharmony_ci					    "... %02x\n", sense[8]);
45162306a36Sopenharmony_ci				break;
45262306a36Sopenharmony_ci			case 0x0B:
45362306a36Sopenharmony_ci				dev_warn(&device->cdev->dev,
45462306a36Sopenharmony_ci					    "FORMAT 0 - Invalid Defective/"
45562306a36Sopenharmony_ci					    "Alternate Track Pointer\n");
45662306a36Sopenharmony_ci				break;
45762306a36Sopenharmony_ci			case 0x0C:
45862306a36Sopenharmony_ci				dev_warn(&device->cdev->dev,
45962306a36Sopenharmony_ci					    "FORMAT 0 - DPS Installation "
46062306a36Sopenharmony_ci					    "Check\n");
46162306a36Sopenharmony_ci				break;
46262306a36Sopenharmony_ci			case 0x0E:
46362306a36Sopenharmony_ci				dev_warn(&device->cdev->dev,
46462306a36Sopenharmony_ci					    "FORMAT 0 - Command Invalid on "
46562306a36Sopenharmony_ci					    "Secondary Address\n");
46662306a36Sopenharmony_ci				break;
46762306a36Sopenharmony_ci			case 0x0F:
46862306a36Sopenharmony_ci				dev_warn(&device->cdev->dev,
46962306a36Sopenharmony_ci					    "FORMAT 0 - Status Not As "
47062306a36Sopenharmony_ci					    "Required: reason %02x\n",
47162306a36Sopenharmony_ci					 sense[8]);
47262306a36Sopenharmony_ci				break;
47362306a36Sopenharmony_ci			default:
47462306a36Sopenharmony_ci				dev_warn(&device->cdev->dev,
47562306a36Sopenharmony_ci					    "FORMAT 0 - Reserved\n");
47662306a36Sopenharmony_ci			}
47762306a36Sopenharmony_ci		} else {
47862306a36Sopenharmony_ci			switch (msg_no) {
47962306a36Sopenharmony_ci			case 0x00:	/* No Message */
48062306a36Sopenharmony_ci				break;
48162306a36Sopenharmony_ci			case 0x01:
48262306a36Sopenharmony_ci				dev_warn(&device->cdev->dev,
48362306a36Sopenharmony_ci					 "FORMAT 0 - Device Error "
48462306a36Sopenharmony_ci					 "Source\n");
48562306a36Sopenharmony_ci				break;
48662306a36Sopenharmony_ci			case 0x02:
48762306a36Sopenharmony_ci				dev_warn(&device->cdev->dev,
48862306a36Sopenharmony_ci					    "FORMAT 0 - Reserved\n");
48962306a36Sopenharmony_ci				break;
49062306a36Sopenharmony_ci			case 0x03:
49162306a36Sopenharmony_ci				dev_warn(&device->cdev->dev,
49262306a36Sopenharmony_ci					    "FORMAT 0 - Device Fenced - "
49362306a36Sopenharmony_ci					    "device = %02x\n", sense[4]);
49462306a36Sopenharmony_ci				break;
49562306a36Sopenharmony_ci			case 0x04:
49662306a36Sopenharmony_ci				dev_warn(&device->cdev->dev,
49762306a36Sopenharmony_ci					    "FORMAT 0 - Data Pinned for "
49862306a36Sopenharmony_ci					    "Device\n");
49962306a36Sopenharmony_ci				break;
50062306a36Sopenharmony_ci			default:
50162306a36Sopenharmony_ci				dev_warn(&device->cdev->dev,
50262306a36Sopenharmony_ci					    "FORMAT 0 - Reserved\n");
50362306a36Sopenharmony_ci			}
50462306a36Sopenharmony_ci		}
50562306a36Sopenharmony_ci		break;
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_ci	case 0x10:		/* Format 1 - Device Equipment Checks */
50862306a36Sopenharmony_ci		switch (msg_no) {
50962306a36Sopenharmony_ci		case 0x00:	/* No Message */
51062306a36Sopenharmony_ci			break;
51162306a36Sopenharmony_ci		case 0x01:
51262306a36Sopenharmony_ci			dev_warn(&device->cdev->dev,
51362306a36Sopenharmony_ci				    "FORMAT 1 - Device Status 1 not as "
51462306a36Sopenharmony_ci				    "expected\n");
51562306a36Sopenharmony_ci			break;
51662306a36Sopenharmony_ci		case 0x03:
51762306a36Sopenharmony_ci			dev_warn(&device->cdev->dev,
51862306a36Sopenharmony_ci				    "FORMAT 1 - Index missing\n");
51962306a36Sopenharmony_ci			break;
52062306a36Sopenharmony_ci		case 0x04:
52162306a36Sopenharmony_ci			dev_warn(&device->cdev->dev,
52262306a36Sopenharmony_ci				 "FORMAT 1 - Interruption cannot be "
52362306a36Sopenharmony_ci				 "reset\n");
52462306a36Sopenharmony_ci			break;
52562306a36Sopenharmony_ci		case 0x05:
52662306a36Sopenharmony_ci			dev_warn(&device->cdev->dev,
52762306a36Sopenharmony_ci				    "FORMAT 1 - Device did not respond to "
52862306a36Sopenharmony_ci				    "selection\n");
52962306a36Sopenharmony_ci			break;
53062306a36Sopenharmony_ci		case 0x06:
53162306a36Sopenharmony_ci			dev_warn(&device->cdev->dev,
53262306a36Sopenharmony_ci				    "FORMAT 1 - Device check-2 error or Set "
53362306a36Sopenharmony_ci				    "Sector is not complete\n");
53462306a36Sopenharmony_ci			break;
53562306a36Sopenharmony_ci		case 0x07:
53662306a36Sopenharmony_ci			dev_warn(&device->cdev->dev,
53762306a36Sopenharmony_ci				    "FORMAT 1 - Head address does not "
53862306a36Sopenharmony_ci				    "compare\n");
53962306a36Sopenharmony_ci			break;
54062306a36Sopenharmony_ci		case 0x08:
54162306a36Sopenharmony_ci			dev_warn(&device->cdev->dev,
54262306a36Sopenharmony_ci				    "FORMAT 1 - Device status 1 not valid\n");
54362306a36Sopenharmony_ci			break;
54462306a36Sopenharmony_ci		case 0x09:
54562306a36Sopenharmony_ci			dev_warn(&device->cdev->dev,
54662306a36Sopenharmony_ci				    "FORMAT 1 - Device not ready\n");
54762306a36Sopenharmony_ci			break;
54862306a36Sopenharmony_ci		case 0x0A:
54962306a36Sopenharmony_ci			dev_warn(&device->cdev->dev,
55062306a36Sopenharmony_ci				    "FORMAT 1 - Track physical address did "
55162306a36Sopenharmony_ci				    "not compare\n");
55262306a36Sopenharmony_ci			break;
55362306a36Sopenharmony_ci		case 0x0B:
55462306a36Sopenharmony_ci			dev_warn(&device->cdev->dev,
55562306a36Sopenharmony_ci				    "FORMAT 1 - Missing device address bit\n");
55662306a36Sopenharmony_ci			break;
55762306a36Sopenharmony_ci		case 0x0C:
55862306a36Sopenharmony_ci			dev_warn(&device->cdev->dev,
55962306a36Sopenharmony_ci				    "FORMAT 1 - Drive motor switch is off\n");
56062306a36Sopenharmony_ci			break;
56162306a36Sopenharmony_ci		case 0x0D:
56262306a36Sopenharmony_ci			dev_warn(&device->cdev->dev,
56362306a36Sopenharmony_ci				    "FORMAT 1 - Seek incomplete\n");
56462306a36Sopenharmony_ci			break;
56562306a36Sopenharmony_ci		case 0x0E:
56662306a36Sopenharmony_ci			dev_warn(&device->cdev->dev,
56762306a36Sopenharmony_ci				    "FORMAT 1 - Cylinder address did not "
56862306a36Sopenharmony_ci				    "compare\n");
56962306a36Sopenharmony_ci			break;
57062306a36Sopenharmony_ci		case 0x0F:
57162306a36Sopenharmony_ci			dev_warn(&device->cdev->dev,
57262306a36Sopenharmony_ci				    "FORMAT 1 - Offset active cannot be "
57362306a36Sopenharmony_ci				    "reset\n");
57462306a36Sopenharmony_ci			break;
57562306a36Sopenharmony_ci		default:
57662306a36Sopenharmony_ci			dev_warn(&device->cdev->dev,
57762306a36Sopenharmony_ci				    "FORMAT 1 - Reserved\n");
57862306a36Sopenharmony_ci		}
57962306a36Sopenharmony_ci		break;
58062306a36Sopenharmony_ci
58162306a36Sopenharmony_ci	case 0x20:		/* Format 2 - 3990 Equipment Checks */
58262306a36Sopenharmony_ci		switch (msg_no) {
58362306a36Sopenharmony_ci		case 0x08:
58462306a36Sopenharmony_ci			dev_warn(&device->cdev->dev,
58562306a36Sopenharmony_ci				    "FORMAT 2 - 3990 check-2 error\n");
58662306a36Sopenharmony_ci			break;
58762306a36Sopenharmony_ci		case 0x0E:
58862306a36Sopenharmony_ci			dev_warn(&device->cdev->dev,
58962306a36Sopenharmony_ci				    "FORMAT 2 - Support facility errors\n");
59062306a36Sopenharmony_ci			break;
59162306a36Sopenharmony_ci		case 0x0F:
59262306a36Sopenharmony_ci			dev_warn(&device->cdev->dev,
59362306a36Sopenharmony_ci				 "FORMAT 2 - Microcode detected error "
59462306a36Sopenharmony_ci				 "%02x\n",
59562306a36Sopenharmony_ci				 sense[8]);
59662306a36Sopenharmony_ci			break;
59762306a36Sopenharmony_ci		default:
59862306a36Sopenharmony_ci			dev_warn(&device->cdev->dev,
59962306a36Sopenharmony_ci				    "FORMAT 2 - Reserved\n");
60062306a36Sopenharmony_ci		}
60162306a36Sopenharmony_ci		break;
60262306a36Sopenharmony_ci
60362306a36Sopenharmony_ci	case 0x30:		/* Format 3 - 3990 Control Checks */
60462306a36Sopenharmony_ci		switch (msg_no) {
60562306a36Sopenharmony_ci		case 0x0F:
60662306a36Sopenharmony_ci			dev_warn(&device->cdev->dev,
60762306a36Sopenharmony_ci				    "FORMAT 3 - Allegiance terminated\n");
60862306a36Sopenharmony_ci			break;
60962306a36Sopenharmony_ci		default:
61062306a36Sopenharmony_ci			dev_warn(&device->cdev->dev,
61162306a36Sopenharmony_ci				    "FORMAT 3 - Reserved\n");
61262306a36Sopenharmony_ci		}
61362306a36Sopenharmony_ci		break;
61462306a36Sopenharmony_ci
61562306a36Sopenharmony_ci	case 0x40:		/* Format 4 - Data Checks */
61662306a36Sopenharmony_ci		switch (msg_no) {
61762306a36Sopenharmony_ci		case 0x00:
61862306a36Sopenharmony_ci			dev_warn(&device->cdev->dev,
61962306a36Sopenharmony_ci				    "FORMAT 4 - Home address area error\n");
62062306a36Sopenharmony_ci			break;
62162306a36Sopenharmony_ci		case 0x01:
62262306a36Sopenharmony_ci			dev_warn(&device->cdev->dev,
62362306a36Sopenharmony_ci				    "FORMAT 4 - Count area error\n");
62462306a36Sopenharmony_ci			break;
62562306a36Sopenharmony_ci		case 0x02:
62662306a36Sopenharmony_ci			dev_warn(&device->cdev->dev,
62762306a36Sopenharmony_ci				    "FORMAT 4 - Key area error\n");
62862306a36Sopenharmony_ci			break;
62962306a36Sopenharmony_ci		case 0x03:
63062306a36Sopenharmony_ci			dev_warn(&device->cdev->dev,
63162306a36Sopenharmony_ci				    "FORMAT 4 - Data area error\n");
63262306a36Sopenharmony_ci			break;
63362306a36Sopenharmony_ci		case 0x04:
63462306a36Sopenharmony_ci			dev_warn(&device->cdev->dev,
63562306a36Sopenharmony_ci				    "FORMAT 4 - No sync byte in home address "
63662306a36Sopenharmony_ci				    "area\n");
63762306a36Sopenharmony_ci			break;
63862306a36Sopenharmony_ci		case 0x05:
63962306a36Sopenharmony_ci			dev_warn(&device->cdev->dev,
64062306a36Sopenharmony_ci				    "FORMAT 4 - No sync byte in count address "
64162306a36Sopenharmony_ci				    "area\n");
64262306a36Sopenharmony_ci			break;
64362306a36Sopenharmony_ci		case 0x06:
64462306a36Sopenharmony_ci			dev_warn(&device->cdev->dev,
64562306a36Sopenharmony_ci				    "FORMAT 4 - No sync byte in key area\n");
64662306a36Sopenharmony_ci			break;
64762306a36Sopenharmony_ci		case 0x07:
64862306a36Sopenharmony_ci			dev_warn(&device->cdev->dev,
64962306a36Sopenharmony_ci				    "FORMAT 4 - No sync byte in data area\n");
65062306a36Sopenharmony_ci			break;
65162306a36Sopenharmony_ci		case 0x08:
65262306a36Sopenharmony_ci			dev_warn(&device->cdev->dev,
65362306a36Sopenharmony_ci				    "FORMAT 4 - Home address area error; "
65462306a36Sopenharmony_ci				    "offset active\n");
65562306a36Sopenharmony_ci			break;
65662306a36Sopenharmony_ci		case 0x09:
65762306a36Sopenharmony_ci			dev_warn(&device->cdev->dev,
65862306a36Sopenharmony_ci				    "FORMAT 4 - Count area error; offset "
65962306a36Sopenharmony_ci				    "active\n");
66062306a36Sopenharmony_ci			break;
66162306a36Sopenharmony_ci		case 0x0A:
66262306a36Sopenharmony_ci			dev_warn(&device->cdev->dev,
66362306a36Sopenharmony_ci				    "FORMAT 4 - Key area error; offset "
66462306a36Sopenharmony_ci				    "active\n");
66562306a36Sopenharmony_ci			break;
66662306a36Sopenharmony_ci		case 0x0B:
66762306a36Sopenharmony_ci			dev_warn(&device->cdev->dev,
66862306a36Sopenharmony_ci				    "FORMAT 4 - Data area error; "
66962306a36Sopenharmony_ci				    "offset active\n");
67062306a36Sopenharmony_ci			break;
67162306a36Sopenharmony_ci		case 0x0C:
67262306a36Sopenharmony_ci			dev_warn(&device->cdev->dev,
67362306a36Sopenharmony_ci				    "FORMAT 4 - No sync byte in home "
67462306a36Sopenharmony_ci				    "address area; offset active\n");
67562306a36Sopenharmony_ci			break;
67662306a36Sopenharmony_ci		case 0x0D:
67762306a36Sopenharmony_ci			dev_warn(&device->cdev->dev,
67862306a36Sopenharmony_ci				    "FORMAT 4 - No sync byte in count "
67962306a36Sopenharmony_ci				    "address area; offset active\n");
68062306a36Sopenharmony_ci			break;
68162306a36Sopenharmony_ci		case 0x0E:
68262306a36Sopenharmony_ci			dev_warn(&device->cdev->dev,
68362306a36Sopenharmony_ci				    "FORMAT 4 - No sync byte in key area; "
68462306a36Sopenharmony_ci				    "offset active\n");
68562306a36Sopenharmony_ci			break;
68662306a36Sopenharmony_ci		case 0x0F:
68762306a36Sopenharmony_ci			dev_warn(&device->cdev->dev,
68862306a36Sopenharmony_ci				    "FORMAT 4 - No sync byte in data area; "
68962306a36Sopenharmony_ci				    "offset active\n");
69062306a36Sopenharmony_ci			break;
69162306a36Sopenharmony_ci		default:
69262306a36Sopenharmony_ci			dev_warn(&device->cdev->dev,
69362306a36Sopenharmony_ci				    "FORMAT 4 - Reserved\n");
69462306a36Sopenharmony_ci		}
69562306a36Sopenharmony_ci		break;
69662306a36Sopenharmony_ci
69762306a36Sopenharmony_ci	case 0x50:  /* Format 5 - Data Check with displacement information */
69862306a36Sopenharmony_ci		switch (msg_no) {
69962306a36Sopenharmony_ci		case 0x00:
70062306a36Sopenharmony_ci			dev_warn(&device->cdev->dev,
70162306a36Sopenharmony_ci				    "FORMAT 5 - Data Check in the "
70262306a36Sopenharmony_ci				    "home address area\n");
70362306a36Sopenharmony_ci			break;
70462306a36Sopenharmony_ci		case 0x01:
70562306a36Sopenharmony_ci			dev_warn(&device->cdev->dev,
70662306a36Sopenharmony_ci				 "FORMAT 5 - Data Check in the count "
70762306a36Sopenharmony_ci				 "area\n");
70862306a36Sopenharmony_ci			break;
70962306a36Sopenharmony_ci		case 0x02:
71062306a36Sopenharmony_ci			dev_warn(&device->cdev->dev,
71162306a36Sopenharmony_ci				    "FORMAT 5 - Data Check in the key area\n");
71262306a36Sopenharmony_ci			break;
71362306a36Sopenharmony_ci		case 0x03:
71462306a36Sopenharmony_ci			dev_warn(&device->cdev->dev,
71562306a36Sopenharmony_ci				 "FORMAT 5 - Data Check in the data "
71662306a36Sopenharmony_ci				 "area\n");
71762306a36Sopenharmony_ci			break;
71862306a36Sopenharmony_ci		case 0x08:
71962306a36Sopenharmony_ci			dev_warn(&device->cdev->dev,
72062306a36Sopenharmony_ci				    "FORMAT 5 - Data Check in the "
72162306a36Sopenharmony_ci				    "home address area; offset active\n");
72262306a36Sopenharmony_ci			break;
72362306a36Sopenharmony_ci		case 0x09:
72462306a36Sopenharmony_ci			dev_warn(&device->cdev->dev,
72562306a36Sopenharmony_ci				    "FORMAT 5 - Data Check in the count area; "
72662306a36Sopenharmony_ci				    "offset active\n");
72762306a36Sopenharmony_ci			break;
72862306a36Sopenharmony_ci		case 0x0A:
72962306a36Sopenharmony_ci			dev_warn(&device->cdev->dev,
73062306a36Sopenharmony_ci				    "FORMAT 5 - Data Check in the key area; "
73162306a36Sopenharmony_ci				    "offset active\n");
73262306a36Sopenharmony_ci			break;
73362306a36Sopenharmony_ci		case 0x0B:
73462306a36Sopenharmony_ci			dev_warn(&device->cdev->dev,
73562306a36Sopenharmony_ci				    "FORMAT 5 - Data Check in the data area; "
73662306a36Sopenharmony_ci				    "offset active\n");
73762306a36Sopenharmony_ci			break;
73862306a36Sopenharmony_ci		default:
73962306a36Sopenharmony_ci			dev_warn(&device->cdev->dev,
74062306a36Sopenharmony_ci				    "FORMAT 5 - Reserved\n");
74162306a36Sopenharmony_ci		}
74262306a36Sopenharmony_ci		break;
74362306a36Sopenharmony_ci
74462306a36Sopenharmony_ci	case 0x60:  /* Format 6 - Usage Statistics/Overrun Errors */
74562306a36Sopenharmony_ci		switch (msg_no) {
74662306a36Sopenharmony_ci		case 0x00:
74762306a36Sopenharmony_ci			dev_warn(&device->cdev->dev,
74862306a36Sopenharmony_ci				    "FORMAT 6 - Overrun on channel A\n");
74962306a36Sopenharmony_ci			break;
75062306a36Sopenharmony_ci		case 0x01:
75162306a36Sopenharmony_ci			dev_warn(&device->cdev->dev,
75262306a36Sopenharmony_ci				    "FORMAT 6 - Overrun on channel B\n");
75362306a36Sopenharmony_ci			break;
75462306a36Sopenharmony_ci		case 0x02:
75562306a36Sopenharmony_ci			dev_warn(&device->cdev->dev,
75662306a36Sopenharmony_ci				    "FORMAT 6 - Overrun on channel C\n");
75762306a36Sopenharmony_ci			break;
75862306a36Sopenharmony_ci		case 0x03:
75962306a36Sopenharmony_ci			dev_warn(&device->cdev->dev,
76062306a36Sopenharmony_ci				    "FORMAT 6 - Overrun on channel D\n");
76162306a36Sopenharmony_ci			break;
76262306a36Sopenharmony_ci		case 0x04:
76362306a36Sopenharmony_ci			dev_warn(&device->cdev->dev,
76462306a36Sopenharmony_ci				    "FORMAT 6 - Overrun on channel E\n");
76562306a36Sopenharmony_ci			break;
76662306a36Sopenharmony_ci		case 0x05:
76762306a36Sopenharmony_ci			dev_warn(&device->cdev->dev,
76862306a36Sopenharmony_ci				    "FORMAT 6 - Overrun on channel F\n");
76962306a36Sopenharmony_ci			break;
77062306a36Sopenharmony_ci		case 0x06:
77162306a36Sopenharmony_ci			dev_warn(&device->cdev->dev,
77262306a36Sopenharmony_ci				    "FORMAT 6 - Overrun on channel G\n");
77362306a36Sopenharmony_ci			break;
77462306a36Sopenharmony_ci		case 0x07:
77562306a36Sopenharmony_ci			dev_warn(&device->cdev->dev,
77662306a36Sopenharmony_ci				    "FORMAT 6 - Overrun on channel H\n");
77762306a36Sopenharmony_ci			break;
77862306a36Sopenharmony_ci		default:
77962306a36Sopenharmony_ci			dev_warn(&device->cdev->dev,
78062306a36Sopenharmony_ci				    "FORMAT 6 - Reserved\n");
78162306a36Sopenharmony_ci		}
78262306a36Sopenharmony_ci		break;
78362306a36Sopenharmony_ci
78462306a36Sopenharmony_ci	case 0x70:  /* Format 7 - Device Connection Control Checks */
78562306a36Sopenharmony_ci		switch (msg_no) {
78662306a36Sopenharmony_ci		case 0x00:
78762306a36Sopenharmony_ci			dev_warn(&device->cdev->dev,
78862306a36Sopenharmony_ci				    "FORMAT 7 - RCC initiated by a connection "
78962306a36Sopenharmony_ci				    "check alert\n");
79062306a36Sopenharmony_ci			break;
79162306a36Sopenharmony_ci		case 0x01:
79262306a36Sopenharmony_ci			dev_warn(&device->cdev->dev,
79362306a36Sopenharmony_ci				    "FORMAT 7 - RCC 1 sequence not "
79462306a36Sopenharmony_ci				    "successful\n");
79562306a36Sopenharmony_ci			break;
79662306a36Sopenharmony_ci		case 0x02:
79762306a36Sopenharmony_ci			dev_warn(&device->cdev->dev,
79862306a36Sopenharmony_ci				    "FORMAT 7 - RCC 1 and RCC 2 sequences not "
79962306a36Sopenharmony_ci				    "successful\n");
80062306a36Sopenharmony_ci			break;
80162306a36Sopenharmony_ci		case 0x03:
80262306a36Sopenharmony_ci			dev_warn(&device->cdev->dev,
80362306a36Sopenharmony_ci				    "FORMAT 7 - Invalid tag-in during "
80462306a36Sopenharmony_ci				    "selection sequence\n");
80562306a36Sopenharmony_ci			break;
80662306a36Sopenharmony_ci		case 0x04:
80762306a36Sopenharmony_ci			dev_warn(&device->cdev->dev,
80862306a36Sopenharmony_ci				    "FORMAT 7 - extra RCC required\n");
80962306a36Sopenharmony_ci			break;
81062306a36Sopenharmony_ci		case 0x05:
81162306a36Sopenharmony_ci			dev_warn(&device->cdev->dev,
81262306a36Sopenharmony_ci				    "FORMAT 7 - Invalid DCC selection "
81362306a36Sopenharmony_ci				    "response or timeout\n");
81462306a36Sopenharmony_ci			break;
81562306a36Sopenharmony_ci		case 0x06:
81662306a36Sopenharmony_ci			dev_warn(&device->cdev->dev,
81762306a36Sopenharmony_ci				    "FORMAT 7 - Missing end operation; device "
81862306a36Sopenharmony_ci				    "transfer complete\n");
81962306a36Sopenharmony_ci			break;
82062306a36Sopenharmony_ci		case 0x07:
82162306a36Sopenharmony_ci			dev_warn(&device->cdev->dev,
82262306a36Sopenharmony_ci				    "FORMAT 7 - Missing end operation; device "
82362306a36Sopenharmony_ci				    "transfer incomplete\n");
82462306a36Sopenharmony_ci			break;
82562306a36Sopenharmony_ci		case 0x08:
82662306a36Sopenharmony_ci			dev_warn(&device->cdev->dev,
82762306a36Sopenharmony_ci				    "FORMAT 7 - Invalid tag-in for an "
82862306a36Sopenharmony_ci				    "immediate command sequence\n");
82962306a36Sopenharmony_ci			break;
83062306a36Sopenharmony_ci		case 0x09:
83162306a36Sopenharmony_ci			dev_warn(&device->cdev->dev,
83262306a36Sopenharmony_ci				    "FORMAT 7 - Invalid tag-in for an "
83362306a36Sopenharmony_ci				    "extended command sequence\n");
83462306a36Sopenharmony_ci			break;
83562306a36Sopenharmony_ci		case 0x0A:
83662306a36Sopenharmony_ci			dev_warn(&device->cdev->dev,
83762306a36Sopenharmony_ci				    "FORMAT 7 - 3990 microcode time out when "
83862306a36Sopenharmony_ci				    "stopping selection\n");
83962306a36Sopenharmony_ci			break;
84062306a36Sopenharmony_ci		case 0x0B:
84162306a36Sopenharmony_ci			dev_warn(&device->cdev->dev,
84262306a36Sopenharmony_ci				    "FORMAT 7 - No response to selection "
84362306a36Sopenharmony_ci				    "after a poll interruption\n");
84462306a36Sopenharmony_ci			break;
84562306a36Sopenharmony_ci		case 0x0C:
84662306a36Sopenharmony_ci			dev_warn(&device->cdev->dev,
84762306a36Sopenharmony_ci				    "FORMAT 7 - Permanent path error (DASD "
84862306a36Sopenharmony_ci				    "controller not available)\n");
84962306a36Sopenharmony_ci			break;
85062306a36Sopenharmony_ci		case 0x0D:
85162306a36Sopenharmony_ci			dev_warn(&device->cdev->dev,
85262306a36Sopenharmony_ci				    "FORMAT 7 - DASD controller not available"
85362306a36Sopenharmony_ci				    " on disconnected command chain\n");
85462306a36Sopenharmony_ci			break;
85562306a36Sopenharmony_ci		default:
85662306a36Sopenharmony_ci			dev_warn(&device->cdev->dev,
85762306a36Sopenharmony_ci				    "FORMAT 7 - Reserved\n");
85862306a36Sopenharmony_ci		}
85962306a36Sopenharmony_ci		break;
86062306a36Sopenharmony_ci
86162306a36Sopenharmony_ci	case 0x80:  /* Format 8 - Additional Device Equipment Checks */
86262306a36Sopenharmony_ci		switch (msg_no) {
86362306a36Sopenharmony_ci		case 0x00:	/* No Message */
86462306a36Sopenharmony_ci		case 0x01:
86562306a36Sopenharmony_ci			dev_warn(&device->cdev->dev,
86662306a36Sopenharmony_ci				    "FORMAT 8 - Error correction code "
86762306a36Sopenharmony_ci				    "hardware fault\n");
86862306a36Sopenharmony_ci			break;
86962306a36Sopenharmony_ci		case 0x03:
87062306a36Sopenharmony_ci			dev_warn(&device->cdev->dev,
87162306a36Sopenharmony_ci				    "FORMAT 8 - Unexpected end operation "
87262306a36Sopenharmony_ci				    "response code\n");
87362306a36Sopenharmony_ci			break;
87462306a36Sopenharmony_ci		case 0x04:
87562306a36Sopenharmony_ci			dev_warn(&device->cdev->dev,
87662306a36Sopenharmony_ci				    "FORMAT 8 - End operation with transfer "
87762306a36Sopenharmony_ci				    "count not zero\n");
87862306a36Sopenharmony_ci			break;
87962306a36Sopenharmony_ci		case 0x05:
88062306a36Sopenharmony_ci			dev_warn(&device->cdev->dev,
88162306a36Sopenharmony_ci				    "FORMAT 8 - End operation with transfer "
88262306a36Sopenharmony_ci				    "count zero\n");
88362306a36Sopenharmony_ci			break;
88462306a36Sopenharmony_ci		case 0x06:
88562306a36Sopenharmony_ci			dev_warn(&device->cdev->dev,
88662306a36Sopenharmony_ci				    "FORMAT 8 - DPS checks after a system "
88762306a36Sopenharmony_ci				    "reset or selective reset\n");
88862306a36Sopenharmony_ci			break;
88962306a36Sopenharmony_ci		case 0x07:
89062306a36Sopenharmony_ci			dev_warn(&device->cdev->dev,
89162306a36Sopenharmony_ci				    "FORMAT 8 - DPS cannot be filled\n");
89262306a36Sopenharmony_ci			break;
89362306a36Sopenharmony_ci		case 0x08:
89462306a36Sopenharmony_ci			dev_warn(&device->cdev->dev,
89562306a36Sopenharmony_ci				    "FORMAT 8 - Short busy time-out during "
89662306a36Sopenharmony_ci				    "device selection\n");
89762306a36Sopenharmony_ci			break;
89862306a36Sopenharmony_ci		case 0x09:
89962306a36Sopenharmony_ci			dev_warn(&device->cdev->dev,
90062306a36Sopenharmony_ci				    "FORMAT 8 - DASD controller failed to "
90162306a36Sopenharmony_ci				    "set or reset the long busy latch\n");
90262306a36Sopenharmony_ci			break;
90362306a36Sopenharmony_ci		case 0x0A:
90462306a36Sopenharmony_ci			dev_warn(&device->cdev->dev,
90562306a36Sopenharmony_ci				    "FORMAT 8 - No interruption from device "
90662306a36Sopenharmony_ci				    "during a command chain\n");
90762306a36Sopenharmony_ci			break;
90862306a36Sopenharmony_ci		default:
90962306a36Sopenharmony_ci			dev_warn(&device->cdev->dev,
91062306a36Sopenharmony_ci				    "FORMAT 8 - Reserved\n");
91162306a36Sopenharmony_ci		}
91262306a36Sopenharmony_ci		break;
91362306a36Sopenharmony_ci
91462306a36Sopenharmony_ci	case 0x90:  /* Format 9 - Device Read, Write, and Seek Checks */
91562306a36Sopenharmony_ci		switch (msg_no) {
91662306a36Sopenharmony_ci		case 0x00:
91762306a36Sopenharmony_ci			break;	/* No Message */
91862306a36Sopenharmony_ci		case 0x06:
91962306a36Sopenharmony_ci			dev_warn(&device->cdev->dev,
92062306a36Sopenharmony_ci				    "FORMAT 9 - Device check-2 error\n");
92162306a36Sopenharmony_ci			break;
92262306a36Sopenharmony_ci		case 0x07:
92362306a36Sopenharmony_ci			dev_warn(&device->cdev->dev,
92462306a36Sopenharmony_ci				 "FORMAT 9 - Head address did not "
92562306a36Sopenharmony_ci				 "compare\n");
92662306a36Sopenharmony_ci			break;
92762306a36Sopenharmony_ci		case 0x0A:
92862306a36Sopenharmony_ci			dev_warn(&device->cdev->dev,
92962306a36Sopenharmony_ci				    "FORMAT 9 - Track physical address did "
93062306a36Sopenharmony_ci				    "not compare while oriented\n");
93162306a36Sopenharmony_ci			break;
93262306a36Sopenharmony_ci		case 0x0E:
93362306a36Sopenharmony_ci			dev_warn(&device->cdev->dev,
93462306a36Sopenharmony_ci				    "FORMAT 9 - Cylinder address did not "
93562306a36Sopenharmony_ci				    "compare\n");
93662306a36Sopenharmony_ci			break;
93762306a36Sopenharmony_ci		default:
93862306a36Sopenharmony_ci			dev_warn(&device->cdev->dev,
93962306a36Sopenharmony_ci				    "FORMAT 9 - Reserved\n");
94062306a36Sopenharmony_ci		}
94162306a36Sopenharmony_ci		break;
94262306a36Sopenharmony_ci
94362306a36Sopenharmony_ci	case 0xF0:		/* Format F - Cache Storage Checks */
94462306a36Sopenharmony_ci		switch (msg_no) {
94562306a36Sopenharmony_ci		case 0x00:
94662306a36Sopenharmony_ci			dev_warn(&device->cdev->dev,
94762306a36Sopenharmony_ci				    "FORMAT F - Operation Terminated\n");
94862306a36Sopenharmony_ci			break;
94962306a36Sopenharmony_ci		case 0x01:
95062306a36Sopenharmony_ci			dev_warn(&device->cdev->dev,
95162306a36Sopenharmony_ci				    "FORMAT F - Subsystem Processing Error\n");
95262306a36Sopenharmony_ci			break;
95362306a36Sopenharmony_ci		case 0x02:
95462306a36Sopenharmony_ci			dev_warn(&device->cdev->dev,
95562306a36Sopenharmony_ci				    "FORMAT F - Cache or nonvolatile storage "
95662306a36Sopenharmony_ci				    "equipment failure\n");
95762306a36Sopenharmony_ci			break;
95862306a36Sopenharmony_ci		case 0x04:
95962306a36Sopenharmony_ci			dev_warn(&device->cdev->dev,
96062306a36Sopenharmony_ci				    "FORMAT F - Caching terminated\n");
96162306a36Sopenharmony_ci			break;
96262306a36Sopenharmony_ci		case 0x06:
96362306a36Sopenharmony_ci			dev_warn(&device->cdev->dev,
96462306a36Sopenharmony_ci				    "FORMAT F - Cache fast write access not "
96562306a36Sopenharmony_ci				    "authorized\n");
96662306a36Sopenharmony_ci			break;
96762306a36Sopenharmony_ci		case 0x07:
96862306a36Sopenharmony_ci			dev_warn(&device->cdev->dev,
96962306a36Sopenharmony_ci				    "FORMAT F - Track format incorrect\n");
97062306a36Sopenharmony_ci			break;
97162306a36Sopenharmony_ci		case 0x09:
97262306a36Sopenharmony_ci			dev_warn(&device->cdev->dev,
97362306a36Sopenharmony_ci				    "FORMAT F - Caching reinitiated\n");
97462306a36Sopenharmony_ci			break;
97562306a36Sopenharmony_ci		case 0x0A:
97662306a36Sopenharmony_ci			dev_warn(&device->cdev->dev,
97762306a36Sopenharmony_ci				    "FORMAT F - Nonvolatile storage "
97862306a36Sopenharmony_ci				    "terminated\n");
97962306a36Sopenharmony_ci			break;
98062306a36Sopenharmony_ci		case 0x0B:
98162306a36Sopenharmony_ci			dev_warn(&device->cdev->dev,
98262306a36Sopenharmony_ci				    "FORMAT F - Volume is suspended duplex\n");
98362306a36Sopenharmony_ci			/* call extended error reporting (EER) */
98462306a36Sopenharmony_ci			dasd_eer_write(device, erp->refers,
98562306a36Sopenharmony_ci				       DASD_EER_PPRCSUSPEND);
98662306a36Sopenharmony_ci			break;
98762306a36Sopenharmony_ci		case 0x0C:
98862306a36Sopenharmony_ci			dev_warn(&device->cdev->dev,
98962306a36Sopenharmony_ci				    "FORMAT F - Subsystem status cannot be "
99062306a36Sopenharmony_ci				    "determined\n");
99162306a36Sopenharmony_ci			break;
99262306a36Sopenharmony_ci		case 0x0D:
99362306a36Sopenharmony_ci			dev_warn(&device->cdev->dev,
99462306a36Sopenharmony_ci				    "FORMAT F - Caching status reset to "
99562306a36Sopenharmony_ci				    "default\n");
99662306a36Sopenharmony_ci			break;
99762306a36Sopenharmony_ci		case 0x0E:
99862306a36Sopenharmony_ci			dev_warn(&device->cdev->dev,
99962306a36Sopenharmony_ci				    "FORMAT F - DASD Fast Write inhibited\n");
100062306a36Sopenharmony_ci			break;
100162306a36Sopenharmony_ci		default:
100262306a36Sopenharmony_ci			dev_warn(&device->cdev->dev,
100362306a36Sopenharmony_ci				    "FORMAT F - Reserved\n");
100462306a36Sopenharmony_ci		}
100562306a36Sopenharmony_ci		break;
100662306a36Sopenharmony_ci
100762306a36Sopenharmony_ci	default:	/* unknown message format - should not happen
100862306a36Sopenharmony_ci			   internal error 03 - unknown message format */
100962306a36Sopenharmony_ci		snprintf(errorstring, ERRORLENGTH, "03 %x02", msg_format);
101062306a36Sopenharmony_ci		dev_err(&device->cdev->dev,
101162306a36Sopenharmony_ci			 "An error occurred in the DASD device driver, "
101262306a36Sopenharmony_ci			 "reason=%s\n", errorstring);
101362306a36Sopenharmony_ci		break;
101462306a36Sopenharmony_ci	}			/* end switch message format */
101562306a36Sopenharmony_ci
101662306a36Sopenharmony_ci}				/* end dasd_3990_handle_env_data */
101762306a36Sopenharmony_ci
101862306a36Sopenharmony_ci/*
101962306a36Sopenharmony_ci * DASD_3990_ERP_COM_REJ
102062306a36Sopenharmony_ci *
102162306a36Sopenharmony_ci * DESCRIPTION
102262306a36Sopenharmony_ci *   Handles 24 byte 'Command Reject' error.
102362306a36Sopenharmony_ci *
102462306a36Sopenharmony_ci * PARAMETER
102562306a36Sopenharmony_ci *   erp		current erp_head
102662306a36Sopenharmony_ci *   sense		current sense data
102762306a36Sopenharmony_ci *
102862306a36Sopenharmony_ci * RETURN VALUES
102962306a36Sopenharmony_ci *   erp		'new' erp_head - pointer to new ERP
103062306a36Sopenharmony_ci */
103162306a36Sopenharmony_cistatic struct dasd_ccw_req *
103262306a36Sopenharmony_cidasd_3990_erp_com_rej(struct dasd_ccw_req * erp, char *sense)
103362306a36Sopenharmony_ci{
103462306a36Sopenharmony_ci
103562306a36Sopenharmony_ci	struct dasd_device *device = erp->startdev;
103662306a36Sopenharmony_ci
103762306a36Sopenharmony_ci	erp->function = dasd_3990_erp_com_rej;
103862306a36Sopenharmony_ci
103962306a36Sopenharmony_ci	/* env data present (ACTION 10 - retry should work) */
104062306a36Sopenharmony_ci	if (sense[2] & SNS2_ENV_DATA_PRESENT) {
104162306a36Sopenharmony_ci
104262306a36Sopenharmony_ci		DBF_DEV_EVENT(DBF_WARNING, device, "%s",
104362306a36Sopenharmony_ci			    "Command Reject - environmental data present");
104462306a36Sopenharmony_ci
104562306a36Sopenharmony_ci		dasd_3990_handle_env_data(erp, sense);
104662306a36Sopenharmony_ci
104762306a36Sopenharmony_ci		erp->retries = 5;
104862306a36Sopenharmony_ci
104962306a36Sopenharmony_ci	} else if (sense[1] & SNS1_WRITE_INHIBITED) {
105062306a36Sopenharmony_ci		dev_err(&device->cdev->dev, "An I/O request was rejected"
105162306a36Sopenharmony_ci			" because writing is inhibited\n");
105262306a36Sopenharmony_ci		erp = dasd_3990_erp_cleanup(erp, DASD_CQR_FAILED);
105362306a36Sopenharmony_ci	} else if (sense[7] == SNS7_INVALID_ON_SEC) {
105462306a36Sopenharmony_ci		dev_err(&device->cdev->dev, "An I/O request was rejected on a copy pair secondary device\n");
105562306a36Sopenharmony_ci		/* suppress dump of sense data for this error */
105662306a36Sopenharmony_ci		set_bit(DASD_CQR_SUPPRESS_CR, &erp->refers->flags);
105762306a36Sopenharmony_ci		erp = dasd_3990_erp_cleanup(erp, DASD_CQR_FAILED);
105862306a36Sopenharmony_ci	} else {
105962306a36Sopenharmony_ci		/* fatal error -  set status to FAILED
106062306a36Sopenharmony_ci		   internal error 09 - Command Reject */
106162306a36Sopenharmony_ci		if (!test_bit(DASD_CQR_SUPPRESS_CR, &erp->flags))
106262306a36Sopenharmony_ci			dev_err(&device->cdev->dev,
106362306a36Sopenharmony_ci				"An error occurred in the DASD device driver, reason=09\n");
106462306a36Sopenharmony_ci
106562306a36Sopenharmony_ci		erp = dasd_3990_erp_cleanup(erp, DASD_CQR_FAILED);
106662306a36Sopenharmony_ci	}
106762306a36Sopenharmony_ci
106862306a36Sopenharmony_ci	return erp;
106962306a36Sopenharmony_ci
107062306a36Sopenharmony_ci}				/* end dasd_3990_erp_com_rej */
107162306a36Sopenharmony_ci
107262306a36Sopenharmony_ci/*
107362306a36Sopenharmony_ci * DASD_3990_ERP_BUS_OUT
107462306a36Sopenharmony_ci *
107562306a36Sopenharmony_ci * DESCRIPTION
107662306a36Sopenharmony_ci *   Handles 24 byte 'Bus Out Parity Check' error.
107762306a36Sopenharmony_ci *
107862306a36Sopenharmony_ci * PARAMETER
107962306a36Sopenharmony_ci *   erp		current erp_head
108062306a36Sopenharmony_ci * RETURN VALUES
108162306a36Sopenharmony_ci *   erp		new erp_head - pointer to new ERP
108262306a36Sopenharmony_ci */
108362306a36Sopenharmony_cistatic struct dasd_ccw_req *
108462306a36Sopenharmony_cidasd_3990_erp_bus_out(struct dasd_ccw_req * erp)
108562306a36Sopenharmony_ci{
108662306a36Sopenharmony_ci
108762306a36Sopenharmony_ci	struct dasd_device *device = erp->startdev;
108862306a36Sopenharmony_ci
108962306a36Sopenharmony_ci	/* first time set initial retry counter and erp_function */
109062306a36Sopenharmony_ci	/* and retry once without blocking queue		 */
109162306a36Sopenharmony_ci	/* (this enables easier enqueing of the cqr)		 */
109262306a36Sopenharmony_ci	if (erp->function != dasd_3990_erp_bus_out) {
109362306a36Sopenharmony_ci		erp->retries = 256;
109462306a36Sopenharmony_ci		erp->function = dasd_3990_erp_bus_out;
109562306a36Sopenharmony_ci
109662306a36Sopenharmony_ci	} else {
109762306a36Sopenharmony_ci
109862306a36Sopenharmony_ci		/* issue a message and wait for 'device ready' interrupt */
109962306a36Sopenharmony_ci		DBF_DEV_EVENT(DBF_WARNING, device, "%s",
110062306a36Sopenharmony_ci			    "bus out parity error or BOPC requested by "
110162306a36Sopenharmony_ci			    "channel");
110262306a36Sopenharmony_ci
110362306a36Sopenharmony_ci		dasd_3990_erp_block_queue(erp, 60*HZ);
110462306a36Sopenharmony_ci
110562306a36Sopenharmony_ci	}
110662306a36Sopenharmony_ci
110762306a36Sopenharmony_ci	return erp;
110862306a36Sopenharmony_ci
110962306a36Sopenharmony_ci}				/* end dasd_3990_erp_bus_out */
111062306a36Sopenharmony_ci
111162306a36Sopenharmony_ci/*
111262306a36Sopenharmony_ci * DASD_3990_ERP_EQUIP_CHECK
111362306a36Sopenharmony_ci *
111462306a36Sopenharmony_ci * DESCRIPTION
111562306a36Sopenharmony_ci *   Handles 24 byte 'Equipment Check' error.
111662306a36Sopenharmony_ci *
111762306a36Sopenharmony_ci * PARAMETER
111862306a36Sopenharmony_ci *   erp		current erp_head
111962306a36Sopenharmony_ci * RETURN VALUES
112062306a36Sopenharmony_ci *   erp		new erp_head - pointer to new ERP
112162306a36Sopenharmony_ci */
112262306a36Sopenharmony_cistatic struct dasd_ccw_req *
112362306a36Sopenharmony_cidasd_3990_erp_equip_check(struct dasd_ccw_req * erp, char *sense)
112462306a36Sopenharmony_ci{
112562306a36Sopenharmony_ci
112662306a36Sopenharmony_ci	struct dasd_device *device = erp->startdev;
112762306a36Sopenharmony_ci
112862306a36Sopenharmony_ci	erp->function = dasd_3990_erp_equip_check;
112962306a36Sopenharmony_ci
113062306a36Sopenharmony_ci	if (sense[1] & SNS1_WRITE_INHIBITED) {
113162306a36Sopenharmony_ci		dev_info(&device->cdev->dev,
113262306a36Sopenharmony_ci			    "Write inhibited path encountered\n");
113362306a36Sopenharmony_ci
113462306a36Sopenharmony_ci		/* vary path offline
113562306a36Sopenharmony_ci		   internal error 04 - Path should be varied off-line.*/
113662306a36Sopenharmony_ci		dev_err(&device->cdev->dev, "An error occurred in the DASD "
113762306a36Sopenharmony_ci			"device driver, reason=%s\n", "04");
113862306a36Sopenharmony_ci
113962306a36Sopenharmony_ci		erp = dasd_3990_erp_action_1(erp);
114062306a36Sopenharmony_ci
114162306a36Sopenharmony_ci	} else if (sense[2] & SNS2_ENV_DATA_PRESENT) {
114262306a36Sopenharmony_ci
114362306a36Sopenharmony_ci		DBF_DEV_EVENT(DBF_WARNING, device, "%s",
114462306a36Sopenharmony_ci			    "Equipment Check - " "environmental data present");
114562306a36Sopenharmony_ci
114662306a36Sopenharmony_ci		dasd_3990_handle_env_data(erp, sense);
114762306a36Sopenharmony_ci
114862306a36Sopenharmony_ci		erp = dasd_3990_erp_action_4(erp, sense);
114962306a36Sopenharmony_ci
115062306a36Sopenharmony_ci	} else if (sense[1] & SNS1_PERM_ERR) {
115162306a36Sopenharmony_ci
115262306a36Sopenharmony_ci		DBF_DEV_EVENT(DBF_WARNING, device, "%s",
115362306a36Sopenharmony_ci			    "Equipment Check - retry exhausted or "
115462306a36Sopenharmony_ci			    "undesirable");
115562306a36Sopenharmony_ci
115662306a36Sopenharmony_ci		erp = dasd_3990_erp_action_1(erp);
115762306a36Sopenharmony_ci
115862306a36Sopenharmony_ci	} else {
115962306a36Sopenharmony_ci		/* all other equipment checks - Action 5 */
116062306a36Sopenharmony_ci		/* rest is done when retries == 0 */
116162306a36Sopenharmony_ci		DBF_DEV_EVENT(DBF_WARNING, device, "%s",
116262306a36Sopenharmony_ci			    "Equipment check or processing error");
116362306a36Sopenharmony_ci
116462306a36Sopenharmony_ci		erp = dasd_3990_erp_action_5(erp);
116562306a36Sopenharmony_ci	}
116662306a36Sopenharmony_ci	return erp;
116762306a36Sopenharmony_ci
116862306a36Sopenharmony_ci}				/* end dasd_3990_erp_equip_check */
116962306a36Sopenharmony_ci
117062306a36Sopenharmony_ci/*
117162306a36Sopenharmony_ci * DASD_3990_ERP_DATA_CHECK
117262306a36Sopenharmony_ci *
117362306a36Sopenharmony_ci * DESCRIPTION
117462306a36Sopenharmony_ci *   Handles 24 byte 'Data Check' error.
117562306a36Sopenharmony_ci *
117662306a36Sopenharmony_ci * PARAMETER
117762306a36Sopenharmony_ci *   erp		current erp_head
117862306a36Sopenharmony_ci * RETURN VALUES
117962306a36Sopenharmony_ci *   erp		new erp_head - pointer to new ERP
118062306a36Sopenharmony_ci */
118162306a36Sopenharmony_cistatic struct dasd_ccw_req *
118262306a36Sopenharmony_cidasd_3990_erp_data_check(struct dasd_ccw_req * erp, char *sense)
118362306a36Sopenharmony_ci{
118462306a36Sopenharmony_ci
118562306a36Sopenharmony_ci	struct dasd_device *device = erp->startdev;
118662306a36Sopenharmony_ci
118762306a36Sopenharmony_ci	erp->function = dasd_3990_erp_data_check;
118862306a36Sopenharmony_ci
118962306a36Sopenharmony_ci	if (sense[2] & SNS2_CORRECTABLE) {	/* correctable data check */
119062306a36Sopenharmony_ci
119162306a36Sopenharmony_ci		/* issue message that the data has been corrected */
119262306a36Sopenharmony_ci		dev_emerg(&device->cdev->dev,
119362306a36Sopenharmony_ci			    "Data recovered during retry with PCI "
119462306a36Sopenharmony_ci			    "fetch mode active\n");
119562306a36Sopenharmony_ci
119662306a36Sopenharmony_ci		/* not possible to handle this situation in Linux */
119762306a36Sopenharmony_ci		panic("No way to inform application about the possibly "
119862306a36Sopenharmony_ci		      "incorrect data");
119962306a36Sopenharmony_ci
120062306a36Sopenharmony_ci	} else if (sense[2] & SNS2_ENV_DATA_PRESENT) {
120162306a36Sopenharmony_ci
120262306a36Sopenharmony_ci		DBF_DEV_EVENT(DBF_WARNING, device, "%s",
120362306a36Sopenharmony_ci			    "Uncorrectable data check recovered secondary "
120462306a36Sopenharmony_ci			    "addr of duplex pair");
120562306a36Sopenharmony_ci
120662306a36Sopenharmony_ci		erp = dasd_3990_erp_action_4(erp, sense);
120762306a36Sopenharmony_ci
120862306a36Sopenharmony_ci	} else if (sense[1] & SNS1_PERM_ERR) {
120962306a36Sopenharmony_ci
121062306a36Sopenharmony_ci		DBF_DEV_EVENT(DBF_WARNING, device, "%s",
121162306a36Sopenharmony_ci			    "Uncorrectable data check with internal "
121262306a36Sopenharmony_ci			    "retry exhausted");
121362306a36Sopenharmony_ci
121462306a36Sopenharmony_ci		erp = dasd_3990_erp_action_1(erp);
121562306a36Sopenharmony_ci
121662306a36Sopenharmony_ci	} else {
121762306a36Sopenharmony_ci		/* all other data checks */
121862306a36Sopenharmony_ci		DBF_DEV_EVENT(DBF_WARNING, device, "%s",
121962306a36Sopenharmony_ci			    "Uncorrectable data check with retry count "
122062306a36Sopenharmony_ci			    "exhausted...");
122162306a36Sopenharmony_ci
122262306a36Sopenharmony_ci		erp = dasd_3990_erp_action_5(erp);
122362306a36Sopenharmony_ci	}
122462306a36Sopenharmony_ci
122562306a36Sopenharmony_ci	return erp;
122662306a36Sopenharmony_ci
122762306a36Sopenharmony_ci}				/* end dasd_3990_erp_data_check */
122862306a36Sopenharmony_ci
122962306a36Sopenharmony_ci/*
123062306a36Sopenharmony_ci * DASD_3990_ERP_OVERRUN
123162306a36Sopenharmony_ci *
123262306a36Sopenharmony_ci * DESCRIPTION
123362306a36Sopenharmony_ci *   Handles 24 byte 'Overrun' error.
123462306a36Sopenharmony_ci *
123562306a36Sopenharmony_ci * PARAMETER
123662306a36Sopenharmony_ci *   erp		current erp_head
123762306a36Sopenharmony_ci * RETURN VALUES
123862306a36Sopenharmony_ci *   erp		new erp_head - pointer to new ERP
123962306a36Sopenharmony_ci */
124062306a36Sopenharmony_cistatic struct dasd_ccw_req *
124162306a36Sopenharmony_cidasd_3990_erp_overrun(struct dasd_ccw_req * erp, char *sense)
124262306a36Sopenharmony_ci{
124362306a36Sopenharmony_ci
124462306a36Sopenharmony_ci	struct dasd_device *device = erp->startdev;
124562306a36Sopenharmony_ci
124662306a36Sopenharmony_ci	erp->function = dasd_3990_erp_overrun;
124762306a36Sopenharmony_ci
124862306a36Sopenharmony_ci	DBF_DEV_EVENT(DBF_WARNING, device, "%s",
124962306a36Sopenharmony_ci		    "Overrun - service overrun or overrun"
125062306a36Sopenharmony_ci		    " error requested by channel");
125162306a36Sopenharmony_ci
125262306a36Sopenharmony_ci	erp = dasd_3990_erp_action_5(erp);
125362306a36Sopenharmony_ci
125462306a36Sopenharmony_ci	return erp;
125562306a36Sopenharmony_ci
125662306a36Sopenharmony_ci}				/* end dasd_3990_erp_overrun */
125762306a36Sopenharmony_ci
125862306a36Sopenharmony_ci/*
125962306a36Sopenharmony_ci * DASD_3990_ERP_INV_FORMAT
126062306a36Sopenharmony_ci *
126162306a36Sopenharmony_ci * DESCRIPTION
126262306a36Sopenharmony_ci *   Handles 24 byte 'Invalid Track Format' error.
126362306a36Sopenharmony_ci *
126462306a36Sopenharmony_ci * PARAMETER
126562306a36Sopenharmony_ci *   erp		current erp_head
126662306a36Sopenharmony_ci * RETURN VALUES
126762306a36Sopenharmony_ci *   erp		new erp_head - pointer to new ERP
126862306a36Sopenharmony_ci */
126962306a36Sopenharmony_cistatic struct dasd_ccw_req *
127062306a36Sopenharmony_cidasd_3990_erp_inv_format(struct dasd_ccw_req * erp, char *sense)
127162306a36Sopenharmony_ci{
127262306a36Sopenharmony_ci
127362306a36Sopenharmony_ci	struct dasd_device *device = erp->startdev;
127462306a36Sopenharmony_ci
127562306a36Sopenharmony_ci	erp->function = dasd_3990_erp_inv_format;
127662306a36Sopenharmony_ci
127762306a36Sopenharmony_ci	if (sense[2] & SNS2_ENV_DATA_PRESENT) {
127862306a36Sopenharmony_ci
127962306a36Sopenharmony_ci		DBF_DEV_EVENT(DBF_WARNING, device, "%s",
128062306a36Sopenharmony_ci			    "Track format error when destaging or "
128162306a36Sopenharmony_ci			    "staging data");
128262306a36Sopenharmony_ci
128362306a36Sopenharmony_ci		dasd_3990_handle_env_data(erp, sense);
128462306a36Sopenharmony_ci
128562306a36Sopenharmony_ci		erp = dasd_3990_erp_action_4(erp, sense);
128662306a36Sopenharmony_ci
128762306a36Sopenharmony_ci	} else {
128862306a36Sopenharmony_ci		/* internal error 06 - The track format is not valid*/
128962306a36Sopenharmony_ci		dev_err(&device->cdev->dev,
129062306a36Sopenharmony_ci			"An error occurred in the DASD device driver, "
129162306a36Sopenharmony_ci			"reason=%s\n", "06");
129262306a36Sopenharmony_ci
129362306a36Sopenharmony_ci		erp = dasd_3990_erp_cleanup(erp, DASD_CQR_FAILED);
129462306a36Sopenharmony_ci	}
129562306a36Sopenharmony_ci
129662306a36Sopenharmony_ci	return erp;
129762306a36Sopenharmony_ci
129862306a36Sopenharmony_ci}				/* end dasd_3990_erp_inv_format */
129962306a36Sopenharmony_ci
130062306a36Sopenharmony_ci/*
130162306a36Sopenharmony_ci * DASD_3990_ERP_EOC
130262306a36Sopenharmony_ci *
130362306a36Sopenharmony_ci * DESCRIPTION
130462306a36Sopenharmony_ci *   Handles 24 byte 'End-of-Cylinder' error.
130562306a36Sopenharmony_ci *
130662306a36Sopenharmony_ci * PARAMETER
130762306a36Sopenharmony_ci *   erp		already added default erp
130862306a36Sopenharmony_ci * RETURN VALUES
130962306a36Sopenharmony_ci *   erp		pointer to original (failed) cqr.
131062306a36Sopenharmony_ci */
131162306a36Sopenharmony_cistatic struct dasd_ccw_req *
131262306a36Sopenharmony_cidasd_3990_erp_EOC(struct dasd_ccw_req * default_erp, char *sense)
131362306a36Sopenharmony_ci{
131462306a36Sopenharmony_ci
131562306a36Sopenharmony_ci	struct dasd_device *device = default_erp->startdev;
131662306a36Sopenharmony_ci
131762306a36Sopenharmony_ci	dev_err(&device->cdev->dev,
131862306a36Sopenharmony_ci		"The cylinder data for accessing the DASD is inconsistent\n");
131962306a36Sopenharmony_ci
132062306a36Sopenharmony_ci	/* implement action 7 - BUG */
132162306a36Sopenharmony_ci	return dasd_3990_erp_cleanup(default_erp, DASD_CQR_FAILED);
132262306a36Sopenharmony_ci
132362306a36Sopenharmony_ci}				/* end dasd_3990_erp_EOC */
132462306a36Sopenharmony_ci
132562306a36Sopenharmony_ci/*
132662306a36Sopenharmony_ci * DASD_3990_ERP_ENV_DATA
132762306a36Sopenharmony_ci *
132862306a36Sopenharmony_ci * DESCRIPTION
132962306a36Sopenharmony_ci *   Handles 24 byte 'Environmental-Data Present' error.
133062306a36Sopenharmony_ci *
133162306a36Sopenharmony_ci * PARAMETER
133262306a36Sopenharmony_ci *   erp		current erp_head
133362306a36Sopenharmony_ci * RETURN VALUES
133462306a36Sopenharmony_ci *   erp		new erp_head - pointer to new ERP
133562306a36Sopenharmony_ci */
133662306a36Sopenharmony_cistatic struct dasd_ccw_req *
133762306a36Sopenharmony_cidasd_3990_erp_env_data(struct dasd_ccw_req * erp, char *sense)
133862306a36Sopenharmony_ci{
133962306a36Sopenharmony_ci
134062306a36Sopenharmony_ci	struct dasd_device *device = erp->startdev;
134162306a36Sopenharmony_ci
134262306a36Sopenharmony_ci	erp->function = dasd_3990_erp_env_data;
134362306a36Sopenharmony_ci
134462306a36Sopenharmony_ci	DBF_DEV_EVENT(DBF_WARNING, device, "%s", "Environmental data present");
134562306a36Sopenharmony_ci
134662306a36Sopenharmony_ci	dasd_3990_handle_env_data(erp, sense);
134762306a36Sopenharmony_ci
134862306a36Sopenharmony_ci	/* don't retry on disabled interface */
134962306a36Sopenharmony_ci	if (sense[7] != 0x0F) {
135062306a36Sopenharmony_ci		erp = dasd_3990_erp_action_4(erp, sense);
135162306a36Sopenharmony_ci	} else {
135262306a36Sopenharmony_ci		erp->status = DASD_CQR_FILLED;
135362306a36Sopenharmony_ci	}
135462306a36Sopenharmony_ci
135562306a36Sopenharmony_ci	return erp;
135662306a36Sopenharmony_ci
135762306a36Sopenharmony_ci}				/* end dasd_3990_erp_env_data */
135862306a36Sopenharmony_ci
135962306a36Sopenharmony_ci/*
136062306a36Sopenharmony_ci * DASD_3990_ERP_NO_REC
136162306a36Sopenharmony_ci *
136262306a36Sopenharmony_ci * DESCRIPTION
136362306a36Sopenharmony_ci *   Handles 24 byte 'No Record Found' error.
136462306a36Sopenharmony_ci *
136562306a36Sopenharmony_ci * PARAMETER
136662306a36Sopenharmony_ci *   erp		already added default ERP
136762306a36Sopenharmony_ci *
136862306a36Sopenharmony_ci * RETURN VALUES
136962306a36Sopenharmony_ci *   erp		new erp_head - pointer to new ERP
137062306a36Sopenharmony_ci */
137162306a36Sopenharmony_cistatic struct dasd_ccw_req *
137262306a36Sopenharmony_cidasd_3990_erp_no_rec(struct dasd_ccw_req * default_erp, char *sense)
137362306a36Sopenharmony_ci{
137462306a36Sopenharmony_ci
137562306a36Sopenharmony_ci	struct dasd_device *device = default_erp->startdev;
137662306a36Sopenharmony_ci
137762306a36Sopenharmony_ci	/*
137862306a36Sopenharmony_ci	 * In some cases the 'No Record Found' error might be expected and
137962306a36Sopenharmony_ci	 * log messages shouldn't be written then.
138062306a36Sopenharmony_ci	 * Check if the according suppress bit is set.
138162306a36Sopenharmony_ci	 */
138262306a36Sopenharmony_ci	if (!test_bit(DASD_CQR_SUPPRESS_NRF, &default_erp->flags))
138362306a36Sopenharmony_ci		dev_err(&device->cdev->dev,
138462306a36Sopenharmony_ci			"The specified record was not found\n");
138562306a36Sopenharmony_ci
138662306a36Sopenharmony_ci	return dasd_3990_erp_cleanup(default_erp, DASD_CQR_FAILED);
138762306a36Sopenharmony_ci
138862306a36Sopenharmony_ci}				/* end dasd_3990_erp_no_rec */
138962306a36Sopenharmony_ci
139062306a36Sopenharmony_ci/*
139162306a36Sopenharmony_ci * DASD_3990_ERP_FILE_PROT
139262306a36Sopenharmony_ci *
139362306a36Sopenharmony_ci * DESCRIPTION
139462306a36Sopenharmony_ci *   Handles 24 byte 'File Protected' error.
139562306a36Sopenharmony_ci *   Note: Seek related recovery is not implemented because
139662306a36Sopenharmony_ci *	   wee don't use the seek command yet.
139762306a36Sopenharmony_ci *
139862306a36Sopenharmony_ci * PARAMETER
139962306a36Sopenharmony_ci *   erp		current erp_head
140062306a36Sopenharmony_ci * RETURN VALUES
140162306a36Sopenharmony_ci *   erp		new erp_head - pointer to new ERP
140262306a36Sopenharmony_ci */
140362306a36Sopenharmony_cistatic struct dasd_ccw_req *
140462306a36Sopenharmony_cidasd_3990_erp_file_prot(struct dasd_ccw_req * erp)
140562306a36Sopenharmony_ci{
140662306a36Sopenharmony_ci
140762306a36Sopenharmony_ci	struct dasd_device *device = erp->startdev;
140862306a36Sopenharmony_ci
140962306a36Sopenharmony_ci	/*
141062306a36Sopenharmony_ci	 * In some cases the 'File Protected' error might be expected and
141162306a36Sopenharmony_ci	 * log messages shouldn't be written then.
141262306a36Sopenharmony_ci	 * Check if the according suppress bit is set.
141362306a36Sopenharmony_ci	 */
141462306a36Sopenharmony_ci	if (!test_bit(DASD_CQR_SUPPRESS_FP, &erp->flags))
141562306a36Sopenharmony_ci		dev_err(&device->cdev->dev,
141662306a36Sopenharmony_ci			"Accessing the DASD failed because of a hardware error\n");
141762306a36Sopenharmony_ci
141862306a36Sopenharmony_ci	return dasd_3990_erp_cleanup(erp, DASD_CQR_FAILED);
141962306a36Sopenharmony_ci
142062306a36Sopenharmony_ci}				/* end dasd_3990_erp_file_prot */
142162306a36Sopenharmony_ci
142262306a36Sopenharmony_ci/*
142362306a36Sopenharmony_ci * DASD_3990_ERP_INSPECT_ALIAS
142462306a36Sopenharmony_ci *
142562306a36Sopenharmony_ci * DESCRIPTION
142662306a36Sopenharmony_ci *   Checks if the original request was started on an alias device.
142762306a36Sopenharmony_ci *   If yes, it modifies the original and the erp request so that
142862306a36Sopenharmony_ci *   the erp request can be started on a base device.
142962306a36Sopenharmony_ci *
143062306a36Sopenharmony_ci * PARAMETER
143162306a36Sopenharmony_ci *   erp		pointer to the currently created default ERP
143262306a36Sopenharmony_ci *
143362306a36Sopenharmony_ci * RETURN VALUES
143462306a36Sopenharmony_ci *   erp		pointer to the modified ERP, or NULL
143562306a36Sopenharmony_ci */
143662306a36Sopenharmony_ci
143762306a36Sopenharmony_cistatic struct dasd_ccw_req *dasd_3990_erp_inspect_alias(
143862306a36Sopenharmony_ci						struct dasd_ccw_req *erp)
143962306a36Sopenharmony_ci{
144062306a36Sopenharmony_ci	struct dasd_ccw_req *cqr = erp->refers;
144162306a36Sopenharmony_ci	char *sense;
144262306a36Sopenharmony_ci
144362306a36Sopenharmony_ci	if (cqr->block &&
144462306a36Sopenharmony_ci	    (cqr->block->base != cqr->startdev)) {
144562306a36Sopenharmony_ci
144662306a36Sopenharmony_ci		sense = dasd_get_sense(&erp->refers->irb);
144762306a36Sopenharmony_ci		/*
144862306a36Sopenharmony_ci		 * dynamic pav may have changed base alias mapping
144962306a36Sopenharmony_ci		 */
145062306a36Sopenharmony_ci		if (!test_bit(DASD_FLAG_OFFLINE, &cqr->startdev->flags) && sense
145162306a36Sopenharmony_ci		    && (sense[0] == 0x10) && (sense[7] == 0x0F)
145262306a36Sopenharmony_ci		    && (sense[8] == 0x67)) {
145362306a36Sopenharmony_ci			/*
145462306a36Sopenharmony_ci			 * remove device from alias handling to prevent new
145562306a36Sopenharmony_ci			 * requests from being scheduled on the
145662306a36Sopenharmony_ci			 * wrong alias device
145762306a36Sopenharmony_ci			 */
145862306a36Sopenharmony_ci			dasd_alias_remove_device(cqr->startdev);
145962306a36Sopenharmony_ci
146062306a36Sopenharmony_ci			/* schedule worker to reload device */
146162306a36Sopenharmony_ci			dasd_reload_device(cqr->startdev);
146262306a36Sopenharmony_ci		}
146362306a36Sopenharmony_ci
146462306a36Sopenharmony_ci		if (cqr->startdev->features & DASD_FEATURE_ERPLOG) {
146562306a36Sopenharmony_ci			DBF_DEV_EVENT(DBF_ERR, cqr->startdev,
146662306a36Sopenharmony_ci				    "ERP on alias device for request %p,"
146762306a36Sopenharmony_ci				    " recover on base device %s", cqr,
146862306a36Sopenharmony_ci				    dev_name(&cqr->block->base->cdev->dev));
146962306a36Sopenharmony_ci		}
147062306a36Sopenharmony_ci		dasd_eckd_reset_ccw_to_base_io(cqr);
147162306a36Sopenharmony_ci		erp->startdev = cqr->block->base;
147262306a36Sopenharmony_ci		erp->function = dasd_3990_erp_inspect_alias;
147362306a36Sopenharmony_ci		return erp;
147462306a36Sopenharmony_ci	} else
147562306a36Sopenharmony_ci		return NULL;
147662306a36Sopenharmony_ci}
147762306a36Sopenharmony_ci
147862306a36Sopenharmony_ci
147962306a36Sopenharmony_ci/*
148062306a36Sopenharmony_ci * DASD_3990_ERP_INSPECT_24
148162306a36Sopenharmony_ci *
148262306a36Sopenharmony_ci * DESCRIPTION
148362306a36Sopenharmony_ci *   Does a detailed inspection of the 24 byte sense data
148462306a36Sopenharmony_ci *   and sets up a related error recovery action.
148562306a36Sopenharmony_ci *
148662306a36Sopenharmony_ci * PARAMETER
148762306a36Sopenharmony_ci *   sense		sense data of the actual error
148862306a36Sopenharmony_ci *   erp		pointer to the currently created default ERP
148962306a36Sopenharmony_ci *
149062306a36Sopenharmony_ci * RETURN VALUES
149162306a36Sopenharmony_ci *   erp		pointer to the (addtitional) ERP
149262306a36Sopenharmony_ci */
149362306a36Sopenharmony_cistatic struct dasd_ccw_req *
149462306a36Sopenharmony_cidasd_3990_erp_inspect_24(struct dasd_ccw_req * erp, char *sense)
149562306a36Sopenharmony_ci{
149662306a36Sopenharmony_ci
149762306a36Sopenharmony_ci	struct dasd_ccw_req *erp_filled = NULL;
149862306a36Sopenharmony_ci
149962306a36Sopenharmony_ci	/* Check sense for ....	   */
150062306a36Sopenharmony_ci	/* 'Command Reject'	   */
150162306a36Sopenharmony_ci	if ((erp_filled == NULL) && (sense[0] & SNS0_CMD_REJECT)) {
150262306a36Sopenharmony_ci		erp_filled = dasd_3990_erp_com_rej(erp, sense);
150362306a36Sopenharmony_ci	}
150462306a36Sopenharmony_ci	/* 'Intervention Required' */
150562306a36Sopenharmony_ci	if ((erp_filled == NULL) && (sense[0] & SNS0_INTERVENTION_REQ)) {
150662306a36Sopenharmony_ci		erp_filled = dasd_3990_erp_int_req(erp);
150762306a36Sopenharmony_ci	}
150862306a36Sopenharmony_ci	/* 'Bus Out Parity Check'  */
150962306a36Sopenharmony_ci	if ((erp_filled == NULL) && (sense[0] & SNS0_BUS_OUT_CHECK)) {
151062306a36Sopenharmony_ci		erp_filled = dasd_3990_erp_bus_out(erp);
151162306a36Sopenharmony_ci	}
151262306a36Sopenharmony_ci	/* 'Equipment Check'	   */
151362306a36Sopenharmony_ci	if ((erp_filled == NULL) && (sense[0] & SNS0_EQUIPMENT_CHECK)) {
151462306a36Sopenharmony_ci		erp_filled = dasd_3990_erp_equip_check(erp, sense);
151562306a36Sopenharmony_ci	}
151662306a36Sopenharmony_ci	/* 'Data Check'		   */
151762306a36Sopenharmony_ci	if ((erp_filled == NULL) && (sense[0] & SNS0_DATA_CHECK)) {
151862306a36Sopenharmony_ci		erp_filled = dasd_3990_erp_data_check(erp, sense);
151962306a36Sopenharmony_ci	}
152062306a36Sopenharmony_ci	/* 'Overrun'		   */
152162306a36Sopenharmony_ci	if ((erp_filled == NULL) && (sense[0] & SNS0_OVERRUN)) {
152262306a36Sopenharmony_ci		erp_filled = dasd_3990_erp_overrun(erp, sense);
152362306a36Sopenharmony_ci	}
152462306a36Sopenharmony_ci	/* 'Invalid Track Format'  */
152562306a36Sopenharmony_ci	if ((erp_filled == NULL) && (sense[1] & SNS1_INV_TRACK_FORMAT)) {
152662306a36Sopenharmony_ci		erp_filled = dasd_3990_erp_inv_format(erp, sense);
152762306a36Sopenharmony_ci	}
152862306a36Sopenharmony_ci	/* 'End-of-Cylinder'	   */
152962306a36Sopenharmony_ci	if ((erp_filled == NULL) && (sense[1] & SNS1_EOC)) {
153062306a36Sopenharmony_ci		erp_filled = dasd_3990_erp_EOC(erp, sense);
153162306a36Sopenharmony_ci	}
153262306a36Sopenharmony_ci	/* 'Environmental Data'	   */
153362306a36Sopenharmony_ci	if ((erp_filled == NULL) && (sense[2] & SNS2_ENV_DATA_PRESENT)) {
153462306a36Sopenharmony_ci		erp_filled = dasd_3990_erp_env_data(erp, sense);
153562306a36Sopenharmony_ci	}
153662306a36Sopenharmony_ci	/* 'No Record Found'	   */
153762306a36Sopenharmony_ci	if ((erp_filled == NULL) && (sense[1] & SNS1_NO_REC_FOUND)) {
153862306a36Sopenharmony_ci		erp_filled = dasd_3990_erp_no_rec(erp, sense);
153962306a36Sopenharmony_ci	}
154062306a36Sopenharmony_ci	/* 'File Protected'	   */
154162306a36Sopenharmony_ci	if ((erp_filled == NULL) && (sense[1] & SNS1_FILE_PROTECTED)) {
154262306a36Sopenharmony_ci		erp_filled = dasd_3990_erp_file_prot(erp);
154362306a36Sopenharmony_ci	}
154462306a36Sopenharmony_ci	/* other (unknown) error - do default ERP */
154562306a36Sopenharmony_ci	if (erp_filled == NULL) {
154662306a36Sopenharmony_ci
154762306a36Sopenharmony_ci		erp_filled = erp;
154862306a36Sopenharmony_ci	}
154962306a36Sopenharmony_ci
155062306a36Sopenharmony_ci	return erp_filled;
155162306a36Sopenharmony_ci
155262306a36Sopenharmony_ci}				/* END dasd_3990_erp_inspect_24 */
155362306a36Sopenharmony_ci
155462306a36Sopenharmony_ci/*
155562306a36Sopenharmony_ci *****************************************************************************
155662306a36Sopenharmony_ci * 32 byte sense ERP functions (only)
155762306a36Sopenharmony_ci *****************************************************************************
155862306a36Sopenharmony_ci */
155962306a36Sopenharmony_ci
156062306a36Sopenharmony_ci/*
156162306a36Sopenharmony_ci * DASD_3990_ERPACTION_10_32
156262306a36Sopenharmony_ci *
156362306a36Sopenharmony_ci * DESCRIPTION
156462306a36Sopenharmony_ci *   Handles 32 byte 'Action 10' of Single Program Action Codes.
156562306a36Sopenharmony_ci *   Just retry and if retry doesn't work, return with error.
156662306a36Sopenharmony_ci *
156762306a36Sopenharmony_ci * PARAMETER
156862306a36Sopenharmony_ci *   erp		current erp_head
156962306a36Sopenharmony_ci *   sense		current sense data
157062306a36Sopenharmony_ci * RETURN VALUES
157162306a36Sopenharmony_ci *   erp		modified erp_head
157262306a36Sopenharmony_ci */
157362306a36Sopenharmony_cistatic struct dasd_ccw_req *
157462306a36Sopenharmony_cidasd_3990_erp_action_10_32(struct dasd_ccw_req * erp, char *sense)
157562306a36Sopenharmony_ci{
157662306a36Sopenharmony_ci
157762306a36Sopenharmony_ci	struct dasd_device *device = erp->startdev;
157862306a36Sopenharmony_ci
157962306a36Sopenharmony_ci	erp->retries = 256;
158062306a36Sopenharmony_ci	erp->function = dasd_3990_erp_action_10_32;
158162306a36Sopenharmony_ci
158262306a36Sopenharmony_ci	DBF_DEV_EVENT(DBF_WARNING, device, "%s", "Perform logging requested");
158362306a36Sopenharmony_ci
158462306a36Sopenharmony_ci	return erp;
158562306a36Sopenharmony_ci
158662306a36Sopenharmony_ci}				/* end dasd_3990_erp_action_10_32 */
158762306a36Sopenharmony_ci
158862306a36Sopenharmony_ci/*
158962306a36Sopenharmony_ci * DASD_3990_ERP_ACTION_1B_32
159062306a36Sopenharmony_ci *
159162306a36Sopenharmony_ci * DESCRIPTION
159262306a36Sopenharmony_ci *   Handles 32 byte 'Action 1B' of Single Program Action Codes.
159362306a36Sopenharmony_ci *   A write operation could not be finished because of an unexpected
159462306a36Sopenharmony_ci *   condition.
159562306a36Sopenharmony_ci *   The already created 'default erp' is used to get the link to
159662306a36Sopenharmony_ci *   the erp chain, but it can not be used for this recovery
159762306a36Sopenharmony_ci *   action because it contains no DE/LO data space.
159862306a36Sopenharmony_ci *
159962306a36Sopenharmony_ci * PARAMETER
160062306a36Sopenharmony_ci *   default_erp	already added default erp.
160162306a36Sopenharmony_ci *   sense		current sense data
160262306a36Sopenharmony_ci *
160362306a36Sopenharmony_ci * RETURN VALUES
160462306a36Sopenharmony_ci *   erp		new erp or
160562306a36Sopenharmony_ci *			default_erp in case of imprecise ending or error
160662306a36Sopenharmony_ci */
160762306a36Sopenharmony_cistatic struct dasd_ccw_req *
160862306a36Sopenharmony_cidasd_3990_erp_action_1B_32(struct dasd_ccw_req * default_erp, char *sense)
160962306a36Sopenharmony_ci{
161062306a36Sopenharmony_ci
161162306a36Sopenharmony_ci	struct dasd_device *device = default_erp->startdev;
161262306a36Sopenharmony_ci	__u32 cpa = 0;
161362306a36Sopenharmony_ci	struct dasd_ccw_req *cqr;
161462306a36Sopenharmony_ci	struct dasd_ccw_req *erp;
161562306a36Sopenharmony_ci	struct DE_eckd_data *DE_data;
161662306a36Sopenharmony_ci	struct PFX_eckd_data *PFX_data;
161762306a36Sopenharmony_ci	char *LO_data;		/* LO_eckd_data_t */
161862306a36Sopenharmony_ci	struct ccw1 *ccw, *oldccw;
161962306a36Sopenharmony_ci
162062306a36Sopenharmony_ci	DBF_DEV_EVENT(DBF_WARNING, device, "%s",
162162306a36Sopenharmony_ci		    "Write not finished because of unexpected condition");
162262306a36Sopenharmony_ci
162362306a36Sopenharmony_ci	default_erp->function = dasd_3990_erp_action_1B_32;
162462306a36Sopenharmony_ci
162562306a36Sopenharmony_ci	/* determine the original cqr */
162662306a36Sopenharmony_ci	cqr = default_erp;
162762306a36Sopenharmony_ci
162862306a36Sopenharmony_ci	while (cqr->refers != NULL) {
162962306a36Sopenharmony_ci		cqr = cqr->refers;
163062306a36Sopenharmony_ci	}
163162306a36Sopenharmony_ci
163262306a36Sopenharmony_ci	if (scsw_is_tm(&cqr->irb.scsw)) {
163362306a36Sopenharmony_ci		DBF_DEV_EVENT(DBF_WARNING, device, "%s",
163462306a36Sopenharmony_ci			      "32 bit sense, action 1B is not defined"
163562306a36Sopenharmony_ci			      " in transport mode - just retry");
163662306a36Sopenharmony_ci		return default_erp;
163762306a36Sopenharmony_ci	}
163862306a36Sopenharmony_ci
163962306a36Sopenharmony_ci	/* for imprecise ending just do default erp */
164062306a36Sopenharmony_ci	if (sense[1] & 0x01) {
164162306a36Sopenharmony_ci		DBF_DEV_EVENT(DBF_WARNING, device, "%s",
164262306a36Sopenharmony_ci			    "Imprecise ending is set - just retry");
164362306a36Sopenharmony_ci
164462306a36Sopenharmony_ci		return default_erp;
164562306a36Sopenharmony_ci	}
164662306a36Sopenharmony_ci
164762306a36Sopenharmony_ci	/* determine the address of the CCW to be restarted */
164862306a36Sopenharmony_ci	/* Imprecise ending is not set -> addr from IRB-SCSW */
164962306a36Sopenharmony_ci	cpa = default_erp->refers->irb.scsw.cmd.cpa;
165062306a36Sopenharmony_ci
165162306a36Sopenharmony_ci	if (cpa == 0) {
165262306a36Sopenharmony_ci		DBF_DEV_EVENT(DBF_WARNING, device, "%s",
165362306a36Sopenharmony_ci			    "Unable to determine address of the CCW "
165462306a36Sopenharmony_ci			    "to be restarted");
165562306a36Sopenharmony_ci
165662306a36Sopenharmony_ci		return dasd_3990_erp_cleanup(default_erp, DASD_CQR_FAILED);
165762306a36Sopenharmony_ci	}
165862306a36Sopenharmony_ci
165962306a36Sopenharmony_ci	/* Build new ERP request including DE/LO */
166062306a36Sopenharmony_ci	erp = dasd_alloc_erp_request(cqr->magic,
166162306a36Sopenharmony_ci				     2 + 1,/* DE/LO + TIC */
166262306a36Sopenharmony_ci				     sizeof(struct DE_eckd_data) +
166362306a36Sopenharmony_ci				     sizeof(struct LO_eckd_data), device);
166462306a36Sopenharmony_ci
166562306a36Sopenharmony_ci	if (IS_ERR(erp)) {
166662306a36Sopenharmony_ci		/* internal error 01 - Unable to allocate ERP */
166762306a36Sopenharmony_ci		dev_err(&device->cdev->dev, "An error occurred in the DASD "
166862306a36Sopenharmony_ci			"device driver, reason=%s\n", "01");
166962306a36Sopenharmony_ci		return dasd_3990_erp_cleanup(default_erp, DASD_CQR_FAILED);
167062306a36Sopenharmony_ci	}
167162306a36Sopenharmony_ci
167262306a36Sopenharmony_ci	/* use original DE */
167362306a36Sopenharmony_ci	DE_data = erp->data;
167462306a36Sopenharmony_ci	oldccw = cqr->cpaddr;
167562306a36Sopenharmony_ci	if (oldccw->cmd_code == DASD_ECKD_CCW_PFX) {
167662306a36Sopenharmony_ci		PFX_data = cqr->data;
167762306a36Sopenharmony_ci		memcpy(DE_data, &PFX_data->define_extent,
167862306a36Sopenharmony_ci		       sizeof(struct DE_eckd_data));
167962306a36Sopenharmony_ci	} else
168062306a36Sopenharmony_ci		memcpy(DE_data, cqr->data, sizeof(struct DE_eckd_data));
168162306a36Sopenharmony_ci
168262306a36Sopenharmony_ci	/* create LO */
168362306a36Sopenharmony_ci	LO_data = erp->data + sizeof(struct DE_eckd_data);
168462306a36Sopenharmony_ci
168562306a36Sopenharmony_ci	if ((sense[3] == 0x01) && (LO_data[1] & 0x01)) {
168662306a36Sopenharmony_ci		/* should not */
168762306a36Sopenharmony_ci		return dasd_3990_erp_cleanup(default_erp, DASD_CQR_FAILED);
168862306a36Sopenharmony_ci	}
168962306a36Sopenharmony_ci
169062306a36Sopenharmony_ci	if ((sense[7] & 0x3F) == 0x01) {
169162306a36Sopenharmony_ci		/* operation code is WRITE DATA -> data area orientation */
169262306a36Sopenharmony_ci		LO_data[0] = 0x81;
169362306a36Sopenharmony_ci
169462306a36Sopenharmony_ci	} else if ((sense[7] & 0x3F) == 0x03) {
169562306a36Sopenharmony_ci		/* operation code is FORMAT WRITE -> index orientation */
169662306a36Sopenharmony_ci		LO_data[0] = 0xC3;
169762306a36Sopenharmony_ci
169862306a36Sopenharmony_ci	} else {
169962306a36Sopenharmony_ci		LO_data[0] = sense[7];	/* operation */
170062306a36Sopenharmony_ci	}
170162306a36Sopenharmony_ci
170262306a36Sopenharmony_ci	LO_data[1] = sense[8];	/* auxiliary */
170362306a36Sopenharmony_ci	LO_data[2] = sense[9];
170462306a36Sopenharmony_ci	LO_data[3] = sense[3];	/* count */
170562306a36Sopenharmony_ci	LO_data[4] = sense[29];	/* seek_addr.cyl */
170662306a36Sopenharmony_ci	LO_data[5] = sense[30];	/* seek_addr.cyl 2nd byte */
170762306a36Sopenharmony_ci	LO_data[7] = sense[31];	/* seek_addr.head 2nd byte */
170862306a36Sopenharmony_ci
170962306a36Sopenharmony_ci	memcpy(&(LO_data[8]), &(sense[11]), 8);
171062306a36Sopenharmony_ci
171162306a36Sopenharmony_ci	/* create DE ccw */
171262306a36Sopenharmony_ci	ccw = erp->cpaddr;
171362306a36Sopenharmony_ci	memset(ccw, 0, sizeof(struct ccw1));
171462306a36Sopenharmony_ci	ccw->cmd_code = DASD_ECKD_CCW_DEFINE_EXTENT;
171562306a36Sopenharmony_ci	ccw->flags = CCW_FLAG_CC;
171662306a36Sopenharmony_ci	ccw->count = 16;
171762306a36Sopenharmony_ci	ccw->cda = (__u32)virt_to_phys(DE_data);
171862306a36Sopenharmony_ci
171962306a36Sopenharmony_ci	/* create LO ccw */
172062306a36Sopenharmony_ci	ccw++;
172162306a36Sopenharmony_ci	memset(ccw, 0, sizeof(struct ccw1));
172262306a36Sopenharmony_ci	ccw->cmd_code = DASD_ECKD_CCW_LOCATE_RECORD;
172362306a36Sopenharmony_ci	ccw->flags = CCW_FLAG_CC;
172462306a36Sopenharmony_ci	ccw->count = 16;
172562306a36Sopenharmony_ci	ccw->cda = (__u32)virt_to_phys(LO_data);
172662306a36Sopenharmony_ci
172762306a36Sopenharmony_ci	/* TIC to the failed ccw */
172862306a36Sopenharmony_ci	ccw++;
172962306a36Sopenharmony_ci	ccw->cmd_code = CCW_CMD_TIC;
173062306a36Sopenharmony_ci	ccw->cda = cpa;
173162306a36Sopenharmony_ci
173262306a36Sopenharmony_ci	/* fill erp related fields */
173362306a36Sopenharmony_ci	erp->flags = default_erp->flags;
173462306a36Sopenharmony_ci	erp->function = dasd_3990_erp_action_1B_32;
173562306a36Sopenharmony_ci	erp->refers = default_erp->refers;
173662306a36Sopenharmony_ci	erp->startdev = device;
173762306a36Sopenharmony_ci	erp->memdev = device;
173862306a36Sopenharmony_ci	erp->magic = default_erp->magic;
173962306a36Sopenharmony_ci	erp->expires = default_erp->expires;
174062306a36Sopenharmony_ci	erp->retries = 256;
174162306a36Sopenharmony_ci	erp->buildclk = get_tod_clock();
174262306a36Sopenharmony_ci	erp->status = DASD_CQR_FILLED;
174362306a36Sopenharmony_ci
174462306a36Sopenharmony_ci	/* remove the default erp */
174562306a36Sopenharmony_ci	dasd_free_erp_request(default_erp, device);
174662306a36Sopenharmony_ci
174762306a36Sopenharmony_ci	return erp;
174862306a36Sopenharmony_ci
174962306a36Sopenharmony_ci}				/* end dasd_3990_erp_action_1B_32 */
175062306a36Sopenharmony_ci
175162306a36Sopenharmony_ci/*
175262306a36Sopenharmony_ci * DASD_3990_UPDATE_1B
175362306a36Sopenharmony_ci *
175462306a36Sopenharmony_ci * DESCRIPTION
175562306a36Sopenharmony_ci *   Handles the update to the 32 byte 'Action 1B' of Single Program
175662306a36Sopenharmony_ci *   Action Codes in case the first action was not successful.
175762306a36Sopenharmony_ci *   The already created 'previous_erp' is the currently not successful
175862306a36Sopenharmony_ci *   ERP.
175962306a36Sopenharmony_ci *
176062306a36Sopenharmony_ci * PARAMETER
176162306a36Sopenharmony_ci *   previous_erp	already created previous erp.
176262306a36Sopenharmony_ci *   sense		current sense data
176362306a36Sopenharmony_ci * RETURN VALUES
176462306a36Sopenharmony_ci *   erp		modified erp
176562306a36Sopenharmony_ci */
176662306a36Sopenharmony_cistatic struct dasd_ccw_req *
176762306a36Sopenharmony_cidasd_3990_update_1B(struct dasd_ccw_req * previous_erp, char *sense)
176862306a36Sopenharmony_ci{
176962306a36Sopenharmony_ci
177062306a36Sopenharmony_ci	struct dasd_device *device = previous_erp->startdev;
177162306a36Sopenharmony_ci	__u32 cpa = 0;
177262306a36Sopenharmony_ci	struct dasd_ccw_req *cqr;
177362306a36Sopenharmony_ci	struct dasd_ccw_req *erp;
177462306a36Sopenharmony_ci	char *LO_data;		/* struct LO_eckd_data */
177562306a36Sopenharmony_ci	struct ccw1 *ccw;
177662306a36Sopenharmony_ci
177762306a36Sopenharmony_ci	DBF_DEV_EVENT(DBF_WARNING, device, "%s",
177862306a36Sopenharmony_ci		    "Write not finished because of unexpected condition"
177962306a36Sopenharmony_ci		    " - follow on");
178062306a36Sopenharmony_ci
178162306a36Sopenharmony_ci	/* determine the original cqr */
178262306a36Sopenharmony_ci	cqr = previous_erp;
178362306a36Sopenharmony_ci
178462306a36Sopenharmony_ci	while (cqr->refers != NULL) {
178562306a36Sopenharmony_ci		cqr = cqr->refers;
178662306a36Sopenharmony_ci	}
178762306a36Sopenharmony_ci
178862306a36Sopenharmony_ci	if (scsw_is_tm(&cqr->irb.scsw)) {
178962306a36Sopenharmony_ci		DBF_DEV_EVENT(DBF_WARNING, device, "%s",
179062306a36Sopenharmony_ci			      "32 bit sense, action 1B, update,"
179162306a36Sopenharmony_ci			      " in transport mode - just retry");
179262306a36Sopenharmony_ci		return previous_erp;
179362306a36Sopenharmony_ci	}
179462306a36Sopenharmony_ci
179562306a36Sopenharmony_ci	/* for imprecise ending just do default erp */
179662306a36Sopenharmony_ci	if (sense[1] & 0x01) {
179762306a36Sopenharmony_ci		DBF_DEV_EVENT(DBF_WARNING, device, "%s",
179862306a36Sopenharmony_ci			    "Imprecise ending is set - just retry");
179962306a36Sopenharmony_ci
180062306a36Sopenharmony_ci		previous_erp->status = DASD_CQR_FILLED;
180162306a36Sopenharmony_ci
180262306a36Sopenharmony_ci		return previous_erp;
180362306a36Sopenharmony_ci	}
180462306a36Sopenharmony_ci
180562306a36Sopenharmony_ci	/* determine the address of the CCW to be restarted */
180662306a36Sopenharmony_ci	/* Imprecise ending is not set -> addr from IRB-SCSW */
180762306a36Sopenharmony_ci	cpa = previous_erp->irb.scsw.cmd.cpa;
180862306a36Sopenharmony_ci
180962306a36Sopenharmony_ci	if (cpa == 0) {
181062306a36Sopenharmony_ci		/* internal error 02 -
181162306a36Sopenharmony_ci		   Unable to determine address of the CCW to be restarted */
181262306a36Sopenharmony_ci		dev_err(&device->cdev->dev, "An error occurred in the DASD "
181362306a36Sopenharmony_ci			"device driver, reason=%s\n", "02");
181462306a36Sopenharmony_ci
181562306a36Sopenharmony_ci		previous_erp->status = DASD_CQR_FAILED;
181662306a36Sopenharmony_ci
181762306a36Sopenharmony_ci		return previous_erp;
181862306a36Sopenharmony_ci	}
181962306a36Sopenharmony_ci
182062306a36Sopenharmony_ci	erp = previous_erp;
182162306a36Sopenharmony_ci
182262306a36Sopenharmony_ci	/* update the LO with the new returned sense data  */
182362306a36Sopenharmony_ci	LO_data = erp->data + sizeof(struct DE_eckd_data);
182462306a36Sopenharmony_ci
182562306a36Sopenharmony_ci	if ((sense[3] == 0x01) && (LO_data[1] & 0x01)) {
182662306a36Sopenharmony_ci		/* should not happen */
182762306a36Sopenharmony_ci		previous_erp->status = DASD_CQR_FAILED;
182862306a36Sopenharmony_ci
182962306a36Sopenharmony_ci		return previous_erp;
183062306a36Sopenharmony_ci	}
183162306a36Sopenharmony_ci
183262306a36Sopenharmony_ci	if ((sense[7] & 0x3F) == 0x01) {
183362306a36Sopenharmony_ci		/* operation code is WRITE DATA -> data area orientation */
183462306a36Sopenharmony_ci		LO_data[0] = 0x81;
183562306a36Sopenharmony_ci
183662306a36Sopenharmony_ci	} else if ((sense[7] & 0x3F) == 0x03) {
183762306a36Sopenharmony_ci		/* operation code is FORMAT WRITE -> index orientation */
183862306a36Sopenharmony_ci		LO_data[0] = 0xC3;
183962306a36Sopenharmony_ci
184062306a36Sopenharmony_ci	} else {
184162306a36Sopenharmony_ci		LO_data[0] = sense[7];	/* operation */
184262306a36Sopenharmony_ci	}
184362306a36Sopenharmony_ci
184462306a36Sopenharmony_ci	LO_data[1] = sense[8];	/* auxiliary */
184562306a36Sopenharmony_ci	LO_data[2] = sense[9];
184662306a36Sopenharmony_ci	LO_data[3] = sense[3];	/* count */
184762306a36Sopenharmony_ci	LO_data[4] = sense[29];	/* seek_addr.cyl */
184862306a36Sopenharmony_ci	LO_data[5] = sense[30];	/* seek_addr.cyl 2nd byte */
184962306a36Sopenharmony_ci	LO_data[7] = sense[31];	/* seek_addr.head 2nd byte */
185062306a36Sopenharmony_ci
185162306a36Sopenharmony_ci	memcpy(&(LO_data[8]), &(sense[11]), 8);
185262306a36Sopenharmony_ci
185362306a36Sopenharmony_ci	/* TIC to the failed ccw */
185462306a36Sopenharmony_ci	ccw = erp->cpaddr;	/* addr of DE ccw */
185562306a36Sopenharmony_ci	ccw++;			/* addr of LE ccw */
185662306a36Sopenharmony_ci	ccw++;			/* addr of TIC ccw */
185762306a36Sopenharmony_ci	ccw->cda = cpa;
185862306a36Sopenharmony_ci
185962306a36Sopenharmony_ci	erp->status = DASD_CQR_FILLED;
186062306a36Sopenharmony_ci
186162306a36Sopenharmony_ci	return erp;
186262306a36Sopenharmony_ci
186362306a36Sopenharmony_ci}				/* end dasd_3990_update_1B */
186462306a36Sopenharmony_ci
186562306a36Sopenharmony_ci/*
186662306a36Sopenharmony_ci * DASD_3990_ERP_COMPOUND_RETRY
186762306a36Sopenharmony_ci *
186862306a36Sopenharmony_ci * DESCRIPTION
186962306a36Sopenharmony_ci *   Handles the compound ERP action retry code.
187062306a36Sopenharmony_ci *   NOTE: At least one retry is done even if zero is specified
187162306a36Sopenharmony_ci *	   by the sense data. This makes enqueueing of the request
187262306a36Sopenharmony_ci *	   easier.
187362306a36Sopenharmony_ci *
187462306a36Sopenharmony_ci * PARAMETER
187562306a36Sopenharmony_ci *   sense		sense data of the actual error
187662306a36Sopenharmony_ci *   erp		pointer to the currently created ERP
187762306a36Sopenharmony_ci *
187862306a36Sopenharmony_ci * RETURN VALUES
187962306a36Sopenharmony_ci *   erp		modified ERP pointer
188062306a36Sopenharmony_ci *
188162306a36Sopenharmony_ci */
188262306a36Sopenharmony_cistatic void
188362306a36Sopenharmony_cidasd_3990_erp_compound_retry(struct dasd_ccw_req * erp, char *sense)
188462306a36Sopenharmony_ci{
188562306a36Sopenharmony_ci
188662306a36Sopenharmony_ci	switch (sense[25] & 0x03) {
188762306a36Sopenharmony_ci	case 0x00:		/* no not retry */
188862306a36Sopenharmony_ci		erp->retries = 1;
188962306a36Sopenharmony_ci		break;
189062306a36Sopenharmony_ci
189162306a36Sopenharmony_ci	case 0x01:		/* retry 2 times */
189262306a36Sopenharmony_ci		erp->retries = 2;
189362306a36Sopenharmony_ci		break;
189462306a36Sopenharmony_ci
189562306a36Sopenharmony_ci	case 0x02:		/* retry 10 times */
189662306a36Sopenharmony_ci		erp->retries = 10;
189762306a36Sopenharmony_ci		break;
189862306a36Sopenharmony_ci
189962306a36Sopenharmony_ci	case 0x03:		/* retry 256 times */
190062306a36Sopenharmony_ci		erp->retries = 256;
190162306a36Sopenharmony_ci		break;
190262306a36Sopenharmony_ci
190362306a36Sopenharmony_ci	default:
190462306a36Sopenharmony_ci		BUG();
190562306a36Sopenharmony_ci	}
190662306a36Sopenharmony_ci
190762306a36Sopenharmony_ci	erp->function = dasd_3990_erp_compound_retry;
190862306a36Sopenharmony_ci
190962306a36Sopenharmony_ci}				/* end dasd_3990_erp_compound_retry */
191062306a36Sopenharmony_ci
191162306a36Sopenharmony_ci/*
191262306a36Sopenharmony_ci * DASD_3990_ERP_COMPOUND_PATH
191362306a36Sopenharmony_ci *
191462306a36Sopenharmony_ci * DESCRIPTION
191562306a36Sopenharmony_ci *   Handles the compound ERP action for retry on alternate
191662306a36Sopenharmony_ci *   channel path.
191762306a36Sopenharmony_ci *
191862306a36Sopenharmony_ci * PARAMETER
191962306a36Sopenharmony_ci *   sense		sense data of the actual error
192062306a36Sopenharmony_ci *   erp		pointer to the currently created ERP
192162306a36Sopenharmony_ci *
192262306a36Sopenharmony_ci * RETURN VALUES
192362306a36Sopenharmony_ci *   erp		modified ERP pointer
192462306a36Sopenharmony_ci *
192562306a36Sopenharmony_ci */
192662306a36Sopenharmony_cistatic void
192762306a36Sopenharmony_cidasd_3990_erp_compound_path(struct dasd_ccw_req * erp, char *sense)
192862306a36Sopenharmony_ci{
192962306a36Sopenharmony_ci	if (sense[25] & DASD_SENSE_BIT_3) {
193062306a36Sopenharmony_ci		dasd_3990_erp_alternate_path(erp);
193162306a36Sopenharmony_ci
193262306a36Sopenharmony_ci		if (erp->status == DASD_CQR_FAILED &&
193362306a36Sopenharmony_ci		    !test_bit(DASD_CQR_VERIFY_PATH, &erp->flags)) {
193462306a36Sopenharmony_ci			/* reset the lpm and the status to be able to
193562306a36Sopenharmony_ci			 * try further actions. */
193662306a36Sopenharmony_ci			erp->lpm = dasd_path_get_opm(erp->startdev);
193762306a36Sopenharmony_ci			erp->status = DASD_CQR_NEED_ERP;
193862306a36Sopenharmony_ci		}
193962306a36Sopenharmony_ci	}
194062306a36Sopenharmony_ci
194162306a36Sopenharmony_ci	erp->function = dasd_3990_erp_compound_path;
194262306a36Sopenharmony_ci
194362306a36Sopenharmony_ci}				/* end dasd_3990_erp_compound_path */
194462306a36Sopenharmony_ci
194562306a36Sopenharmony_ci/*
194662306a36Sopenharmony_ci * DASD_3990_ERP_COMPOUND_CODE
194762306a36Sopenharmony_ci *
194862306a36Sopenharmony_ci * DESCRIPTION
194962306a36Sopenharmony_ci *   Handles the compound ERP action for retry code.
195062306a36Sopenharmony_ci *
195162306a36Sopenharmony_ci * PARAMETER
195262306a36Sopenharmony_ci *   sense		sense data of the actual error
195362306a36Sopenharmony_ci *   erp		pointer to the currently created ERP
195462306a36Sopenharmony_ci *
195562306a36Sopenharmony_ci * RETURN VALUES
195662306a36Sopenharmony_ci *   erp		NEW ERP pointer
195762306a36Sopenharmony_ci *
195862306a36Sopenharmony_ci */
195962306a36Sopenharmony_cistatic struct dasd_ccw_req *
196062306a36Sopenharmony_cidasd_3990_erp_compound_code(struct dasd_ccw_req * erp, char *sense)
196162306a36Sopenharmony_ci{
196262306a36Sopenharmony_ci
196362306a36Sopenharmony_ci	if (sense[25] & DASD_SENSE_BIT_2) {
196462306a36Sopenharmony_ci
196562306a36Sopenharmony_ci		switch (sense[28]) {
196662306a36Sopenharmony_ci		case 0x17:
196762306a36Sopenharmony_ci			/* issue a Diagnostic Control command with an
196862306a36Sopenharmony_ci			 * Inhibit Write subcommand and controller modifier */
196962306a36Sopenharmony_ci			erp = dasd_3990_erp_DCTL(erp, 0x20);
197062306a36Sopenharmony_ci			break;
197162306a36Sopenharmony_ci
197262306a36Sopenharmony_ci		case 0x25:
197362306a36Sopenharmony_ci			/* wait for 5 seconds and retry again */
197462306a36Sopenharmony_ci			erp->retries = 1;
197562306a36Sopenharmony_ci
197662306a36Sopenharmony_ci			dasd_3990_erp_block_queue (erp, 5*HZ);
197762306a36Sopenharmony_ci			break;
197862306a36Sopenharmony_ci
197962306a36Sopenharmony_ci		default:
198062306a36Sopenharmony_ci			/* should not happen - continue */
198162306a36Sopenharmony_ci			break;
198262306a36Sopenharmony_ci		}
198362306a36Sopenharmony_ci	}
198462306a36Sopenharmony_ci
198562306a36Sopenharmony_ci	erp->function = dasd_3990_erp_compound_code;
198662306a36Sopenharmony_ci
198762306a36Sopenharmony_ci	return erp;
198862306a36Sopenharmony_ci
198962306a36Sopenharmony_ci}				/* end dasd_3990_erp_compound_code */
199062306a36Sopenharmony_ci
199162306a36Sopenharmony_ci/*
199262306a36Sopenharmony_ci * DASD_3990_ERP_COMPOUND_CONFIG
199362306a36Sopenharmony_ci *
199462306a36Sopenharmony_ci * DESCRIPTION
199562306a36Sopenharmony_ci *   Handles the compound ERP action for configuration
199662306a36Sopenharmony_ci *   dependent error.
199762306a36Sopenharmony_ci *   Note: duplex handling is not implemented (yet).
199862306a36Sopenharmony_ci *
199962306a36Sopenharmony_ci * PARAMETER
200062306a36Sopenharmony_ci *   sense		sense data of the actual error
200162306a36Sopenharmony_ci *   erp		pointer to the currently created ERP
200262306a36Sopenharmony_ci *
200362306a36Sopenharmony_ci * RETURN VALUES
200462306a36Sopenharmony_ci *   erp		modified ERP pointer
200562306a36Sopenharmony_ci *
200662306a36Sopenharmony_ci */
200762306a36Sopenharmony_cistatic void
200862306a36Sopenharmony_cidasd_3990_erp_compound_config(struct dasd_ccw_req * erp, char *sense)
200962306a36Sopenharmony_ci{
201062306a36Sopenharmony_ci
201162306a36Sopenharmony_ci	if ((sense[25] & DASD_SENSE_BIT_1) && (sense[26] & DASD_SENSE_BIT_2)) {
201262306a36Sopenharmony_ci
201362306a36Sopenharmony_ci		/* set to suspended duplex state then restart
201462306a36Sopenharmony_ci		   internal error 05 - Set device to suspended duplex state
201562306a36Sopenharmony_ci		   should be done */
201662306a36Sopenharmony_ci		struct dasd_device *device = erp->startdev;
201762306a36Sopenharmony_ci		dev_err(&device->cdev->dev,
201862306a36Sopenharmony_ci			"An error occurred in the DASD device driver, "
201962306a36Sopenharmony_ci			"reason=%s\n", "05");
202062306a36Sopenharmony_ci
202162306a36Sopenharmony_ci	}
202262306a36Sopenharmony_ci
202362306a36Sopenharmony_ci	erp->function = dasd_3990_erp_compound_config;
202462306a36Sopenharmony_ci
202562306a36Sopenharmony_ci}				/* end dasd_3990_erp_compound_config */
202662306a36Sopenharmony_ci
202762306a36Sopenharmony_ci/*
202862306a36Sopenharmony_ci * DASD_3990_ERP_COMPOUND
202962306a36Sopenharmony_ci *
203062306a36Sopenharmony_ci * DESCRIPTION
203162306a36Sopenharmony_ci *   Does the further compound program action if
203262306a36Sopenharmony_ci *   compound retry was not successful.
203362306a36Sopenharmony_ci *
203462306a36Sopenharmony_ci * PARAMETER
203562306a36Sopenharmony_ci *   sense		sense data of the actual error
203662306a36Sopenharmony_ci *   erp		pointer to the current (failed) ERP
203762306a36Sopenharmony_ci *
203862306a36Sopenharmony_ci * RETURN VALUES
203962306a36Sopenharmony_ci *   erp		(additional) ERP pointer
204062306a36Sopenharmony_ci *
204162306a36Sopenharmony_ci */
204262306a36Sopenharmony_cistatic struct dasd_ccw_req *
204362306a36Sopenharmony_cidasd_3990_erp_compound(struct dasd_ccw_req * erp, char *sense)
204462306a36Sopenharmony_ci{
204562306a36Sopenharmony_ci
204662306a36Sopenharmony_ci	if ((erp->function == dasd_3990_erp_compound_retry) &&
204762306a36Sopenharmony_ci	    (erp->status == DASD_CQR_NEED_ERP)) {
204862306a36Sopenharmony_ci
204962306a36Sopenharmony_ci		dasd_3990_erp_compound_path(erp, sense);
205062306a36Sopenharmony_ci	}
205162306a36Sopenharmony_ci
205262306a36Sopenharmony_ci	if ((erp->function == dasd_3990_erp_compound_path) &&
205362306a36Sopenharmony_ci	    (erp->status == DASD_CQR_NEED_ERP)) {
205462306a36Sopenharmony_ci
205562306a36Sopenharmony_ci		erp = dasd_3990_erp_compound_code(erp, sense);
205662306a36Sopenharmony_ci	}
205762306a36Sopenharmony_ci
205862306a36Sopenharmony_ci	if ((erp->function == dasd_3990_erp_compound_code) &&
205962306a36Sopenharmony_ci	    (erp->status == DASD_CQR_NEED_ERP)) {
206062306a36Sopenharmony_ci
206162306a36Sopenharmony_ci		dasd_3990_erp_compound_config(erp, sense);
206262306a36Sopenharmony_ci	}
206362306a36Sopenharmony_ci
206462306a36Sopenharmony_ci	/* if no compound action ERP specified, the request failed */
206562306a36Sopenharmony_ci	if (erp->status == DASD_CQR_NEED_ERP)
206662306a36Sopenharmony_ci		erp->status = DASD_CQR_FAILED;
206762306a36Sopenharmony_ci
206862306a36Sopenharmony_ci	return erp;
206962306a36Sopenharmony_ci
207062306a36Sopenharmony_ci}				/* end dasd_3990_erp_compound */
207162306a36Sopenharmony_ci
207262306a36Sopenharmony_ci/*
207362306a36Sopenharmony_ci *DASD_3990_ERP_HANDLE_SIM
207462306a36Sopenharmony_ci *
207562306a36Sopenharmony_ci *DESCRIPTION
207662306a36Sopenharmony_ci *  inspects the SIM SENSE data and starts an appropriate action
207762306a36Sopenharmony_ci *
207862306a36Sopenharmony_ci * PARAMETER
207962306a36Sopenharmony_ci *   sense	   sense data of the actual error
208062306a36Sopenharmony_ci *
208162306a36Sopenharmony_ci * RETURN VALUES
208262306a36Sopenharmony_ci *   none
208362306a36Sopenharmony_ci */
208462306a36Sopenharmony_civoid
208562306a36Sopenharmony_cidasd_3990_erp_handle_sim(struct dasd_device *device, char *sense)
208662306a36Sopenharmony_ci{
208762306a36Sopenharmony_ci	/* print message according to log or message to operator mode */
208862306a36Sopenharmony_ci	if ((sense[24] & DASD_SIM_MSG_TO_OP) || (sense[1] & 0x10)) {
208962306a36Sopenharmony_ci		/* print SIM SRC from RefCode */
209062306a36Sopenharmony_ci		dev_err(&device->cdev->dev, "SIM - SRC: "
209162306a36Sopenharmony_ci			    "%02x%02x%02x%02x\n", sense[22],
209262306a36Sopenharmony_ci			    sense[23], sense[11], sense[12]);
209362306a36Sopenharmony_ci	} else if (sense[24] & DASD_SIM_LOG) {
209462306a36Sopenharmony_ci		/* print SIM SRC Refcode */
209562306a36Sopenharmony_ci		dev_warn(&device->cdev->dev, "log SIM - SRC: "
209662306a36Sopenharmony_ci			    "%02x%02x%02x%02x\n", sense[22],
209762306a36Sopenharmony_ci			    sense[23], sense[11], sense[12]);
209862306a36Sopenharmony_ci	}
209962306a36Sopenharmony_ci}
210062306a36Sopenharmony_ci
210162306a36Sopenharmony_ci/*
210262306a36Sopenharmony_ci * DASD_3990_ERP_INSPECT_32
210362306a36Sopenharmony_ci *
210462306a36Sopenharmony_ci * DESCRIPTION
210562306a36Sopenharmony_ci *   Does a detailed inspection of the 32 byte sense data
210662306a36Sopenharmony_ci *   and sets up a related error recovery action.
210762306a36Sopenharmony_ci *
210862306a36Sopenharmony_ci * PARAMETER
210962306a36Sopenharmony_ci *   sense		sense data of the actual error
211062306a36Sopenharmony_ci *   erp		pointer to the currently created default ERP
211162306a36Sopenharmony_ci *
211262306a36Sopenharmony_ci * RETURN VALUES
211362306a36Sopenharmony_ci *   erp_filled		pointer to the ERP
211462306a36Sopenharmony_ci *
211562306a36Sopenharmony_ci */
211662306a36Sopenharmony_cistatic struct dasd_ccw_req *
211762306a36Sopenharmony_cidasd_3990_erp_inspect_32(struct dasd_ccw_req * erp, char *sense)
211862306a36Sopenharmony_ci{
211962306a36Sopenharmony_ci
212062306a36Sopenharmony_ci	struct dasd_device *device = erp->startdev;
212162306a36Sopenharmony_ci
212262306a36Sopenharmony_ci	erp->function = dasd_3990_erp_inspect_32;
212362306a36Sopenharmony_ci
212462306a36Sopenharmony_ci	/* check for SIM sense data */
212562306a36Sopenharmony_ci	if ((sense[6] & DASD_SIM_SENSE) == DASD_SIM_SENSE)
212662306a36Sopenharmony_ci		dasd_3990_erp_handle_sim(device, sense);
212762306a36Sopenharmony_ci
212862306a36Sopenharmony_ci	if (sense[25] & DASD_SENSE_BIT_0) {
212962306a36Sopenharmony_ci
213062306a36Sopenharmony_ci		/* compound program action codes (byte25 bit 0 == '1') */
213162306a36Sopenharmony_ci		dasd_3990_erp_compound_retry(erp, sense);
213262306a36Sopenharmony_ci
213362306a36Sopenharmony_ci	} else {
213462306a36Sopenharmony_ci
213562306a36Sopenharmony_ci		/* single program action codes (byte25 bit 0 == '0') */
213662306a36Sopenharmony_ci		switch (sense[25]) {
213762306a36Sopenharmony_ci
213862306a36Sopenharmony_ci		case 0x00:	/* success - use default ERP for retries */
213962306a36Sopenharmony_ci			DBF_DEV_EVENT(DBF_DEBUG, device, "%s",
214062306a36Sopenharmony_ci				    "ERP called for successful request"
214162306a36Sopenharmony_ci				    " - just retry");
214262306a36Sopenharmony_ci			break;
214362306a36Sopenharmony_ci
214462306a36Sopenharmony_ci		case 0x01:	/* fatal error */
214562306a36Sopenharmony_ci			dev_err(&device->cdev->dev,
214662306a36Sopenharmony_ci				    "ERP failed for the DASD\n");
214762306a36Sopenharmony_ci
214862306a36Sopenharmony_ci			erp = dasd_3990_erp_cleanup(erp, DASD_CQR_FAILED);
214962306a36Sopenharmony_ci			break;
215062306a36Sopenharmony_ci
215162306a36Sopenharmony_ci		case 0x02:	/* intervention required */
215262306a36Sopenharmony_ci		case 0x03:	/* intervention required during dual copy */
215362306a36Sopenharmony_ci			erp = dasd_3990_erp_int_req(erp);
215462306a36Sopenharmony_ci			break;
215562306a36Sopenharmony_ci
215662306a36Sopenharmony_ci		case 0x0F:  /* length mismatch during update write command
215762306a36Sopenharmony_ci			       internal error 08 - update write command error*/
215862306a36Sopenharmony_ci			dev_err(&device->cdev->dev, "An error occurred in the "
215962306a36Sopenharmony_ci				"DASD device driver, reason=%s\n", "08");
216062306a36Sopenharmony_ci
216162306a36Sopenharmony_ci			erp = dasd_3990_erp_cleanup(erp, DASD_CQR_FAILED);
216262306a36Sopenharmony_ci			break;
216362306a36Sopenharmony_ci
216462306a36Sopenharmony_ci		case 0x10:  /* logging required for other channel program */
216562306a36Sopenharmony_ci			erp = dasd_3990_erp_action_10_32(erp, sense);
216662306a36Sopenharmony_ci			break;
216762306a36Sopenharmony_ci
216862306a36Sopenharmony_ci		case 0x15:	/* next track outside defined extend
216962306a36Sopenharmony_ci				   internal error 07 - The next track is not
217062306a36Sopenharmony_ci				   within the defined storage extent */
217162306a36Sopenharmony_ci			dev_err(&device->cdev->dev,
217262306a36Sopenharmony_ci				"An error occurred in the DASD device driver, "
217362306a36Sopenharmony_ci				"reason=%s\n", "07");
217462306a36Sopenharmony_ci
217562306a36Sopenharmony_ci			erp = dasd_3990_erp_cleanup(erp, DASD_CQR_FAILED);
217662306a36Sopenharmony_ci			break;
217762306a36Sopenharmony_ci
217862306a36Sopenharmony_ci		case 0x1B:	/* unexpected condition during write */
217962306a36Sopenharmony_ci
218062306a36Sopenharmony_ci			erp = dasd_3990_erp_action_1B_32(erp, sense);
218162306a36Sopenharmony_ci			break;
218262306a36Sopenharmony_ci
218362306a36Sopenharmony_ci		case 0x1C:	/* invalid data */
218462306a36Sopenharmony_ci			dev_emerg(&device->cdev->dev,
218562306a36Sopenharmony_ci				    "Data recovered during retry with PCI "
218662306a36Sopenharmony_ci				    "fetch mode active\n");
218762306a36Sopenharmony_ci
218862306a36Sopenharmony_ci			/* not possible to handle this situation in Linux */
218962306a36Sopenharmony_ci			panic
219062306a36Sopenharmony_ci			    ("Invalid data - No way to inform application "
219162306a36Sopenharmony_ci			     "about the possibly incorrect data");
219262306a36Sopenharmony_ci			break;
219362306a36Sopenharmony_ci
219462306a36Sopenharmony_ci		case 0x1D:	/* state-change pending */
219562306a36Sopenharmony_ci			DBF_DEV_EVENT(DBF_WARNING, device, "%s",
219662306a36Sopenharmony_ci				    "A State change pending condition exists "
219762306a36Sopenharmony_ci				    "for the subsystem or device");
219862306a36Sopenharmony_ci
219962306a36Sopenharmony_ci			erp = dasd_3990_erp_action_4(erp, sense);
220062306a36Sopenharmony_ci			break;
220162306a36Sopenharmony_ci
220262306a36Sopenharmony_ci		case 0x1E:	/* busy */
220362306a36Sopenharmony_ci			DBF_DEV_EVENT(DBF_WARNING, device, "%s",
220462306a36Sopenharmony_ci				    "Busy condition exists "
220562306a36Sopenharmony_ci				    "for the subsystem or device");
220662306a36Sopenharmony_ci                        erp = dasd_3990_erp_action_4(erp, sense);
220762306a36Sopenharmony_ci			break;
220862306a36Sopenharmony_ci
220962306a36Sopenharmony_ci		default:	/* all others errors - default erp  */
221062306a36Sopenharmony_ci			break;
221162306a36Sopenharmony_ci		}
221262306a36Sopenharmony_ci	}
221362306a36Sopenharmony_ci
221462306a36Sopenharmony_ci	return erp;
221562306a36Sopenharmony_ci
221662306a36Sopenharmony_ci}				/* end dasd_3990_erp_inspect_32 */
221762306a36Sopenharmony_ci
221862306a36Sopenharmony_cistatic void dasd_3990_erp_disable_path(struct dasd_device *device, __u8 lpum)
221962306a36Sopenharmony_ci{
222062306a36Sopenharmony_ci	int pos = pathmask_to_pos(lpum);
222162306a36Sopenharmony_ci
222262306a36Sopenharmony_ci	if (!(device->features & DASD_FEATURE_PATH_AUTODISABLE)) {
222362306a36Sopenharmony_ci		dev_err(&device->cdev->dev,
222462306a36Sopenharmony_ci			"Path %x.%02x (pathmask %02x) is operational despite excessive IFCCs\n",
222562306a36Sopenharmony_ci			device->path[pos].cssid, device->path[pos].chpid, lpum);
222662306a36Sopenharmony_ci		goto out;
222762306a36Sopenharmony_ci	}
222862306a36Sopenharmony_ci
222962306a36Sopenharmony_ci	/* no remaining path, cannot disable */
223062306a36Sopenharmony_ci	if (!(dasd_path_get_opm(device) & ~lpum)) {
223162306a36Sopenharmony_ci		dev_err(&device->cdev->dev,
223262306a36Sopenharmony_ci			"Last path %x.%02x (pathmask %02x) is operational despite excessive IFCCs\n",
223362306a36Sopenharmony_ci			device->path[pos].cssid, device->path[pos].chpid, lpum);
223462306a36Sopenharmony_ci		goto out;
223562306a36Sopenharmony_ci	}
223662306a36Sopenharmony_ci
223762306a36Sopenharmony_ci	dev_err(&device->cdev->dev,
223862306a36Sopenharmony_ci		"Path %x.%02x (pathmask %02x) is disabled - IFCC threshold exceeded\n",
223962306a36Sopenharmony_ci		device->path[pos].cssid, device->path[pos].chpid, lpum);
224062306a36Sopenharmony_ci	dasd_path_remove_opm(device, lpum);
224162306a36Sopenharmony_ci	dasd_path_add_ifccpm(device, lpum);
224262306a36Sopenharmony_ci
224362306a36Sopenharmony_ciout:
224462306a36Sopenharmony_ci	device->path[pos].errorclk = 0;
224562306a36Sopenharmony_ci	atomic_set(&device->path[pos].error_count, 0);
224662306a36Sopenharmony_ci}
224762306a36Sopenharmony_ci
224862306a36Sopenharmony_cistatic void dasd_3990_erp_account_error(struct dasd_ccw_req *erp)
224962306a36Sopenharmony_ci{
225062306a36Sopenharmony_ci	struct dasd_device *device = erp->startdev;
225162306a36Sopenharmony_ci	__u8 lpum = erp->refers->irb.esw.esw1.lpum;
225262306a36Sopenharmony_ci	int pos = pathmask_to_pos(lpum);
225362306a36Sopenharmony_ci	unsigned long clk;
225462306a36Sopenharmony_ci
225562306a36Sopenharmony_ci	if (!device->path_thrhld)
225662306a36Sopenharmony_ci		return;
225762306a36Sopenharmony_ci
225862306a36Sopenharmony_ci	clk = get_tod_clock();
225962306a36Sopenharmony_ci	/*
226062306a36Sopenharmony_ci	 * check if the last error is longer ago than the timeout,
226162306a36Sopenharmony_ci	 * if so reset error state
226262306a36Sopenharmony_ci	 */
226362306a36Sopenharmony_ci	if ((tod_to_ns(clk - device->path[pos].errorclk) / NSEC_PER_SEC)
226462306a36Sopenharmony_ci	    >= device->path_interval) {
226562306a36Sopenharmony_ci		atomic_set(&device->path[pos].error_count, 0);
226662306a36Sopenharmony_ci		device->path[pos].errorclk = 0;
226762306a36Sopenharmony_ci	}
226862306a36Sopenharmony_ci	atomic_inc(&device->path[pos].error_count);
226962306a36Sopenharmony_ci	device->path[pos].errorclk = clk;
227062306a36Sopenharmony_ci	/* threshold exceeded disable path if possible */
227162306a36Sopenharmony_ci	if (atomic_read(&device->path[pos].error_count) >=
227262306a36Sopenharmony_ci	    device->path_thrhld)
227362306a36Sopenharmony_ci		dasd_3990_erp_disable_path(device, lpum);
227462306a36Sopenharmony_ci}
227562306a36Sopenharmony_ci
227662306a36Sopenharmony_ci/*
227762306a36Sopenharmony_ci *****************************************************************************
227862306a36Sopenharmony_ci * main ERP control functions (24 and 32 byte sense)
227962306a36Sopenharmony_ci *****************************************************************************
228062306a36Sopenharmony_ci */
228162306a36Sopenharmony_ci
228262306a36Sopenharmony_ci/*
228362306a36Sopenharmony_ci * DASD_3990_ERP_CONTROL_CHECK
228462306a36Sopenharmony_ci *
228562306a36Sopenharmony_ci * DESCRIPTION
228662306a36Sopenharmony_ci *   Does a generic inspection if a control check occurred and sets up
228762306a36Sopenharmony_ci *   the related error recovery procedure
228862306a36Sopenharmony_ci *
228962306a36Sopenharmony_ci * PARAMETER
229062306a36Sopenharmony_ci *   erp		pointer to the currently created default ERP
229162306a36Sopenharmony_ci *
229262306a36Sopenharmony_ci * RETURN VALUES
229362306a36Sopenharmony_ci *   erp_filled		pointer to the erp
229462306a36Sopenharmony_ci */
229562306a36Sopenharmony_ci
229662306a36Sopenharmony_cistatic struct dasd_ccw_req *
229762306a36Sopenharmony_cidasd_3990_erp_control_check(struct dasd_ccw_req *erp)
229862306a36Sopenharmony_ci{
229962306a36Sopenharmony_ci	struct dasd_device *device = erp->startdev;
230062306a36Sopenharmony_ci
230162306a36Sopenharmony_ci	if (scsw_cstat(&erp->refers->irb.scsw) & (SCHN_STAT_INTF_CTRL_CHK
230262306a36Sopenharmony_ci					   | SCHN_STAT_CHN_CTRL_CHK)) {
230362306a36Sopenharmony_ci		DBF_DEV_EVENT(DBF_WARNING, device, "%s",
230462306a36Sopenharmony_ci			    "channel or interface control check");
230562306a36Sopenharmony_ci		dasd_3990_erp_account_error(erp);
230662306a36Sopenharmony_ci		erp = dasd_3990_erp_action_4(erp, NULL);
230762306a36Sopenharmony_ci	}
230862306a36Sopenharmony_ci	return erp;
230962306a36Sopenharmony_ci}
231062306a36Sopenharmony_ci
231162306a36Sopenharmony_ci/*
231262306a36Sopenharmony_ci * DASD_3990_ERP_INSPECT
231362306a36Sopenharmony_ci *
231462306a36Sopenharmony_ci * DESCRIPTION
231562306a36Sopenharmony_ci *   Does a detailed inspection for sense data by calling either
231662306a36Sopenharmony_ci *   the 24-byte or the 32-byte inspection routine.
231762306a36Sopenharmony_ci *
231862306a36Sopenharmony_ci * PARAMETER
231962306a36Sopenharmony_ci *   erp		pointer to the currently created default ERP
232062306a36Sopenharmony_ci * RETURN VALUES
232162306a36Sopenharmony_ci *   erp_new		contens was possibly modified
232262306a36Sopenharmony_ci */
232362306a36Sopenharmony_cistatic struct dasd_ccw_req *
232462306a36Sopenharmony_cidasd_3990_erp_inspect(struct dasd_ccw_req *erp)
232562306a36Sopenharmony_ci{
232662306a36Sopenharmony_ci
232762306a36Sopenharmony_ci	struct dasd_ccw_req *erp_new = NULL;
232862306a36Sopenharmony_ci	char *sense;
232962306a36Sopenharmony_ci
233062306a36Sopenharmony_ci	/* if this problem occurred on an alias retry on base */
233162306a36Sopenharmony_ci	erp_new = dasd_3990_erp_inspect_alias(erp);
233262306a36Sopenharmony_ci	if (erp_new)
233362306a36Sopenharmony_ci		return erp_new;
233462306a36Sopenharmony_ci
233562306a36Sopenharmony_ci	/* sense data are located in the refers record of the
233662306a36Sopenharmony_ci	 * already set up new ERP !
233762306a36Sopenharmony_ci	 * check if concurrent sens is available
233862306a36Sopenharmony_ci	 */
233962306a36Sopenharmony_ci	sense = dasd_get_sense(&erp->refers->irb);
234062306a36Sopenharmony_ci	if (!sense)
234162306a36Sopenharmony_ci		erp_new = dasd_3990_erp_control_check(erp);
234262306a36Sopenharmony_ci	/* distinguish between 24 and 32 byte sense data */
234362306a36Sopenharmony_ci	else if (sense[27] & DASD_SENSE_BIT_0) {
234462306a36Sopenharmony_ci
234562306a36Sopenharmony_ci		/* inspect the 24 byte sense data */
234662306a36Sopenharmony_ci		erp_new = dasd_3990_erp_inspect_24(erp, sense);
234762306a36Sopenharmony_ci
234862306a36Sopenharmony_ci	} else {
234962306a36Sopenharmony_ci
235062306a36Sopenharmony_ci		/* inspect the 32 byte sense data */
235162306a36Sopenharmony_ci		erp_new = dasd_3990_erp_inspect_32(erp, sense);
235262306a36Sopenharmony_ci
235362306a36Sopenharmony_ci	}	/* end distinguish between 24 and 32 byte sense data */
235462306a36Sopenharmony_ci
235562306a36Sopenharmony_ci	return erp_new;
235662306a36Sopenharmony_ci}
235762306a36Sopenharmony_ci
235862306a36Sopenharmony_ci/*
235962306a36Sopenharmony_ci * DASD_3990_ERP_ADD_ERP
236062306a36Sopenharmony_ci *
236162306a36Sopenharmony_ci * DESCRIPTION
236262306a36Sopenharmony_ci *   This function adds an additional request block (ERP) to the head of
236362306a36Sopenharmony_ci *   the given cqr (or erp).
236462306a36Sopenharmony_ci *   For a command mode cqr the erp is initialized as an default erp
236562306a36Sopenharmony_ci *   (retry TIC).
236662306a36Sopenharmony_ci *   For transport mode we make a copy of the original TCW (points to
236762306a36Sopenharmony_ci *   the original TCCB, TIDALs, etc.) but give it a fresh
236862306a36Sopenharmony_ci *   TSB so the original sense data will not be changed.
236962306a36Sopenharmony_ci *
237062306a36Sopenharmony_ci * PARAMETER
237162306a36Sopenharmony_ci *   cqr		head of the current ERP-chain (or single cqr if
237262306a36Sopenharmony_ci *			first error)
237362306a36Sopenharmony_ci * RETURN VALUES
237462306a36Sopenharmony_ci *   erp		pointer to new ERP-chain head
237562306a36Sopenharmony_ci */
237662306a36Sopenharmony_cistatic struct dasd_ccw_req *dasd_3990_erp_add_erp(struct dasd_ccw_req *cqr)
237762306a36Sopenharmony_ci{
237862306a36Sopenharmony_ci
237962306a36Sopenharmony_ci	struct dasd_device *device = cqr->startdev;
238062306a36Sopenharmony_ci	struct ccw1 *ccw;
238162306a36Sopenharmony_ci	struct dasd_ccw_req *erp;
238262306a36Sopenharmony_ci	int cplength, datasize;
238362306a36Sopenharmony_ci	struct tcw *tcw;
238462306a36Sopenharmony_ci	struct tsb *tsb;
238562306a36Sopenharmony_ci
238662306a36Sopenharmony_ci	if (cqr->cpmode == 1) {
238762306a36Sopenharmony_ci		cplength = 0;
238862306a36Sopenharmony_ci		/* TCW needs to be 64 byte aligned, so leave enough room */
238962306a36Sopenharmony_ci		datasize = 64 + sizeof(struct tcw) + sizeof(struct tsb);
239062306a36Sopenharmony_ci	} else {
239162306a36Sopenharmony_ci		cplength = 2;
239262306a36Sopenharmony_ci		datasize = 0;
239362306a36Sopenharmony_ci	}
239462306a36Sopenharmony_ci
239562306a36Sopenharmony_ci	/* allocate additional request block */
239662306a36Sopenharmony_ci	erp = dasd_alloc_erp_request(cqr->magic,
239762306a36Sopenharmony_ci				     cplength, datasize, device);
239862306a36Sopenharmony_ci	if (IS_ERR(erp)) {
239962306a36Sopenharmony_ci                if (cqr->retries <= 0) {
240062306a36Sopenharmony_ci			DBF_DEV_EVENT(DBF_ERR, device, "%s",
240162306a36Sopenharmony_ci				    "Unable to allocate ERP request");
240262306a36Sopenharmony_ci			cqr->status = DASD_CQR_FAILED;
240362306a36Sopenharmony_ci			cqr->stopclk = get_tod_clock();
240462306a36Sopenharmony_ci		} else {
240562306a36Sopenharmony_ci			DBF_DEV_EVENT(DBF_ERR, device,
240662306a36Sopenharmony_ci                                     "Unable to allocate ERP request "
240762306a36Sopenharmony_ci				     "(%i retries left)",
240862306a36Sopenharmony_ci                                     cqr->retries);
240962306a36Sopenharmony_ci			dasd_block_set_timer(device->block, (HZ << 3));
241062306a36Sopenharmony_ci                }
241162306a36Sopenharmony_ci		return erp;
241262306a36Sopenharmony_ci	}
241362306a36Sopenharmony_ci
241462306a36Sopenharmony_ci	ccw = cqr->cpaddr;
241562306a36Sopenharmony_ci	if (cqr->cpmode == 1) {
241662306a36Sopenharmony_ci		/* make a shallow copy of the original tcw but set new tsb */
241762306a36Sopenharmony_ci		erp->cpmode = 1;
241862306a36Sopenharmony_ci		erp->cpaddr = PTR_ALIGN(erp->data, 64);
241962306a36Sopenharmony_ci		tcw = erp->cpaddr;
242062306a36Sopenharmony_ci		tsb = (struct tsb *) &tcw[1];
242162306a36Sopenharmony_ci		*tcw = *((struct tcw *)cqr->cpaddr);
242262306a36Sopenharmony_ci		tcw->tsb = virt_to_phys(tsb);
242362306a36Sopenharmony_ci	} else if (ccw->cmd_code == DASD_ECKD_CCW_PSF) {
242462306a36Sopenharmony_ci		/* PSF cannot be chained from NOOP/TIC */
242562306a36Sopenharmony_ci		erp->cpaddr = cqr->cpaddr;
242662306a36Sopenharmony_ci	} else {
242762306a36Sopenharmony_ci		/* initialize request with default TIC to current ERP/CQR */
242862306a36Sopenharmony_ci		ccw = erp->cpaddr;
242962306a36Sopenharmony_ci		ccw->cmd_code = CCW_CMD_NOOP;
243062306a36Sopenharmony_ci		ccw->flags = CCW_FLAG_CC;
243162306a36Sopenharmony_ci		ccw++;
243262306a36Sopenharmony_ci		ccw->cmd_code = CCW_CMD_TIC;
243362306a36Sopenharmony_ci		ccw->cda      = (__u32)virt_to_phys(cqr->cpaddr);
243462306a36Sopenharmony_ci	}
243562306a36Sopenharmony_ci
243662306a36Sopenharmony_ci	erp->flags = cqr->flags;
243762306a36Sopenharmony_ci	erp->function = dasd_3990_erp_add_erp;
243862306a36Sopenharmony_ci	erp->refers   = cqr;
243962306a36Sopenharmony_ci	erp->startdev = device;
244062306a36Sopenharmony_ci	erp->memdev   = device;
244162306a36Sopenharmony_ci	erp->block    = cqr->block;
244262306a36Sopenharmony_ci	erp->magic    = cqr->magic;
244362306a36Sopenharmony_ci	erp->expires  = cqr->expires;
244462306a36Sopenharmony_ci	erp->retries  = device->default_retries;
244562306a36Sopenharmony_ci	erp->buildclk = get_tod_clock();
244662306a36Sopenharmony_ci	erp->status = DASD_CQR_FILLED;
244762306a36Sopenharmony_ci
244862306a36Sopenharmony_ci	return erp;
244962306a36Sopenharmony_ci}
245062306a36Sopenharmony_ci
245162306a36Sopenharmony_ci/*
245262306a36Sopenharmony_ci * DASD_3990_ERP_ADDITIONAL_ERP
245362306a36Sopenharmony_ci *
245462306a36Sopenharmony_ci * DESCRIPTION
245562306a36Sopenharmony_ci *   An additional ERP is needed to handle the current error.
245662306a36Sopenharmony_ci *   Add ERP to the head of the ERP-chain containing the ERP processing
245762306a36Sopenharmony_ci *   determined based on the sense data.
245862306a36Sopenharmony_ci *
245962306a36Sopenharmony_ci * PARAMETER
246062306a36Sopenharmony_ci *   cqr		head of the current ERP-chain (or single cqr if
246162306a36Sopenharmony_ci *			first error)
246262306a36Sopenharmony_ci *
246362306a36Sopenharmony_ci * RETURN VALUES
246462306a36Sopenharmony_ci *   erp		pointer to new ERP-chain head
246562306a36Sopenharmony_ci */
246662306a36Sopenharmony_cistatic struct dasd_ccw_req *
246762306a36Sopenharmony_cidasd_3990_erp_additional_erp(struct dasd_ccw_req * cqr)
246862306a36Sopenharmony_ci{
246962306a36Sopenharmony_ci
247062306a36Sopenharmony_ci	struct dasd_ccw_req *erp = NULL;
247162306a36Sopenharmony_ci
247262306a36Sopenharmony_ci	/* add erp and initialize with default TIC */
247362306a36Sopenharmony_ci	erp = dasd_3990_erp_add_erp(cqr);
247462306a36Sopenharmony_ci
247562306a36Sopenharmony_ci	if (IS_ERR(erp))
247662306a36Sopenharmony_ci		return erp;
247762306a36Sopenharmony_ci
247862306a36Sopenharmony_ci	/* inspect sense, determine specific ERP if possible */
247962306a36Sopenharmony_ci	if (erp != cqr) {
248062306a36Sopenharmony_ci
248162306a36Sopenharmony_ci		erp = dasd_3990_erp_inspect(erp);
248262306a36Sopenharmony_ci	}
248362306a36Sopenharmony_ci
248462306a36Sopenharmony_ci	return erp;
248562306a36Sopenharmony_ci
248662306a36Sopenharmony_ci}				/* end dasd_3990_erp_additional_erp */
248762306a36Sopenharmony_ci
248862306a36Sopenharmony_ci/*
248962306a36Sopenharmony_ci * DASD_3990_ERP_ERROR_MATCH
249062306a36Sopenharmony_ci *
249162306a36Sopenharmony_ci * DESCRIPTION
249262306a36Sopenharmony_ci *   Check if the device status of the given cqr is the same.
249362306a36Sopenharmony_ci *   This means that the failed CCW and the relevant sense data
249462306a36Sopenharmony_ci *   must match.
249562306a36Sopenharmony_ci *   I don't distinguish between 24 and 32 byte sense because in case of
249662306a36Sopenharmony_ci *   24 byte sense byte 25 and 27 is set as well.
249762306a36Sopenharmony_ci *
249862306a36Sopenharmony_ci * PARAMETER
249962306a36Sopenharmony_ci *   cqr1		first cqr, which will be compared with the
250062306a36Sopenharmony_ci *   cqr2		second cqr.
250162306a36Sopenharmony_ci *
250262306a36Sopenharmony_ci * RETURN VALUES
250362306a36Sopenharmony_ci *   match		'boolean' for match found
250462306a36Sopenharmony_ci *			returns 1 if match found, otherwise 0.
250562306a36Sopenharmony_ci */
250662306a36Sopenharmony_cistatic int dasd_3990_erp_error_match(struct dasd_ccw_req *cqr1,
250762306a36Sopenharmony_ci				     struct dasd_ccw_req *cqr2)
250862306a36Sopenharmony_ci{
250962306a36Sopenharmony_ci	char *sense1, *sense2;
251062306a36Sopenharmony_ci
251162306a36Sopenharmony_ci	if (cqr1->startdev != cqr2->startdev)
251262306a36Sopenharmony_ci		return 0;
251362306a36Sopenharmony_ci
251462306a36Sopenharmony_ci	sense1 = dasd_get_sense(&cqr1->irb);
251562306a36Sopenharmony_ci	sense2 = dasd_get_sense(&cqr2->irb);
251662306a36Sopenharmony_ci
251762306a36Sopenharmony_ci	/* one request has sense data, the other not -> no match, return 0 */
251862306a36Sopenharmony_ci	if (!sense1 != !sense2)
251962306a36Sopenharmony_ci		return 0;
252062306a36Sopenharmony_ci	/* no sense data in both cases -> check cstat for IFCC */
252162306a36Sopenharmony_ci	if (!sense1 && !sense2)	{
252262306a36Sopenharmony_ci		if ((scsw_cstat(&cqr1->irb.scsw) & (SCHN_STAT_INTF_CTRL_CHK |
252362306a36Sopenharmony_ci						    SCHN_STAT_CHN_CTRL_CHK)) ==
252462306a36Sopenharmony_ci		    (scsw_cstat(&cqr2->irb.scsw) & (SCHN_STAT_INTF_CTRL_CHK |
252562306a36Sopenharmony_ci						    SCHN_STAT_CHN_CTRL_CHK)))
252662306a36Sopenharmony_ci			return 1; /* match with ifcc*/
252762306a36Sopenharmony_ci	}
252862306a36Sopenharmony_ci	/* check sense data; byte 0-2,25,27 */
252962306a36Sopenharmony_ci	if (!(sense1 && sense2 &&
253062306a36Sopenharmony_ci	      (memcmp(sense1, sense2, 3) == 0) &&
253162306a36Sopenharmony_ci	      (sense1[27] == sense2[27]) &&
253262306a36Sopenharmony_ci	      (sense1[25] == sense2[25]))) {
253362306a36Sopenharmony_ci
253462306a36Sopenharmony_ci		return 0;	/* sense doesn't match */
253562306a36Sopenharmony_ci	}
253662306a36Sopenharmony_ci
253762306a36Sopenharmony_ci	return 1;		/* match */
253862306a36Sopenharmony_ci
253962306a36Sopenharmony_ci}				/* end dasd_3990_erp_error_match */
254062306a36Sopenharmony_ci
254162306a36Sopenharmony_ci/*
254262306a36Sopenharmony_ci * DASD_3990_ERP_IN_ERP
254362306a36Sopenharmony_ci *
254462306a36Sopenharmony_ci * DESCRIPTION
254562306a36Sopenharmony_ci *   check if the current error already happened before.
254662306a36Sopenharmony_ci *   quick exit if current cqr is not an ERP (cqr->refers=NULL)
254762306a36Sopenharmony_ci *
254862306a36Sopenharmony_ci * PARAMETER
254962306a36Sopenharmony_ci *   cqr		failed cqr (either original cqr or already an erp)
255062306a36Sopenharmony_ci *
255162306a36Sopenharmony_ci * RETURN VALUES
255262306a36Sopenharmony_ci *   erp		erp-pointer to the already defined error
255362306a36Sopenharmony_ci *			recovery procedure OR
255462306a36Sopenharmony_ci *			NULL if a 'new' error occurred.
255562306a36Sopenharmony_ci */
255662306a36Sopenharmony_cistatic struct dasd_ccw_req *
255762306a36Sopenharmony_cidasd_3990_erp_in_erp(struct dasd_ccw_req *cqr)
255862306a36Sopenharmony_ci{
255962306a36Sopenharmony_ci
256062306a36Sopenharmony_ci	struct dasd_ccw_req *erp_head = cqr,	/* save erp chain head */
256162306a36Sopenharmony_ci	*erp_match = NULL;	/* save erp chain head */
256262306a36Sopenharmony_ci	int match = 0;		/* 'boolean' for matching error found */
256362306a36Sopenharmony_ci
256462306a36Sopenharmony_ci	if (cqr->refers == NULL) {	/* return if not in erp */
256562306a36Sopenharmony_ci		return NULL;
256662306a36Sopenharmony_ci	}
256762306a36Sopenharmony_ci
256862306a36Sopenharmony_ci	/* check the erp/cqr chain for current error */
256962306a36Sopenharmony_ci	do {
257062306a36Sopenharmony_ci		match = dasd_3990_erp_error_match(erp_head, cqr->refers);
257162306a36Sopenharmony_ci		erp_match = cqr;	/* save possible matching erp  */
257262306a36Sopenharmony_ci		cqr = cqr->refers;	/* check next erp/cqr in queue */
257362306a36Sopenharmony_ci
257462306a36Sopenharmony_ci	} while ((cqr->refers != NULL) && (!match));
257562306a36Sopenharmony_ci
257662306a36Sopenharmony_ci	if (!match) {
257762306a36Sopenharmony_ci		return NULL;	/* no match was found */
257862306a36Sopenharmony_ci	}
257962306a36Sopenharmony_ci
258062306a36Sopenharmony_ci	return erp_match;	/* return address of matching erp */
258162306a36Sopenharmony_ci
258262306a36Sopenharmony_ci}				/* END dasd_3990_erp_in_erp */
258362306a36Sopenharmony_ci
258462306a36Sopenharmony_ci/*
258562306a36Sopenharmony_ci * DASD_3990_ERP_FURTHER_ERP (24 & 32 byte sense)
258662306a36Sopenharmony_ci *
258762306a36Sopenharmony_ci * DESCRIPTION
258862306a36Sopenharmony_ci *   No retry is left for the current ERP. Check what has to be done
258962306a36Sopenharmony_ci *   with the ERP.
259062306a36Sopenharmony_ci *     - do further defined ERP action or
259162306a36Sopenharmony_ci *     - wait for interrupt or
259262306a36Sopenharmony_ci *     - exit with permanent error
259362306a36Sopenharmony_ci *
259462306a36Sopenharmony_ci * PARAMETER
259562306a36Sopenharmony_ci *   erp		ERP which is in progress with no retry left
259662306a36Sopenharmony_ci *
259762306a36Sopenharmony_ci * RETURN VALUES
259862306a36Sopenharmony_ci *   erp		modified/additional ERP
259962306a36Sopenharmony_ci */
260062306a36Sopenharmony_cistatic struct dasd_ccw_req *
260162306a36Sopenharmony_cidasd_3990_erp_further_erp(struct dasd_ccw_req *erp)
260262306a36Sopenharmony_ci{
260362306a36Sopenharmony_ci
260462306a36Sopenharmony_ci	struct dasd_device *device = erp->startdev;
260562306a36Sopenharmony_ci	char *sense = dasd_get_sense(&erp->irb);
260662306a36Sopenharmony_ci
260762306a36Sopenharmony_ci	/* check for 24 byte sense ERP */
260862306a36Sopenharmony_ci	if ((erp->function == dasd_3990_erp_bus_out) ||
260962306a36Sopenharmony_ci	    (erp->function == dasd_3990_erp_action_1) ||
261062306a36Sopenharmony_ci	    (erp->function == dasd_3990_erp_action_4)) {
261162306a36Sopenharmony_ci
261262306a36Sopenharmony_ci		erp = dasd_3990_erp_action_1(erp);
261362306a36Sopenharmony_ci
261462306a36Sopenharmony_ci	} else if (erp->function == dasd_3990_erp_action_1_sec) {
261562306a36Sopenharmony_ci		erp = dasd_3990_erp_action_1_sec(erp);
261662306a36Sopenharmony_ci	} else if (erp->function == dasd_3990_erp_action_5) {
261762306a36Sopenharmony_ci
261862306a36Sopenharmony_ci		/* retries have not been successful */
261962306a36Sopenharmony_ci		/* prepare erp for retry on different channel path */
262062306a36Sopenharmony_ci		erp = dasd_3990_erp_action_1(erp);
262162306a36Sopenharmony_ci
262262306a36Sopenharmony_ci		if (sense && !(sense[2] & DASD_SENSE_BIT_0)) {
262362306a36Sopenharmony_ci
262462306a36Sopenharmony_ci			/* issue a Diagnostic Control command with an
262562306a36Sopenharmony_ci			 * Inhibit Write subcommand */
262662306a36Sopenharmony_ci
262762306a36Sopenharmony_ci			switch (sense[25]) {
262862306a36Sopenharmony_ci			case 0x17:
262962306a36Sopenharmony_ci			case 0x57:{	/* controller */
263062306a36Sopenharmony_ci					erp = dasd_3990_erp_DCTL(erp, 0x20);
263162306a36Sopenharmony_ci					break;
263262306a36Sopenharmony_ci				}
263362306a36Sopenharmony_ci			case 0x18:
263462306a36Sopenharmony_ci			case 0x58:{	/* channel path */
263562306a36Sopenharmony_ci					erp = dasd_3990_erp_DCTL(erp, 0x40);
263662306a36Sopenharmony_ci					break;
263762306a36Sopenharmony_ci				}
263862306a36Sopenharmony_ci			case 0x19:
263962306a36Sopenharmony_ci			case 0x59:{	/* storage director */
264062306a36Sopenharmony_ci					erp = dasd_3990_erp_DCTL(erp, 0x80);
264162306a36Sopenharmony_ci					break;
264262306a36Sopenharmony_ci				}
264362306a36Sopenharmony_ci			default:
264462306a36Sopenharmony_ci				DBF_DEV_EVENT(DBF_WARNING, device,
264562306a36Sopenharmony_ci					    "invalid subcommand modifier 0x%x "
264662306a36Sopenharmony_ci					    "for Diagnostic Control Command",
264762306a36Sopenharmony_ci					    sense[25]);
264862306a36Sopenharmony_ci			}
264962306a36Sopenharmony_ci		}
265062306a36Sopenharmony_ci
265162306a36Sopenharmony_ci		/* check for 32 byte sense ERP */
265262306a36Sopenharmony_ci	} else if (sense &&
265362306a36Sopenharmony_ci		   ((erp->function == dasd_3990_erp_compound_retry) ||
265462306a36Sopenharmony_ci		    (erp->function == dasd_3990_erp_compound_path) ||
265562306a36Sopenharmony_ci		    (erp->function == dasd_3990_erp_compound_code) ||
265662306a36Sopenharmony_ci		    (erp->function == dasd_3990_erp_compound_config))) {
265762306a36Sopenharmony_ci
265862306a36Sopenharmony_ci		erp = dasd_3990_erp_compound(erp, sense);
265962306a36Sopenharmony_ci
266062306a36Sopenharmony_ci	} else {
266162306a36Sopenharmony_ci		/*
266262306a36Sopenharmony_ci		 * No retry left and no additional special handling
266362306a36Sopenharmony_ci		 * necessary
266462306a36Sopenharmony_ci		 */
266562306a36Sopenharmony_ci		dev_err(&device->cdev->dev,
266662306a36Sopenharmony_ci			"ERP %p has run out of retries and failed\n", erp);
266762306a36Sopenharmony_ci
266862306a36Sopenharmony_ci		erp->status = DASD_CQR_FAILED;
266962306a36Sopenharmony_ci	}
267062306a36Sopenharmony_ci
267162306a36Sopenharmony_ci	return erp;
267262306a36Sopenharmony_ci
267362306a36Sopenharmony_ci}				/* end dasd_3990_erp_further_erp */
267462306a36Sopenharmony_ci
267562306a36Sopenharmony_ci/*
267662306a36Sopenharmony_ci * DASD_3990_ERP_HANDLE_MATCH_ERP
267762306a36Sopenharmony_ci *
267862306a36Sopenharmony_ci * DESCRIPTION
267962306a36Sopenharmony_ci *   An error occurred again and an ERP has been detected which is already
268062306a36Sopenharmony_ci *   used to handle this error (e.g. retries).
268162306a36Sopenharmony_ci *   All prior ERP's are asumed to be successful and therefore removed
268262306a36Sopenharmony_ci *   from queue.
268362306a36Sopenharmony_ci *   If retry counter of matching erp is already 0, it is checked if further
268462306a36Sopenharmony_ci *   action is needed (besides retry) or if the ERP has failed.
268562306a36Sopenharmony_ci *
268662306a36Sopenharmony_ci * PARAMETER
268762306a36Sopenharmony_ci *   erp_head		first ERP in ERP-chain
268862306a36Sopenharmony_ci *   erp		ERP that handles the actual error.
268962306a36Sopenharmony_ci *			(matching erp)
269062306a36Sopenharmony_ci *
269162306a36Sopenharmony_ci * RETURN VALUES
269262306a36Sopenharmony_ci *   erp		modified/additional ERP
269362306a36Sopenharmony_ci */
269462306a36Sopenharmony_cistatic struct dasd_ccw_req *
269562306a36Sopenharmony_cidasd_3990_erp_handle_match_erp(struct dasd_ccw_req *erp_head,
269662306a36Sopenharmony_ci			       struct dasd_ccw_req *erp)
269762306a36Sopenharmony_ci{
269862306a36Sopenharmony_ci
269962306a36Sopenharmony_ci	struct dasd_device *device = erp_head->startdev;
270062306a36Sopenharmony_ci	struct dasd_ccw_req *erp_done = erp_head;	/* finished req */
270162306a36Sopenharmony_ci	struct dasd_ccw_req *erp_free = NULL;	/* req to be freed */
270262306a36Sopenharmony_ci
270362306a36Sopenharmony_ci	/* loop over successful ERPs and remove them from chanq */
270462306a36Sopenharmony_ci	while (erp_done != erp) {
270562306a36Sopenharmony_ci
270662306a36Sopenharmony_ci		if (erp_done == NULL)	/* end of chain reached */
270762306a36Sopenharmony_ci			panic(PRINTK_HEADER "Programming error in ERP! The "
270862306a36Sopenharmony_ci			      "original request was lost\n");
270962306a36Sopenharmony_ci
271062306a36Sopenharmony_ci		/* remove the request from the device queue */
271162306a36Sopenharmony_ci		list_del(&erp_done->blocklist);
271262306a36Sopenharmony_ci
271362306a36Sopenharmony_ci		erp_free = erp_done;
271462306a36Sopenharmony_ci		erp_done = erp_done->refers;
271562306a36Sopenharmony_ci
271662306a36Sopenharmony_ci		/* free the finished erp request */
271762306a36Sopenharmony_ci		dasd_free_erp_request(erp_free, erp_free->memdev);
271862306a36Sopenharmony_ci
271962306a36Sopenharmony_ci	}			/* end while */
272062306a36Sopenharmony_ci
272162306a36Sopenharmony_ci	if (erp->retries > 0) {
272262306a36Sopenharmony_ci
272362306a36Sopenharmony_ci		char *sense = dasd_get_sense(&erp->refers->irb);
272462306a36Sopenharmony_ci
272562306a36Sopenharmony_ci		/* check for special retries */
272662306a36Sopenharmony_ci		if (sense && erp->function == dasd_3990_erp_action_4) {
272762306a36Sopenharmony_ci
272862306a36Sopenharmony_ci			erp = dasd_3990_erp_action_4(erp, sense);
272962306a36Sopenharmony_ci
273062306a36Sopenharmony_ci		} else if (sense &&
273162306a36Sopenharmony_ci			   erp->function == dasd_3990_erp_action_1B_32) {
273262306a36Sopenharmony_ci
273362306a36Sopenharmony_ci			erp = dasd_3990_update_1B(erp, sense);
273462306a36Sopenharmony_ci
273562306a36Sopenharmony_ci		} else if (sense && erp->function == dasd_3990_erp_int_req) {
273662306a36Sopenharmony_ci
273762306a36Sopenharmony_ci			erp = dasd_3990_erp_int_req(erp);
273862306a36Sopenharmony_ci
273962306a36Sopenharmony_ci		} else {
274062306a36Sopenharmony_ci			/* simple retry	  */
274162306a36Sopenharmony_ci			DBF_DEV_EVENT(DBF_DEBUG, device,
274262306a36Sopenharmony_ci				    "%i retries left for erp %p",
274362306a36Sopenharmony_ci				    erp->retries, erp);
274462306a36Sopenharmony_ci
274562306a36Sopenharmony_ci			/* handle the request again... */
274662306a36Sopenharmony_ci			erp->status = DASD_CQR_FILLED;
274762306a36Sopenharmony_ci		}
274862306a36Sopenharmony_ci
274962306a36Sopenharmony_ci	} else {
275062306a36Sopenharmony_ci		/* no retry left - check for further necessary action	 */
275162306a36Sopenharmony_ci		/* if no further actions, handle rest as permanent error */
275262306a36Sopenharmony_ci		erp = dasd_3990_erp_further_erp(erp);
275362306a36Sopenharmony_ci	}
275462306a36Sopenharmony_ci
275562306a36Sopenharmony_ci	return erp;
275662306a36Sopenharmony_ci
275762306a36Sopenharmony_ci}				/* end dasd_3990_erp_handle_match_erp */
275862306a36Sopenharmony_ci
275962306a36Sopenharmony_ci/*
276062306a36Sopenharmony_ci * DASD_3990_ERP_ACTION
276162306a36Sopenharmony_ci *
276262306a36Sopenharmony_ci * DESCRIPTION
276362306a36Sopenharmony_ci *   control routine for 3990 erp actions.
276462306a36Sopenharmony_ci *   Has to be called with the queue lock (namely the s390_irq_lock) acquired.
276562306a36Sopenharmony_ci *
276662306a36Sopenharmony_ci * PARAMETER
276762306a36Sopenharmony_ci *   cqr		failed cqr (either original cqr or already an erp)
276862306a36Sopenharmony_ci *
276962306a36Sopenharmony_ci * RETURN VALUES
277062306a36Sopenharmony_ci *   erp		erp-pointer to the head of the ERP action chain.
277162306a36Sopenharmony_ci *			This means:
277262306a36Sopenharmony_ci *			 - either a ptr to an additional ERP cqr or
277362306a36Sopenharmony_ci *			 - the original given cqr (which's status might
277462306a36Sopenharmony_ci *			   be modified)
277562306a36Sopenharmony_ci */
277662306a36Sopenharmony_cistruct dasd_ccw_req *
277762306a36Sopenharmony_cidasd_3990_erp_action(struct dasd_ccw_req * cqr)
277862306a36Sopenharmony_ci{
277962306a36Sopenharmony_ci	struct dasd_ccw_req *erp = NULL;
278062306a36Sopenharmony_ci	struct dasd_device *device = cqr->startdev;
278162306a36Sopenharmony_ci	struct dasd_ccw_req *temp_erp = NULL;
278262306a36Sopenharmony_ci
278362306a36Sopenharmony_ci	if (device->features & DASD_FEATURE_ERPLOG) {
278462306a36Sopenharmony_ci		/* print current erp_chain */
278562306a36Sopenharmony_ci		dev_err(&device->cdev->dev,
278662306a36Sopenharmony_ci			    "ERP chain at BEGINNING of ERP-ACTION\n");
278762306a36Sopenharmony_ci		for (temp_erp = cqr;
278862306a36Sopenharmony_ci		     temp_erp != NULL; temp_erp = temp_erp->refers) {
278962306a36Sopenharmony_ci
279062306a36Sopenharmony_ci			dev_err(&device->cdev->dev,
279162306a36Sopenharmony_ci				    "ERP %p (%02x) refers to %p\n",
279262306a36Sopenharmony_ci				    temp_erp, temp_erp->status,
279362306a36Sopenharmony_ci				    temp_erp->refers);
279462306a36Sopenharmony_ci		}
279562306a36Sopenharmony_ci	}
279662306a36Sopenharmony_ci
279762306a36Sopenharmony_ci	/* double-check if current erp/cqr was successful */
279862306a36Sopenharmony_ci	if ((scsw_cstat(&cqr->irb.scsw) == 0x00) &&
279962306a36Sopenharmony_ci	    (scsw_dstat(&cqr->irb.scsw) ==
280062306a36Sopenharmony_ci	     (DEV_STAT_CHN_END | DEV_STAT_DEV_END))) {
280162306a36Sopenharmony_ci
280262306a36Sopenharmony_ci		DBF_DEV_EVENT(DBF_DEBUG, device,
280362306a36Sopenharmony_ci			    "ERP called for successful request %p"
280462306a36Sopenharmony_ci			    " - NO ERP necessary", cqr);
280562306a36Sopenharmony_ci
280662306a36Sopenharmony_ci		cqr->status = DASD_CQR_DONE;
280762306a36Sopenharmony_ci
280862306a36Sopenharmony_ci		return cqr;
280962306a36Sopenharmony_ci	}
281062306a36Sopenharmony_ci
281162306a36Sopenharmony_ci	/* check if error happened before */
281262306a36Sopenharmony_ci	erp = dasd_3990_erp_in_erp(cqr);
281362306a36Sopenharmony_ci
281462306a36Sopenharmony_ci	if (erp == NULL) {
281562306a36Sopenharmony_ci		/* no matching erp found - set up erp */
281662306a36Sopenharmony_ci		erp = dasd_3990_erp_additional_erp(cqr);
281762306a36Sopenharmony_ci		if (IS_ERR(erp))
281862306a36Sopenharmony_ci			return erp;
281962306a36Sopenharmony_ci	} else {
282062306a36Sopenharmony_ci		/* matching erp found - set all leading erp's to DONE */
282162306a36Sopenharmony_ci		erp = dasd_3990_erp_handle_match_erp(cqr, erp);
282262306a36Sopenharmony_ci	}
282362306a36Sopenharmony_ci
282462306a36Sopenharmony_ci
282562306a36Sopenharmony_ci	/*
282662306a36Sopenharmony_ci	 * For path verification work we need to stick with the path that was
282762306a36Sopenharmony_ci	 * originally chosen so that the per path configuration data is
282862306a36Sopenharmony_ci	 * assigned correctly.
282962306a36Sopenharmony_ci	 */
283062306a36Sopenharmony_ci	if (test_bit(DASD_CQR_VERIFY_PATH, &erp->flags) && cqr->lpm) {
283162306a36Sopenharmony_ci		erp->lpm = cqr->lpm;
283262306a36Sopenharmony_ci	}
283362306a36Sopenharmony_ci
283462306a36Sopenharmony_ci	if (device->features & DASD_FEATURE_ERPLOG) {
283562306a36Sopenharmony_ci		/* print current erp_chain */
283662306a36Sopenharmony_ci		dev_err(&device->cdev->dev,
283762306a36Sopenharmony_ci			    "ERP chain at END of ERP-ACTION\n");
283862306a36Sopenharmony_ci		for (temp_erp = erp;
283962306a36Sopenharmony_ci		     temp_erp != NULL; temp_erp = temp_erp->refers) {
284062306a36Sopenharmony_ci
284162306a36Sopenharmony_ci			dev_err(&device->cdev->dev,
284262306a36Sopenharmony_ci				    "ERP %p (%02x) refers to %p\n",
284362306a36Sopenharmony_ci				    temp_erp, temp_erp->status,
284462306a36Sopenharmony_ci				    temp_erp->refers);
284562306a36Sopenharmony_ci		}
284662306a36Sopenharmony_ci	}
284762306a36Sopenharmony_ci
284862306a36Sopenharmony_ci	/* enqueue ERP request if it's a new one */
284962306a36Sopenharmony_ci	if (list_empty(&erp->blocklist)) {
285062306a36Sopenharmony_ci		cqr->status = DASD_CQR_IN_ERP;
285162306a36Sopenharmony_ci		/* add erp request before the cqr */
285262306a36Sopenharmony_ci		list_add_tail(&erp->blocklist, &cqr->blocklist);
285362306a36Sopenharmony_ci	}
285462306a36Sopenharmony_ci
285562306a36Sopenharmony_ci
285662306a36Sopenharmony_ci
285762306a36Sopenharmony_ci	return erp;
285862306a36Sopenharmony_ci
285962306a36Sopenharmony_ci}				/* end dasd_3990_erp_action */
2860