1 /* 2 * File...........: linux/drivers/s390/block/dasd.c 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 * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999-2001 9 * 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 <asm/uaccess.h> 18 19 /* This is ugly... */ 20 #define PRINTK_HEADER "dasd_erp:" 21 22 #include "dasd_int.h" 23 24 struct dasd_ccw_req * 25 dasd_alloc_erp_request(char *magic, int cplength, int datasize, 26 struct dasd_device * device) 27 { 28 unsigned long flags; 29 struct dasd_ccw_req *cqr; 30 char *data; 31 int size; 32 33 /* Sanity checks */ 34 BUG_ON( magic == NULL || datasize > PAGE_SIZE || 35 (cplength*sizeof(struct ccw1)) > PAGE_SIZE); 36 37 size = (sizeof(struct dasd_ccw_req) + 7L) & -8L; 38 if (cplength > 0) 39 size += cplength * sizeof(struct ccw1); 40 if (datasize > 0) 41 size += datasize; 42 spin_lock_irqsave(&device->mem_lock, flags); 43 cqr = (struct dasd_ccw_req *) 44 dasd_alloc_chunk(&device->erp_chunks, size); 45 spin_unlock_irqrestore(&device->mem_lock, flags); 46 if (cqr == NULL) 47 return ERR_PTR(-ENOMEM); 48 memset(cqr, 0, sizeof(struct dasd_ccw_req)); 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 strncpy((char *) &cqr->magic, magic, 4); 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 68 void 69 dasd_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 */ 83 struct dasd_ccw_req * 84 dasd_default_erp_action(struct dasd_ccw_req * cqr) 85 { 86 struct dasd_device *device; 87 88 device = cqr->device; 89 90 /* just retry - there is nothing to save ... I got no sense data.... */ 91 if (cqr->retries > 0) { 92 DEV_MESSAGE (KERN_DEBUG, device, 93 "default ERP called (%i retries left)", 94 cqr->retries); 95 cqr->lpm = LPM_ANYPATH; 96 cqr->status = DASD_CQR_QUEUED; 97 } else { 98 DEV_MESSAGE (KERN_WARNING, device, "%s", 99 "default ERP called (NO retry left)"); 100 cqr->status = DASD_CQR_FAILED; 101 cqr->stopclk = get_clock (); 102 } 103 return cqr; 104 } /* end dasd_default_erp_action */ 105 106 /* 107 * DESCRIPTION 108 * Frees all ERPs of the current ERP Chain and set the status 109 * of the original CQR either to DASD_CQR_DONE if ERP was successful 110 * or to DASD_CQR_FAILED if ERP was NOT successful. 111 * NOTE: This function is only called if no discipline postaction 112 * is available 113 * 114 * PARAMETER 115 * erp current erp_head 116 * 117 * RETURN VALUES 118 * cqr pointer to the original CQR 119 */ 120 struct dasd_ccw_req * 121 dasd_default_erp_postaction(struct dasd_ccw_req * cqr) 122 { 123 struct dasd_device *device; 124 int success; 125 126 BUG_ON(cqr->refers == NULL || cqr->function == NULL); 127 128 device = cqr->device; 129 success = cqr->status == DASD_CQR_DONE; 130 131 /* free all ERPs - but NOT the original cqr */ 132 while (cqr->refers != NULL) { 133 struct dasd_ccw_req *refers; 134 135 refers = cqr->refers; 136 /* remove the request from the device queue */ 137 list_del(&cqr->list); 138 /* free the finished erp request */ 139 dasd_free_erp_request(cqr, device); 140 cqr = refers; 141 } 142 143 /* set corresponding status to original cqr */ 144 if (success) 145 cqr->status = DASD_CQR_DONE; 146 else { 147 cqr->status = DASD_CQR_FAILED; 148 cqr->stopclk = get_clock(); 149 } 150 151 return cqr; 152 153 } /* end default_erp_postaction */ 154 155 void 156 dasd_log_sense(struct dasd_ccw_req *cqr, struct irb *irb) 157 { 158 struct dasd_device *device; 159 160 device = cqr->device; 161 /* dump sense data */ 162 if (device->discipline && device->discipline->dump_sense) 163 device->discipline->dump_sense(device, cqr, irb); 164 } 165 166 EXPORT_SYMBOL(dasd_default_erp_action); 167 EXPORT_SYMBOL(dasd_default_erp_postaction); 168 EXPORT_SYMBOL(dasd_alloc_erp_request); 169 EXPORT_SYMBOL(dasd_free_erp_request); 170 EXPORT_SYMBOL(dasd_log_sense); 171