File Index
Files and directories
Sign in
FILE

dasd_erp.c

File preview with syntax highlighting.

linux-6.19.14/drivers/s390/block/dasd_erp.c C
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
  4 *		    Horst Hummel <Horst.Hummel@de.ibm.com>
  5 *		    Carsten Otte <Cotte@de.ibm.com>
  6 *		    Martin Schwidefsky <schwidefsky@de.ibm.com>
  7 * Bugreports.to..: <Linux390@de.ibm.com>
  8 * Copyright IBM Corp. 1999, 2001
  9 *
 10 */
 11
 12#include <linux/export.h>
 13#include <linux/ctype.h>
 14#include <linux/init.h>
 15
 16#include <asm/debug.h>
 17#include <asm/ebcdic.h>
 18#include <linux/uaccess.h>
 19
 20#include "dasd_int.h"
 21
 22struct dasd_ccw_req *
 23dasd_alloc_erp_request(unsigned int magic, int cplength, int datasize,
 24		       struct dasd_device * device)
 25{
 26	unsigned long flags;
 27	struct dasd_ccw_req *cqr;
 28	char *data;
 29	int size;
 30
 31	/* Sanity checks */
 32	BUG_ON(datasize > PAGE_SIZE ||
 33	       (cplength*sizeof(struct ccw1)) > PAGE_SIZE);
 34
 35	size = (sizeof(struct dasd_ccw_req) + 7L) & -8L;
 36	if (cplength > 0)
 37		size += cplength * sizeof(struct ccw1);
 38	if (datasize > 0)
 39		size += datasize;
 40	spin_lock_irqsave(&device->mem_lock, flags);
 41	cqr = (struct dasd_ccw_req *)
 42		dasd_alloc_chunk(&device->erp_chunks, size);
 43	spin_unlock_irqrestore(&device->mem_lock, flags);
 44	if (cqr == NULL)
 45		return ERR_PTR(-ENOMEM);
 46	memset(cqr, 0, sizeof(struct dasd_ccw_req));
 47	INIT_LIST_HEAD(&cqr->devlist);
 48	INIT_LIST_HEAD(&cqr->blocklist);
 49	data = (char *) cqr + ((sizeof(struct dasd_ccw_req) + 7L) & -8L);
 50	cqr->cpaddr = NULL;
 51	if (cplength > 0) {
 52		cqr->cpaddr = (struct ccw1 *) data;
 53		data += cplength*sizeof(struct ccw1);
 54		memset(cqr->cpaddr, 0, cplength*sizeof(struct ccw1));
 55	}
 56	cqr->data = NULL;
 57	if (datasize > 0) {
 58		cqr->data = data;
 59 		memset(cqr->data, 0, datasize);
 60	}
 61	cqr->magic = magic;
 62	ASCEBC((char *) &cqr->magic, 4);
 63	set_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
 64	dasd_get_device(device);
 65	return cqr;
 66}
 67
 68void
 69dasd_free_erp_request(struct dasd_ccw_req *cqr, struct dasd_device * device)
 70{
 71	unsigned long flags;
 72
 73	spin_lock_irqsave(&device->mem_lock, flags);
 74	dasd_free_chunk(&device->erp_chunks, cqr);
 75	spin_unlock_irqrestore(&device->mem_lock, flags);
 76	atomic_dec(&device->ref_count);
 77}
 78
 79
 80/*
 81 * dasd_default_erp_action just retries the current cqr
 82 */
 83struct dasd_ccw_req *
 84dasd_default_erp_action(struct dasd_ccw_req *cqr)
 85{
 86	struct dasd_device *device;
 87
 88	device = cqr->startdev;
 89
 90        /* just retry - there is nothing to save ... I got no sense data.... */
 91        if (cqr->retries > 0) {
 92		DBF_DEV_EVENT(DBF_DEBUG, device,
 93                             "default ERP called (%i retries left)",
 94                             cqr->retries);
 95		if (!test_bit(DASD_CQR_VERIFY_PATH, &cqr->flags))
 96			cqr->lpm = dasd_path_get_opm(device);
 97		cqr->status = DASD_CQR_FILLED;
 98        } else {
 99		pr_err("%s: default ERP has run out of retries and failed\n",
100		       dev_name(&device->cdev->dev));
101		cqr->status = DASD_CQR_FAILED;
102		cqr->stopclk = get_tod_clock();
103        }
104        return cqr;
105}				/* end dasd_default_erp_action */
106
107/*
108 * DESCRIPTION
109 *   Frees all ERPs of the current ERP Chain and set the status
110 *   of the original CQR either to DASD_CQR_DONE if ERP was successful
111 *   or to DASD_CQR_FAILED if ERP was NOT successful.
112 *   NOTE: This function is only called if no discipline postaction
113 *	   is available
114 *
115 * PARAMETER
116 *   erp		current erp_head
117 *
118 * RETURN VALUES
119 *   cqr		pointer to the original CQR
120 */
121struct dasd_ccw_req *dasd_default_erp_postaction(struct dasd_ccw_req *cqr)
122{
123	int success;
124	unsigned long startclk, stopclk;
125	struct dasd_device *startdev;
126
127	BUG_ON(cqr->refers == NULL || cqr->function == NULL);
128
129	success = cqr->status == DASD_CQR_DONE;
130	startclk = cqr->startclk;
131	stopclk = cqr->stopclk;
132	startdev = cqr->startdev;
133
134	/* free all ERPs - but NOT the original cqr */
135	while (cqr->refers != NULL) {
136		struct dasd_ccw_req *refers;
137
138		refers = cqr->refers;
139		/* remove the request from the block queue */
140		list_del(&cqr->blocklist);
141		/* free the finished erp request */
142		dasd_free_erp_request(cqr, cqr->memdev);
143		cqr = refers;
144	}
145
146	/* set corresponding status to original cqr */
147	cqr->startclk = startclk;
148	cqr->stopclk = stopclk;
149	cqr->startdev = startdev;
150	if (success)
151		cqr->status = DASD_CQR_DONE;
152	else {
153		cqr->status = DASD_CQR_FAILED;
154		cqr->stopclk = get_tod_clock();
155	}
156
157	return cqr;
158
159}				/* end default_erp_postaction */
160
161void
162dasd_log_sense(struct dasd_ccw_req *cqr, struct irb *irb)
163{
164	struct dasd_device *device;
165
166	device = cqr->startdev;
167	if (cqr->intrc == -ETIMEDOUT) {
168		dev_err(&device->cdev->dev,
169			"A timeout error occurred for cqr %px\n", cqr);
170		return;
171	}
172	if (cqr->intrc == -ENOLINK) {
173		dev_err(&device->cdev->dev,
174			"A transport error occurred for cqr %px\n", cqr);
175		return;
176	}
177	/* dump sense data */
178	if (device->discipline && device->discipline->dump_sense)
179		device->discipline->dump_sense(device, cqr, irb);
180}
181
182void
183dasd_log_sense_dbf(struct dasd_ccw_req *cqr, struct irb *irb)
184{
185	struct dasd_device *device;
186
187	device = cqr->startdev;
188	/* dump sense data to s390 debugfeature*/
189	if (device->discipline && device->discipline->dump_sense_dbf)
190		device->discipline->dump_sense_dbf(device, irb, "log");
191}
192EXPORT_SYMBOL(dasd_log_sense_dbf);
193
194EXPORT_SYMBOL(dasd_default_erp_action);
195EXPORT_SYMBOL(dasd_default_erp_postaction);
196EXPORT_SYMBOL(dasd_alloc_erp_request);
197EXPORT_SYMBOL(dasd_free_erp_request);
198EXPORT_SYMBOL(dasd_log_sense);
199
~/ Read-only file preview.