0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 #define KMSG_COMPONENT "dasd"
0013
0014 #include <linux/ctype.h>
0015 #include <linux/init.h>
0016
0017 #include <asm/debug.h>
0018 #include <asm/ebcdic.h>
0019 #include <linux/uaccess.h>
0020
0021
0022 #define PRINTK_HEADER "dasd_erp:"
0023
0024 #include "dasd_int.h"
0025
0026 struct dasd_ccw_req *
0027 dasd_alloc_erp_request(unsigned int magic, int cplength, int datasize,
0028 struct dasd_device * device)
0029 {
0030 unsigned long flags;
0031 struct dasd_ccw_req *cqr;
0032 char *data;
0033 int size;
0034
0035
0036 BUG_ON(datasize > PAGE_SIZE ||
0037 (cplength*sizeof(struct ccw1)) > PAGE_SIZE);
0038
0039 size = (sizeof(struct dasd_ccw_req) + 7L) & -8L;
0040 if (cplength > 0)
0041 size += cplength * sizeof(struct ccw1);
0042 if (datasize > 0)
0043 size += datasize;
0044 spin_lock_irqsave(&device->mem_lock, flags);
0045 cqr = (struct dasd_ccw_req *)
0046 dasd_alloc_chunk(&device->erp_chunks, size);
0047 spin_unlock_irqrestore(&device->mem_lock, flags);
0048 if (cqr == NULL)
0049 return ERR_PTR(-ENOMEM);
0050 memset(cqr, 0, sizeof(struct dasd_ccw_req));
0051 INIT_LIST_HEAD(&cqr->devlist);
0052 INIT_LIST_HEAD(&cqr->blocklist);
0053 data = (char *) cqr + ((sizeof(struct dasd_ccw_req) + 7L) & -8L);
0054 cqr->cpaddr = NULL;
0055 if (cplength > 0) {
0056 cqr->cpaddr = (struct ccw1 *) data;
0057 data += cplength*sizeof(struct ccw1);
0058 memset(cqr->cpaddr, 0, cplength*sizeof(struct ccw1));
0059 }
0060 cqr->data = NULL;
0061 if (datasize > 0) {
0062 cqr->data = data;
0063 memset(cqr->data, 0, datasize);
0064 }
0065 cqr->magic = magic;
0066 ASCEBC((char *) &cqr->magic, 4);
0067 set_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
0068 dasd_get_device(device);
0069 return cqr;
0070 }
0071
0072 void
0073 dasd_free_erp_request(struct dasd_ccw_req *cqr, struct dasd_device * device)
0074 {
0075 unsigned long flags;
0076
0077 spin_lock_irqsave(&device->mem_lock, flags);
0078 dasd_free_chunk(&device->erp_chunks, cqr);
0079 spin_unlock_irqrestore(&device->mem_lock, flags);
0080 atomic_dec(&device->ref_count);
0081 }
0082
0083
0084
0085
0086
0087 struct dasd_ccw_req *
0088 dasd_default_erp_action(struct dasd_ccw_req *cqr)
0089 {
0090 struct dasd_device *device;
0091
0092 device = cqr->startdev;
0093
0094
0095 if (cqr->retries > 0) {
0096 DBF_DEV_EVENT(DBF_DEBUG, device,
0097 "default ERP called (%i retries left)",
0098 cqr->retries);
0099 if (!test_bit(DASD_CQR_VERIFY_PATH, &cqr->flags))
0100 cqr->lpm = dasd_path_get_opm(device);
0101 cqr->status = DASD_CQR_FILLED;
0102 } else {
0103 pr_err("%s: default ERP has run out of retries and failed\n",
0104 dev_name(&device->cdev->dev));
0105 cqr->status = DASD_CQR_FAILED;
0106 cqr->stopclk = get_tod_clock();
0107 }
0108 return cqr;
0109 }
0110
0111
0112
0113
0114
0115
0116
0117
0118
0119
0120
0121
0122
0123
0124
0125 struct dasd_ccw_req *dasd_default_erp_postaction(struct dasd_ccw_req *cqr)
0126 {
0127 int success;
0128 unsigned long startclk, stopclk;
0129 struct dasd_device *startdev;
0130
0131 BUG_ON(cqr->refers == NULL || cqr->function == NULL);
0132
0133 success = cqr->status == DASD_CQR_DONE;
0134 startclk = cqr->startclk;
0135 stopclk = cqr->stopclk;
0136 startdev = cqr->startdev;
0137
0138
0139 while (cqr->refers != NULL) {
0140 struct dasd_ccw_req *refers;
0141
0142 refers = cqr->refers;
0143
0144 list_del(&cqr->blocklist);
0145
0146 dasd_free_erp_request(cqr, cqr->memdev);
0147 cqr = refers;
0148 }
0149
0150
0151 cqr->startclk = startclk;
0152 cqr->stopclk = stopclk;
0153 cqr->startdev = startdev;
0154 if (success)
0155 cqr->status = DASD_CQR_DONE;
0156 else {
0157 cqr->status = DASD_CQR_FAILED;
0158 cqr->stopclk = get_tod_clock();
0159 }
0160
0161 return cqr;
0162
0163 }
0164
0165 void
0166 dasd_log_sense(struct dasd_ccw_req *cqr, struct irb *irb)
0167 {
0168 struct dasd_device *device;
0169
0170 device = cqr->startdev;
0171 if (cqr->intrc == -ETIMEDOUT) {
0172 dev_err(&device->cdev->dev,
0173 "A timeout error occurred for cqr %p\n", cqr);
0174 return;
0175 }
0176 if (cqr->intrc == -ENOLINK) {
0177 dev_err(&device->cdev->dev,
0178 "A transport error occurred for cqr %p\n", cqr);
0179 return;
0180 }
0181
0182 if (device->discipline && device->discipline->dump_sense)
0183 device->discipline->dump_sense(device, cqr, irb);
0184 }
0185
0186 void
0187 dasd_log_sense_dbf(struct dasd_ccw_req *cqr, struct irb *irb)
0188 {
0189 struct dasd_device *device;
0190
0191 device = cqr->startdev;
0192
0193 if (device->discipline && device->discipline->dump_sense_dbf)
0194 device->discipline->dump_sense_dbf(device, irb, "log");
0195 }
0196 EXPORT_SYMBOL(dasd_log_sense_dbf);
0197
0198 EXPORT_SYMBOL(dasd_default_erp_action);
0199 EXPORT_SYMBOL(dasd_default_erp_postaction);
0200 EXPORT_SYMBOL(dasd_alloc_erp_request);
0201 EXPORT_SYMBOL(dasd_free_erp_request);
0202 EXPORT_SYMBOL(dasd_log_sense);
0203