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/config.h> 13 #include <linux/ctype.h> 14 #include <linux/init.h> 15 16 #include <asm/debug.h> 17 #include <asm/ebcdic.h> 18 #include <asm/uaccess.h> 19 20 /* This is ugly... */ 21 #define PRINTK_HEADER "dasd_erp:" 22 23 #include "dasd_int.h" 24 25 struct dasd_ccw_req * 26 dasd_alloc_erp_request(char *magic, int cplength, int datasize, 27 struct dasd_device * device) 28 { 29 unsigned long flags; 30 struct dasd_ccw_req *cqr; 31 char *data; 32 int size; 33 34 /* Sanity checks */ 35 BUG_ON( magic == NULL || datasize > PAGE_SIZE || 36 (cplength*sizeof(struct ccw1)) > PAGE_SIZE); 37 38 size = (sizeof(struct dasd_ccw_req) + 7L) & -8L; 39 if (cplength > 0) 40 size += cplength * sizeof(struct ccw1); 41 if (datasize > 0) 42 size += datasize; 43 spin_lock_irqsave(&device->mem_lock, flags); 44 cqr = (struct dasd_ccw_req *) 45 dasd_alloc_chunk(&device->erp_chunks, size); 46 spin_unlock_irqrestore(&device->mem_lock, flags); 47 if (cqr == NULL) 48 return ERR_PTR(-ENOMEM); 49 memset(cqr, 0, sizeof(struct dasd_ccw_req)); 50 data = (char *) cqr + ((sizeof(struct dasd_ccw_req) + 7L) & -8L); 51 cqr->cpaddr = NULL; 52 if (cplength > 0) { 53 cqr->cpaddr = (struct ccw1 *) data; 54 data += cplength*sizeof(struct ccw1); 55 memset(cqr->cpaddr, 0, cplength*sizeof(struct ccw1)); 56 } 57 cqr->data = NULL; 58 if (datasize > 0) { 59 cqr->data = data; 60 memset(cqr->data, 0, datasize); 61 } 62 strncpy((char *) &cqr->magic, magic, 4); 63 ASCEBC((char *) &cqr->magic, 4); 64 set_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags); 65 dasd_get_device(device); 66 return cqr; 67 } 68 69 void 70 dasd_free_erp_request(struct dasd_ccw_req * cqr, struct dasd_device * device) 71 { 72 unsigned long flags; 73 74 spin_lock_irqsave(&device->mem_lock, flags); 75 dasd_free_chunk(&device->erp_chunks, cqr); 76 spin_unlock_irqrestore(&device->mem_lock, flags); 77 atomic_dec(&device->ref_count); 78 } 79 80 81 /* 82 * dasd_default_erp_action just retries the current cqr 83 */ 84 struct dasd_ccw_req * 85 dasd_default_erp_action(struct dasd_ccw_req * cqr) 86 { 87 struct dasd_device *device; 88 89 device = cqr->device; 90 91 /* just retry - there is nothing to save ... I got no sense data.... */ 92 if (cqr->retries > 0) { 93 DEV_MESSAGE (KERN_DEBUG, device, 94 "default ERP called (%i retries left)", 95 cqr->retries); 96 cqr->lpm = LPM_ANYPATH; 97 cqr->status = DASD_CQR_QUEUED; 98 } else { 99 DEV_MESSAGE (KERN_WARNING, device, "%s", 100 "default ERP called (NO retry left)"); 101 cqr->status = DASD_CQR_FAILED; 102 cqr->stopclk = get_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 */ 121 struct dasd_ccw_req * 122 dasd_default_erp_postaction(struct dasd_ccw_req * cqr) 123 { 124 struct dasd_device *device; 125 int success; 126 127 BUG_ON(cqr->refers == NULL || cqr->function == NULL); 128 129 device = cqr->device; 130 success = cqr->status == DASD_CQR_DONE; 131 132 /* free all ERPs - but NOT the original cqr */ 133 while (cqr->refers != NULL) { 134 struct dasd_ccw_req *refers; 135 136 refers = cqr->refers; 137 /* remove the request from the device queue */ 138 list_del(&cqr->list); 139 /* free the finished erp request */ 140 dasd_free_erp_request(cqr, device); 141 cqr = refers; 142 } 143 144 /* set corresponding status to original cqr */ 145 if (success) 146 cqr->status = DASD_CQR_DONE; 147 else { 148 cqr->status = DASD_CQR_FAILED; 149 cqr->stopclk = get_clock(); 150 } 151 152 return cqr; 153 154 } /* end default_erp_postaction */ 155 156 /* 157 * Print the hex dump of the memory used by a request. This includes 158 * all error recovery ccws that have been chained in from of the 159 * real request. 160 */ 161 static inline void 162 hex_dump_memory(struct dasd_device *device, void *data, int len) 163 { 164 int *pint; 165 166 pint = (int *) data; 167 while (len > 0) { 168 DEV_MESSAGE(KERN_ERR, device, "%p: %08x %08x %08x %08x", 169 pint, pint[0], pint[1], pint[2], pint[3]); 170 pint += 4; 171 len -= 16; 172 } 173 } 174 175 void 176 dasd_log_sense(struct dasd_ccw_req *cqr, struct irb *irb) 177 { 178 struct dasd_device *device; 179 180 device = cqr->device; 181 /* dump sense data */ 182 if (device->discipline && device->discipline->dump_sense) 183 device->discipline->dump_sense(device, cqr, irb); 184 } 185 186 void 187 dasd_log_ccw(struct dasd_ccw_req * cqr, int caller, __u32 cpa) 188 { 189 struct dasd_device *device; 190 struct dasd_ccw_req *lcqr; 191 struct ccw1 *ccw; 192 int cplength; 193 194 device = cqr->device; 195 /* log the channel program */ 196 for (lcqr = cqr; lcqr != NULL; lcqr = lcqr->refers) { 197 DEV_MESSAGE(KERN_ERR, device, 198 "(%s) ERP chain report for req: %p", 199 caller == 0 ? "EXAMINE" : "ACTION", lcqr); 200 hex_dump_memory(device, lcqr, sizeof(struct dasd_ccw_req)); 201 202 cplength = 1; 203 ccw = lcqr->cpaddr; 204 while (ccw++->flags & (CCW_FLAG_DC | CCW_FLAG_CC)) 205 cplength++; 206 207 if (cplength > 40) { /* log only parts of the CP */ 208 DEV_MESSAGE(KERN_ERR, device, "%s", 209 "Start of channel program:"); 210 hex_dump_memory(device, lcqr->cpaddr, 211 40*sizeof(struct ccw1)); 212 213 DEV_MESSAGE(KERN_ERR, device, "%s", 214 "End of channel program:"); 215 hex_dump_memory(device, lcqr->cpaddr + cplength - 10, 216 10*sizeof(struct ccw1)); 217 } else { /* log the whole CP */ 218 DEV_MESSAGE(KERN_ERR, device, "%s", 219 "Channel program (complete):"); 220 hex_dump_memory(device, lcqr->cpaddr, 221 cplength*sizeof(struct ccw1)); 222 } 223 224 if (lcqr != cqr) 225 continue; 226 227 /* 228 * Log bytes arround failed CCW but only if we did 229 * not log the whole CP of the CCW is outside the 230 * logged CP. 231 */ 232 if (cplength > 40 || 233 ((addr_t) cpa < (addr_t) lcqr->cpaddr && 234 (addr_t) cpa > (addr_t) (lcqr->cpaddr + cplength + 4))) { 235 236 DEV_MESSAGE(KERN_ERR, device, 237 "Failed CCW (%p) (area):", 238 (void *) (long) cpa); 239 hex_dump_memory(device, cqr->cpaddr - 10, 240 20*sizeof(struct ccw1)); 241 } 242 } 243 244 } /* end log_erp_chain */ 245 246 EXPORT_SYMBOL(dasd_default_erp_action); 247 EXPORT_SYMBOL(dasd_default_erp_postaction); 248 EXPORT_SYMBOL(dasd_alloc_erp_request); 249 EXPORT_SYMBOL(dasd_free_erp_request); 250 EXPORT_SYMBOL(dasd_log_sense); 251 EXPORT_SYMBOL(dasd_log_ccw); 252