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