Commit | Line | Data |
---|---|---|
138c014d | 1 | /* |
1da177e4 | 2 | * File...........: linux/drivers/s390/block/dasd_3990_erp.c |
138c014d | 3 | * Author(s)......: Horst Hummel <Horst.Hummel@de.ibm.com> |
1da177e4 LT |
4 | * Holger Smolinski <Holger.Smolinski@de.ibm.com> |
5 | * Bugreports.to..: <Linux390@de.ibm.com> | |
6 | * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000, 2001 | |
7 | * | |
1da177e4 LT |
8 | */ |
9 | ||
10 | #include <linux/timer.h> | |
11 | #include <linux/slab.h> | |
12 | #include <asm/idals.h> | |
13 | #include <asm/todclk.h> | |
14 | ||
15 | #define PRINTK_HEADER "dasd_erp(3990): " | |
16 | ||
17 | #include "dasd_int.h" | |
18 | #include "dasd_eckd.h" | |
19 | ||
20 | ||
21 | struct DCTL_data { | |
22 | unsigned char subcommand; /* e.g Inhibit Write, Enable Write,... */ | |
23 | unsigned char modifier; /* Subcommand modifier */ | |
24 | unsigned short res; /* reserved */ | |
25 | } __attribute__ ((packed)); | |
26 | ||
27 | /* | |
138c014d | 28 | ***************************************************************************** |
1da177e4 | 29 | * SECTION ERP EXAMINATION |
138c014d | 30 | ***************************************************************************** |
1da177e4 LT |
31 | */ |
32 | ||
33 | /* | |
138c014d | 34 | * DASD_3990_ERP_EXAMINE_24 |
1da177e4 LT |
35 | * |
36 | * DESCRIPTION | |
138c014d | 37 | * Checks only for fatal (unrecoverable) error. |
1da177e4 LT |
38 | * A detailed examination of the sense data is done later outside |
39 | * the interrupt handler. | |
40 | * | |
41 | * Each bit configuration leading to an action code 2 (Exit with | |
42 | * programming error or unusual condition indication) | |
96de0e25 | 43 | * are handled as fatal errors. |
138c014d | 44 | * |
1da177e4 LT |
45 | * All other configurations are handled as recoverable errors. |
46 | * | |
47 | * RETURN VALUES | |
48 | * dasd_era_fatal for all fatal (unrecoverable errors) | |
49 | * dasd_era_recover for all others. | |
50 | */ | |
51 | static dasd_era_t | |
52 | dasd_3990_erp_examine_24(struct dasd_ccw_req * cqr, char *sense) | |
53 | { | |
54 | ||
55 | struct dasd_device *device = cqr->device; | |
56 | ||
57 | /* check for 'Command Reject' */ | |
58 | if ((sense[0] & SNS0_CMD_REJECT) && | |
59 | (!(sense[2] & SNS2_ENV_DATA_PRESENT))) { | |
60 | ||
61 | DEV_MESSAGE(KERN_ERR, device, "%s", | |
62 | "EXAMINE 24: Command Reject detected - " | |
63 | "fatal error"); | |
64 | ||
65 | return dasd_era_fatal; | |
66 | } | |
67 | ||
68 | /* check for 'Invalid Track Format' */ | |
69 | if ((sense[1] & SNS1_INV_TRACK_FORMAT) && | |
70 | (!(sense[2] & SNS2_ENV_DATA_PRESENT))) { | |
71 | ||
72 | DEV_MESSAGE(KERN_ERR, device, "%s", | |
73 | "EXAMINE 24: Invalid Track Format detected " | |
74 | "- fatal error"); | |
75 | ||
76 | return dasd_era_fatal; | |
77 | } | |
78 | ||
79 | /* check for 'No Record Found' */ | |
80 | if (sense[1] & SNS1_NO_REC_FOUND) { | |
81 | ||
82 | /* FIXME: fatal error ?!? */ | |
83 | DEV_MESSAGE(KERN_ERR, device, | |
84 | "EXAMINE 24: No Record Found detected %s", | |
85 | device->state <= DASD_STATE_BASIC ? | |
86 | " " : "- fatal error"); | |
87 | ||
88 | return dasd_era_fatal; | |
89 | } | |
90 | ||
91 | /* return recoverable for all others */ | |
92 | return dasd_era_recover; | |
93 | } /* END dasd_3990_erp_examine_24 */ | |
94 | ||
95 | /* | |
138c014d | 96 | * DASD_3990_ERP_EXAMINE_32 |
1da177e4 LT |
97 | * |
98 | * DESCRIPTION | |
138c014d | 99 | * Checks only for fatal/no/recoverable error. |
1da177e4 LT |
100 | * A detailed examination of the sense data is done later outside |
101 | * the interrupt handler. | |
102 | * | |
103 | * RETURN VALUES | |
138c014d | 104 | * dasd_era_none no error |
1da177e4 LT |
105 | * dasd_era_fatal for all fatal (unrecoverable errors) |
106 | * dasd_era_recover for recoverable others. | |
107 | */ | |
108 | static dasd_era_t | |
109 | dasd_3990_erp_examine_32(struct dasd_ccw_req * cqr, char *sense) | |
110 | { | |
111 | ||
112 | struct dasd_device *device = cqr->device; | |
113 | ||
114 | switch (sense[25]) { | |
115 | case 0x00: | |
116 | return dasd_era_none; | |
117 | ||
118 | case 0x01: | |
119 | DEV_MESSAGE(KERN_ERR, device, "%s", "EXAMINE 32: fatal error"); | |
120 | ||
121 | return dasd_era_fatal; | |
122 | ||
123 | default: | |
124 | ||
125 | return dasd_era_recover; | |
126 | } | |
127 | ||
128 | } /* end dasd_3990_erp_examine_32 */ | |
129 | ||
130 | /* | |
138c014d | 131 | * DASD_3990_ERP_EXAMINE |
1da177e4 LT |
132 | * |
133 | * DESCRIPTION | |
138c014d | 134 | * Checks only for fatal/no/recover error. |
1da177e4 LT |
135 | * A detailed examination of the sense data is done later outside |
136 | * the interrupt handler. | |
137 | * | |
138 | * The logic is based on the 'IBM 3990 Storage Control Reference' manual | |
139 | * 'Chapter 7. Error Recovery Procedures'. | |
140 | * | |
141 | * RETURN VALUES | |
138c014d | 142 | * dasd_era_none no error |
1da177e4 LT |
143 | * dasd_era_fatal for all fatal (unrecoverable errors) |
144 | * dasd_era_recover for all others. | |
145 | */ | |
146 | dasd_era_t | |
147 | dasd_3990_erp_examine(struct dasd_ccw_req * cqr, struct irb * irb) | |
148 | { | |
149 | ||
150 | char *sense = irb->ecw; | |
151 | dasd_era_t era = dasd_era_recover; | |
152 | struct dasd_device *device = cqr->device; | |
153 | ||
154 | /* check for successful execution first */ | |
155 | if (irb->scsw.cstat == 0x00 && | |
156 | irb->scsw.dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END)) | |
157 | return dasd_era_none; | |
158 | ||
159 | /* distinguish between 24 and 32 byte sense data */ | |
160 | if (sense[27] & DASD_SENSE_BIT_0) { | |
161 | ||
162 | era = dasd_3990_erp_examine_24(cqr, sense); | |
163 | ||
164 | } else { | |
165 | ||
166 | era = dasd_3990_erp_examine_32(cqr, sense); | |
167 | ||
168 | } | |
169 | ||
170 | /* log the erp chain if fatal error occurred */ | |
171 | if ((era == dasd_era_fatal) && (device->state >= DASD_STATE_READY)) { | |
172 | dasd_log_sense(cqr, irb); | |
1da177e4 LT |
173 | } |
174 | ||
175 | return era; | |
176 | ||
177 | } /* END dasd_3990_erp_examine */ | |
178 | ||
179 | /* | |
138c014d | 180 | ***************************************************************************** |
1da177e4 | 181 | * SECTION ERP HANDLING |
138c014d | 182 | ***************************************************************************** |
1da177e4 LT |
183 | */ |
184 | /* | |
138c014d | 185 | ***************************************************************************** |
1da177e4 | 186 | * 24 and 32 byte sense ERP functions |
138c014d | 187 | ***************************************************************************** |
1da177e4 LT |
188 | */ |
189 | ||
190 | /* | |
138c014d | 191 | * DASD_3990_ERP_CLEANUP |
1da177e4 LT |
192 | * |
193 | * DESCRIPTION | |
194 | * Removes the already build but not necessary ERP request and sets | |
195 | * the status of the original cqr / erp to the given (final) status | |
196 | * | |
197 | * PARAMETER | |
198 | * erp request to be blocked | |
138c014d | 199 | * final_status either DASD_CQR_DONE or DASD_CQR_FAILED |
1da177e4 LT |
200 | * |
201 | * RETURN VALUES | |
138c014d | 202 | * cqr original cqr |
1da177e4 LT |
203 | */ |
204 | static struct dasd_ccw_req * | |
205 | dasd_3990_erp_cleanup(struct dasd_ccw_req * erp, char final_status) | |
206 | { | |
207 | struct dasd_ccw_req *cqr = erp->refers; | |
208 | ||
209 | dasd_free_erp_request(erp, erp->device); | |
210 | cqr->status = final_status; | |
211 | return cqr; | |
212 | ||
213 | } /* end dasd_3990_erp_cleanup */ | |
214 | ||
215 | /* | |
138c014d | 216 | * DASD_3990_ERP_BLOCK_QUEUE |
1da177e4 LT |
217 | * |
218 | * DESCRIPTION | |
219 | * Block the given device request queue to prevent from further | |
220 | * processing until the started timer has expired or an related | |
221 | * interrupt was received. | |
222 | */ | |
223 | static void | |
224 | dasd_3990_erp_block_queue(struct dasd_ccw_req * erp, int expires) | |
225 | { | |
226 | ||
227 | struct dasd_device *device = erp->device; | |
228 | ||
229 | DEV_MESSAGE(KERN_INFO, device, | |
230 | "blocking request queue for %is", expires/HZ); | |
231 | ||
232 | device->stopped |= DASD_STOPPED_PENDING; | |
233 | erp->status = DASD_CQR_QUEUED; | |
234 | ||
235 | dasd_set_timer(device, expires); | |
236 | } | |
237 | ||
238 | /* | |
138c014d | 239 | * DASD_3990_ERP_INT_REQ |
1da177e4 LT |
240 | * |
241 | * DESCRIPTION | |
242 | * Handles 'Intervention Required' error. | |
243 | * This means either device offline or not installed. | |
244 | * | |
245 | * PARAMETER | |
246 | * erp current erp | |
247 | * RETURN VALUES | |
248 | * erp modified erp | |
249 | */ | |
250 | static struct dasd_ccw_req * | |
251 | dasd_3990_erp_int_req(struct dasd_ccw_req * erp) | |
252 | { | |
253 | ||
254 | struct dasd_device *device = erp->device; | |
255 | ||
256 | /* first time set initial retry counter and erp_function */ | |
257 | /* and retry once without blocking queue */ | |
258 | /* (this enables easier enqueing of the cqr) */ | |
259 | if (erp->function != dasd_3990_erp_int_req) { | |
260 | ||
261 | erp->retries = 256; | |
262 | erp->function = dasd_3990_erp_int_req; | |
263 | ||
264 | } else { | |
265 | ||
266 | /* issue a message and wait for 'device ready' interrupt */ | |
267 | DEV_MESSAGE(KERN_ERR, device, "%s", | |
268 | "is offline or not installed - " | |
269 | "INTERVENTION REQUIRED!!"); | |
270 | ||
271 | dasd_3990_erp_block_queue(erp, 60*HZ); | |
272 | } | |
273 | ||
274 | return erp; | |
275 | ||
276 | } /* end dasd_3990_erp_int_req */ | |
277 | ||
278 | /* | |
138c014d | 279 | * DASD_3990_ERP_ALTERNATE_PATH |
1da177e4 LT |
280 | * |
281 | * DESCRIPTION | |
282 | * Repeat the operation on a different channel path. | |
283 | * If all alternate paths have been tried, the request is posted with a | |
284 | * permanent error. | |
285 | * | |
286 | * PARAMETER | |
287 | * erp pointer to the current ERP | |
288 | * | |
289 | * RETURN VALUES | |
290 | * erp modified pointer to the ERP | |
291 | */ | |
292 | static void | |
293 | dasd_3990_erp_alternate_path(struct dasd_ccw_req * erp) | |
294 | { | |
295 | struct dasd_device *device = erp->device; | |
296 | __u8 opm; | |
297 | ||
298 | /* try alternate valid path */ | |
299 | opm = ccw_device_get_path_mask(device->cdev); | |
300 | //FIXME: start with get_opm ? | |
301 | if (erp->lpm == 0) | |
302 | erp->lpm = LPM_ANYPATH & ~(erp->irb.esw.esw0.sublog.lpum); | |
303 | else | |
304 | erp->lpm &= ~(erp->irb.esw.esw0.sublog.lpum); | |
305 | ||
306 | if ((erp->lpm & opm) != 0x00) { | |
307 | ||
308 | DEV_MESSAGE(KERN_DEBUG, device, | |
309 | "try alternate lpm=%x (lpum=%x / opm=%x)", | |
310 | erp->lpm, erp->irb.esw.esw0.sublog.lpum, opm); | |
311 | ||
312 | /* reset status to queued to handle the request again... */ | |
313 | if (erp->status > DASD_CQR_QUEUED) | |
314 | erp->status = DASD_CQR_QUEUED; | |
315 | erp->retries = 1; | |
316 | } else { | |
317 | DEV_MESSAGE(KERN_ERR, device, | |
318 | "No alternate channel path left (lpum=%x / " | |
319 | "opm=%x) -> permanent error", | |
320 | erp->irb.esw.esw0.sublog.lpum, opm); | |
321 | ||
322 | /* post request with permanent error */ | |
323 | if (erp->status > DASD_CQR_QUEUED) | |
324 | erp->status = DASD_CQR_FAILED; | |
325 | } | |
326 | } /* end dasd_3990_erp_alternate_path */ | |
327 | ||
328 | /* | |
329 | * DASD_3990_ERP_DCTL | |
330 | * | |
331 | * DESCRIPTION | |
138c014d | 332 | * Setup cqr to do the Diagnostic Control (DCTL) command with an |
1da177e4 LT |
333 | * Inhibit Write subcommand (0x20) and the given modifier. |
334 | * | |
335 | * PARAMETER | |
336 | * erp pointer to the current (failed) ERP | |
337 | * modifier subcommand modifier | |
138c014d | 338 | * |
1da177e4 | 339 | * RETURN VALUES |
138c014d | 340 | * dctl_cqr pointer to NEW dctl_cqr |
1da177e4 LT |
341 | * |
342 | */ | |
343 | static struct dasd_ccw_req * | |
344 | dasd_3990_erp_DCTL(struct dasd_ccw_req * erp, char modifier) | |
345 | { | |
346 | ||
347 | struct dasd_device *device = erp->device; | |
348 | struct DCTL_data *DCTL_data; | |
349 | struct ccw1 *ccw; | |
350 | struct dasd_ccw_req *dctl_cqr; | |
351 | ||
352 | dctl_cqr = dasd_alloc_erp_request((char *) &erp->magic, 1, | |
353 | sizeof (struct DCTL_data), | |
354 | erp->device); | |
355 | if (IS_ERR(dctl_cqr)) { | |
356 | DEV_MESSAGE(KERN_ERR, device, "%s", | |
357 | "Unable to allocate DCTL-CQR"); | |
358 | erp->status = DASD_CQR_FAILED; | |
359 | return erp; | |
360 | } | |
361 | ||
362 | DCTL_data = dctl_cqr->data; | |
363 | ||
364 | DCTL_data->subcommand = 0x02; /* Inhibit Write */ | |
365 | DCTL_data->modifier = modifier; | |
366 | ||
367 | ccw = dctl_cqr->cpaddr; | |
368 | memset(ccw, 0, sizeof (struct ccw1)); | |
369 | ccw->cmd_code = CCW_CMD_DCTL; | |
370 | ccw->count = 4; | |
371 | ccw->cda = (__u32)(addr_t) DCTL_data; | |
372 | dctl_cqr->function = dasd_3990_erp_DCTL; | |
373 | dctl_cqr->refers = erp; | |
374 | dctl_cqr->device = erp->device; | |
375 | dctl_cqr->magic = erp->magic; | |
376 | dctl_cqr->expires = 5 * 60 * HZ; | |
377 | dctl_cqr->retries = 2; | |
378 | ||
379 | dctl_cqr->buildclk = get_clock(); | |
380 | ||
381 | dctl_cqr->status = DASD_CQR_FILLED; | |
382 | ||
383 | return dctl_cqr; | |
384 | ||
385 | } /* end dasd_3990_erp_DCTL */ | |
386 | ||
387 | /* | |
138c014d | 388 | * DASD_3990_ERP_ACTION_1 |
1da177e4 LT |
389 | * |
390 | * DESCRIPTION | |
391 | * Setup ERP to do the ERP action 1 (see Reference manual). | |
392 | * Repeat the operation on a different channel path. | |
393 | * If all alternate paths have been tried, the request is posted with a | |
394 | * permanent error. | |
395 | * Note: duplex handling is not implemented (yet). | |
396 | * | |
397 | * PARAMETER | |
398 | * erp pointer to the current ERP | |
399 | * | |
400 | * RETURN VALUES | |
401 | * erp pointer to the ERP | |
402 | * | |
403 | */ | |
404 | static struct dasd_ccw_req * | |
405 | dasd_3990_erp_action_1(struct dasd_ccw_req * erp) | |
406 | { | |
407 | ||
408 | erp->function = dasd_3990_erp_action_1; | |
409 | ||
410 | dasd_3990_erp_alternate_path(erp); | |
411 | ||
412 | return erp; | |
413 | ||
414 | } /* end dasd_3990_erp_action_1 */ | |
415 | ||
416 | /* | |
138c014d | 417 | * DASD_3990_ERP_ACTION_4 |
1da177e4 LT |
418 | * |
419 | * DESCRIPTION | |
420 | * Setup ERP to do the ERP action 4 (see Reference manual). | |
421 | * Set the current request to PENDING to block the CQR queue for that device | |
422 | * until the state change interrupt appears. | |
423 | * Use a timer (20 seconds) to retry the cqr if the interrupt is still | |
424 | * missing. | |
425 | * | |
426 | * PARAMETER | |
427 | * sense sense data of the actual error | |
428 | * erp pointer to the current ERP | |
429 | * | |
430 | * RETURN VALUES | |
431 | * erp pointer to the ERP | |
432 | * | |
433 | */ | |
434 | static struct dasd_ccw_req * | |
435 | dasd_3990_erp_action_4(struct dasd_ccw_req * erp, char *sense) | |
436 | { | |
437 | ||
438 | struct dasd_device *device = erp->device; | |
439 | ||
440 | /* first time set initial retry counter and erp_function */ | |
441 | /* and retry once without waiting for state change pending */ | |
442 | /* interrupt (this enables easier enqueing of the cqr) */ | |
443 | if (erp->function != dasd_3990_erp_action_4) { | |
444 | ||
445 | DEV_MESSAGE(KERN_INFO, device, "%s", | |
446 | "dasd_3990_erp_action_4: first time retry"); | |
447 | ||
448 | erp->retries = 256; | |
449 | erp->function = dasd_3990_erp_action_4; | |
450 | ||
451 | } else { | |
452 | ||
453 | if (sense[25] == 0x1D) { /* state change pending */ | |
454 | ||
138c014d | 455 | DEV_MESSAGE(KERN_INFO, device, |
1da177e4 LT |
456 | "waiting for state change pending " |
457 | "interrupt, %d retries left", | |
458 | erp->retries); | |
138c014d | 459 | |
1da177e4 LT |
460 | dasd_3990_erp_block_queue(erp, 30*HZ); |
461 | ||
462 | } else if (sense[25] == 0x1E) { /* busy */ | |
463 | DEV_MESSAGE(KERN_INFO, device, | |
464 | "busy - redriving request later, " | |
465 | "%d retries left", | |
466 | erp->retries); | |
467 | dasd_3990_erp_block_queue(erp, HZ); | |
468 | } else { | |
469 | ||
470 | /* no state change pending - retry */ | |
138c014d | 471 | DEV_MESSAGE (KERN_INFO, device, |
1da177e4 | 472 | "redriving request immediately, " |
138c014d | 473 | "%d retries left", |
1da177e4 LT |
474 | erp->retries); |
475 | erp->status = DASD_CQR_QUEUED; | |
476 | } | |
477 | } | |
478 | ||
479 | return erp; | |
480 | ||
481 | } /* end dasd_3990_erp_action_4 */ | |
482 | ||
483 | /* | |
138c014d | 484 | ***************************************************************************** |
1da177e4 | 485 | * 24 byte sense ERP functions (only) |
138c014d | 486 | ***************************************************************************** |
1da177e4 LT |
487 | */ |
488 | ||
489 | /* | |
138c014d | 490 | * DASD_3990_ERP_ACTION_5 |
1da177e4 LT |
491 | * |
492 | * DESCRIPTION | |
493 | * Setup ERP to do the ERP action 5 (see Reference manual). | |
494 | * NOTE: Further handling is done in xxx_further_erp after the retries. | |
495 | * | |
496 | * PARAMETER | |
497 | * erp pointer to the current ERP | |
498 | * | |
499 | * RETURN VALUES | |
500 | * erp pointer to the ERP | |
501 | * | |
502 | */ | |
503 | static struct dasd_ccw_req * | |
504 | dasd_3990_erp_action_5(struct dasd_ccw_req * erp) | |
505 | { | |
506 | ||
507 | /* first of all retry */ | |
508 | erp->retries = 10; | |
509 | erp->function = dasd_3990_erp_action_5; | |
510 | ||
511 | return erp; | |
512 | ||
513 | } /* end dasd_3990_erp_action_5 */ | |
514 | ||
515 | /* | |
516 | * DASD_3990_HANDLE_ENV_DATA | |
517 | * | |
518 | * DESCRIPTION | |
519 | * Handles 24 byte 'Environmental data present'. | |
520 | * Does a analysis of the sense data (message Format) | |
521 | * and prints the error messages. | |
522 | * | |
523 | * PARAMETER | |
524 | * sense current sense data | |
138c014d | 525 | * |
1da177e4 LT |
526 | * RETURN VALUES |
527 | * void | |
528 | */ | |
529 | static void | |
530 | dasd_3990_handle_env_data(struct dasd_ccw_req * erp, char *sense) | |
531 | { | |
532 | ||
533 | struct dasd_device *device = erp->device; | |
534 | char msg_format = (sense[7] & 0xF0); | |
535 | char msg_no = (sense[7] & 0x0F); | |
536 | ||
537 | switch (msg_format) { | |
538 | case 0x00: /* Format 0 - Program or System Checks */ | |
539 | ||
540 | if (sense[1] & 0x10) { /* check message to operator bit */ | |
541 | ||
542 | switch (msg_no) { | |
543 | case 0x00: /* No Message */ | |
544 | break; | |
545 | case 0x01: | |
546 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
547 | "FORMAT 0 - Invalid Command"); | |
548 | break; | |
549 | case 0x02: | |
550 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
551 | "FORMAT 0 - Invalid Command " | |
552 | "Sequence"); | |
553 | break; | |
554 | case 0x03: | |
555 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
556 | "FORMAT 0 - CCW Count less than " | |
557 | "required"); | |
558 | break; | |
559 | case 0x04: | |
560 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
561 | "FORMAT 0 - Invalid Parameter"); | |
562 | break; | |
563 | case 0x05: | |
564 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
565 | "FORMAT 0 - Diagnostic of Sepecial" | |
566 | " Command Violates File Mask"); | |
567 | break; | |
568 | case 0x07: | |
569 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
570 | "FORMAT 0 - Channel Returned with " | |
571 | "Incorrect retry CCW"); | |
572 | break; | |
573 | case 0x08: | |
574 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
575 | "FORMAT 0 - Reset Notification"); | |
576 | break; | |
577 | case 0x09: | |
578 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
579 | "FORMAT 0 - Storage Path Restart"); | |
580 | break; | |
581 | case 0x0A: | |
582 | DEV_MESSAGE(KERN_WARNING, device, | |
583 | "FORMAT 0 - Channel requested " | |
584 | "... %02x", sense[8]); | |
585 | break; | |
586 | case 0x0B: | |
587 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
588 | "FORMAT 0 - Invalid Defective/" | |
589 | "Alternate Track Pointer"); | |
590 | break; | |
591 | case 0x0C: | |
592 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
593 | "FORMAT 0 - DPS Installation " | |
594 | "Check"); | |
595 | break; | |
596 | case 0x0E: | |
597 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
598 | "FORMAT 0 - Command Invalid on " | |
599 | "Secondary Address"); | |
600 | break; | |
601 | case 0x0F: | |
602 | DEV_MESSAGE(KERN_WARNING, device, | |
603 | "FORMAT 0 - Status Not As " | |
604 | "Required: reason %02x", sense[8]); | |
605 | break; | |
606 | default: | |
607 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
608 | "FORMAT 0 - Reseved"); | |
609 | } | |
610 | } else { | |
611 | switch (msg_no) { | |
612 | case 0x00: /* No Message */ | |
613 | break; | |
614 | case 0x01: | |
615 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
616 | "FORMAT 0 - Device Error Source"); | |
617 | break; | |
618 | case 0x02: | |
619 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
620 | "FORMAT 0 - Reserved"); | |
621 | break; | |
622 | case 0x03: | |
623 | DEV_MESSAGE(KERN_WARNING, device, | |
624 | "FORMAT 0 - Device Fenced - " | |
625 | "device = %02x", sense[4]); | |
626 | break; | |
627 | case 0x04: | |
628 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
629 | "FORMAT 0 - Data Pinned for " | |
630 | "Device"); | |
631 | break; | |
632 | default: | |
633 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
634 | "FORMAT 0 - Reserved"); | |
635 | } | |
636 | } | |
637 | break; | |
638 | ||
639 | case 0x10: /* Format 1 - Device Equipment Checks */ | |
640 | switch (msg_no) { | |
641 | case 0x00: /* No Message */ | |
642 | break; | |
643 | case 0x01: | |
644 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
645 | "FORMAT 1 - Device Status 1 not as " | |
646 | "expected"); | |
647 | break; | |
648 | case 0x03: | |
649 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
650 | "FORMAT 1 - Index missing"); | |
651 | break; | |
652 | case 0x04: | |
653 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
654 | "FORMAT 1 - Interruption cannot be reset"); | |
655 | break; | |
656 | case 0x05: | |
657 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
658 | "FORMAT 1 - Device did not respond to " | |
659 | "selection"); | |
660 | break; | |
661 | case 0x06: | |
662 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
663 | "FORMAT 1 - Device check-2 error or Set " | |
664 | "Sector is not complete"); | |
665 | break; | |
666 | case 0x07: | |
667 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
668 | "FORMAT 1 - Head address does not " | |
669 | "compare"); | |
670 | break; | |
671 | case 0x08: | |
672 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
673 | "FORMAT 1 - Device status 1 not valid"); | |
674 | break; | |
675 | case 0x09: | |
676 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
677 | "FORMAT 1 - Device not ready"); | |
678 | break; | |
679 | case 0x0A: | |
680 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
681 | "FORMAT 1 - Track physical address did " | |
682 | "not compare"); | |
683 | break; | |
684 | case 0x0B: | |
685 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
686 | "FORMAT 1 - Missing device address bit"); | |
687 | break; | |
688 | case 0x0C: | |
689 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
690 | "FORMAT 1 - Drive motor switch is off"); | |
691 | break; | |
692 | case 0x0D: | |
693 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
694 | "FORMAT 1 - Seek incomplete"); | |
695 | break; | |
696 | case 0x0E: | |
697 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
698 | "FORMAT 1 - Cylinder address did not " | |
699 | "compare"); | |
700 | break; | |
701 | case 0x0F: | |
702 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
703 | "FORMAT 1 - Offset active cannot be " | |
704 | "reset"); | |
705 | break; | |
706 | default: | |
707 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
708 | "FORMAT 1 - Reserved"); | |
709 | } | |
710 | break; | |
711 | ||
712 | case 0x20: /* Format 2 - 3990 Equipment Checks */ | |
713 | switch (msg_no) { | |
714 | case 0x08: | |
715 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
716 | "FORMAT 2 - 3990 check-2 error"); | |
717 | break; | |
718 | case 0x0E: | |
719 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
720 | "FORMAT 2 - Support facility errors"); | |
721 | break; | |
722 | case 0x0F: | |
723 | DEV_MESSAGE(KERN_WARNING, device, | |
724 | "FORMAT 2 - Microcode detected error %02x", | |
725 | sense[8]); | |
726 | break; | |
727 | default: | |
728 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
729 | "FORMAT 2 - Reserved"); | |
730 | } | |
731 | break; | |
732 | ||
733 | case 0x30: /* Format 3 - 3990 Control Checks */ | |
734 | switch (msg_no) { | |
735 | case 0x0F: | |
736 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
737 | "FORMAT 3 - Allegiance terminated"); | |
738 | break; | |
739 | default: | |
740 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
741 | "FORMAT 3 - Reserved"); | |
742 | } | |
743 | break; | |
744 | ||
745 | case 0x40: /* Format 4 - Data Checks */ | |
746 | switch (msg_no) { | |
747 | case 0x00: | |
748 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
749 | "FORMAT 4 - Home address area error"); | |
750 | break; | |
751 | case 0x01: | |
752 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
753 | "FORMAT 4 - Count area error"); | |
754 | break; | |
755 | case 0x02: | |
756 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
757 | "FORMAT 4 - Key area error"); | |
758 | break; | |
759 | case 0x03: | |
760 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
761 | "FORMAT 4 - Data area error"); | |
762 | break; | |
763 | case 0x04: | |
764 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
765 | "FORMAT 4 - No sync byte in home address " | |
766 | "area"); | |
767 | break; | |
768 | case 0x05: | |
769 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
770 | "FORMAT 4 - No sync byte in count address " | |
771 | "area"); | |
772 | break; | |
773 | case 0x06: | |
774 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
775 | "FORMAT 4 - No sync byte in key area"); | |
776 | break; | |
777 | case 0x07: | |
778 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
779 | "FORMAT 4 - No sync byte in data area"); | |
780 | break; | |
781 | case 0x08: | |
782 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
783 | "FORMAT 4 - Home address area error; " | |
784 | "offset active"); | |
785 | break; | |
786 | case 0x09: | |
787 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
788 | "FORMAT 4 - Count area error; offset " | |
789 | "active"); | |
790 | break; | |
791 | case 0x0A: | |
792 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
793 | "FORMAT 4 - Key area error; offset " | |
794 | "active"); | |
795 | break; | |
796 | case 0x0B: | |
797 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
798 | "FORMAT 4 - Data area error; " | |
799 | "offset active"); | |
800 | break; | |
801 | case 0x0C: | |
802 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
803 | "FORMAT 4 - No sync byte in home " | |
804 | "address area; offset active"); | |
805 | break; | |
806 | case 0x0D: | |
807 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
808 | "FORMAT 4 - No syn byte in count " | |
809 | "address area; offset active"); | |
810 | break; | |
811 | case 0x0E: | |
812 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
813 | "FORMAT 4 - No sync byte in key area; " | |
814 | "offset active"); | |
815 | break; | |
816 | case 0x0F: | |
817 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
818 | "FORMAT 4 - No syn byte in data area; " | |
819 | "offset active"); | |
820 | break; | |
821 | default: | |
822 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
823 | "FORMAT 4 - Reserved"); | |
824 | } | |
825 | break; | |
826 | ||
827 | case 0x50: /* Format 5 - Data Check with displacement information */ | |
828 | switch (msg_no) { | |
829 | case 0x00: | |
830 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
831 | "FORMAT 5 - Data Check in the " | |
832 | "home address area"); | |
833 | break; | |
834 | case 0x01: | |
835 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
836 | "FORMAT 5 - Data Check in the count area"); | |
837 | break; | |
838 | case 0x02: | |
839 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
840 | "FORMAT 5 - Data Check in the key area"); | |
841 | break; | |
842 | case 0x03: | |
843 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
844 | "FORMAT 5 - Data Check in the data area"); | |
845 | break; | |
846 | case 0x08: | |
847 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
848 | "FORMAT 5 - Data Check in the " | |
849 | "home address area; offset active"); | |
850 | break; | |
851 | case 0x09: | |
852 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
853 | "FORMAT 5 - Data Check in the count area; " | |
854 | "offset active"); | |
855 | break; | |
856 | case 0x0A: | |
857 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
858 | "FORMAT 5 - Data Check in the key area; " | |
859 | "offset active"); | |
860 | break; | |
861 | case 0x0B: | |
862 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
863 | "FORMAT 5 - Data Check in the data area; " | |
864 | "offset active"); | |
865 | break; | |
866 | default: | |
867 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
868 | "FORMAT 5 - Reserved"); | |
869 | } | |
870 | break; | |
871 | ||
872 | case 0x60: /* Format 6 - Usage Statistics/Overrun Errors */ | |
873 | switch (msg_no) { | |
874 | case 0x00: | |
875 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
876 | "FORMAT 6 - Overrun on channel A"); | |
877 | break; | |
878 | case 0x01: | |
879 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
880 | "FORMAT 6 - Overrun on channel B"); | |
881 | break; | |
882 | case 0x02: | |
883 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
884 | "FORMAT 6 - Overrun on channel C"); | |
885 | break; | |
886 | case 0x03: | |
887 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
888 | "FORMAT 6 - Overrun on channel D"); | |
889 | break; | |
890 | case 0x04: | |
891 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
892 | "FORMAT 6 - Overrun on channel E"); | |
893 | break; | |
894 | case 0x05: | |
895 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
896 | "FORMAT 6 - Overrun on channel F"); | |
897 | break; | |
898 | case 0x06: | |
899 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
900 | "FORMAT 6 - Overrun on channel G"); | |
901 | break; | |
902 | case 0x07: | |
903 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
904 | "FORMAT 6 - Overrun on channel H"); | |
905 | break; | |
906 | default: | |
907 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
908 | "FORMAT 6 - Reserved"); | |
909 | } | |
910 | break; | |
911 | ||
912 | case 0x70: /* Format 7 - Device Connection Control Checks */ | |
913 | switch (msg_no) { | |
914 | case 0x00: | |
915 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
916 | "FORMAT 7 - RCC initiated by a connection " | |
917 | "check alert"); | |
918 | break; | |
919 | case 0x01: | |
920 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
921 | "FORMAT 7 - RCC 1 sequence not " | |
922 | "successful"); | |
923 | break; | |
924 | case 0x02: | |
925 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
926 | "FORMAT 7 - RCC 1 and RCC 2 sequences not " | |
927 | "successful"); | |
928 | break; | |
929 | case 0x03: | |
930 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
931 | "FORMAT 7 - Invalid tag-in during " | |
932 | "selection sequence"); | |
933 | break; | |
934 | case 0x04: | |
935 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
936 | "FORMAT 7 - extra RCC required"); | |
937 | break; | |
938 | case 0x05: | |
939 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
940 | "FORMAT 7 - Invalid DCC selection " | |
941 | "response or timeout"); | |
942 | break; | |
943 | case 0x06: | |
944 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
945 | "FORMAT 7 - Missing end operation; device " | |
946 | "transfer complete"); | |
947 | break; | |
948 | case 0x07: | |
949 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
950 | "FORMAT 7 - Missing end operation; device " | |
951 | "transfer incomplete"); | |
952 | break; | |
953 | case 0x08: | |
954 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
955 | "FORMAT 7 - Invalid tag-in for an " | |
956 | "immediate command sequence"); | |
957 | break; | |
958 | case 0x09: | |
959 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
960 | "FORMAT 7 - Invalid tag-in for an " | |
961 | "extended command sequence"); | |
962 | break; | |
963 | case 0x0A: | |
964 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
965 | "FORMAT 7 - 3990 microcode time out when " | |
966 | "stopping selection"); | |
967 | break; | |
968 | case 0x0B: | |
969 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
970 | "FORMAT 7 - No response to selection " | |
971 | "after a poll interruption"); | |
972 | break; | |
973 | case 0x0C: | |
974 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
975 | "FORMAT 7 - Permanent path error (DASD " | |
976 | "controller not available)"); | |
977 | break; | |
978 | case 0x0D: | |
979 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
980 | "FORMAT 7 - DASD controller not available" | |
981 | " on disconnected command chain"); | |
982 | break; | |
983 | default: | |
984 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
985 | "FORMAT 7 - Reserved"); | |
986 | } | |
987 | break; | |
988 | ||
989 | case 0x80: /* Format 8 - Additional Device Equipment Checks */ | |
990 | switch (msg_no) { | |
991 | case 0x00: /* No Message */ | |
992 | case 0x01: | |
993 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
994 | "FORMAT 8 - Error correction code " | |
995 | "hardware fault"); | |
996 | break; | |
997 | case 0x03: | |
998 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
999 | "FORMAT 8 - Unexpected end operation " | |
1000 | "response code"); | |
1001 | break; | |
1002 | case 0x04: | |
1003 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
1004 | "FORMAT 8 - End operation with transfer " | |
1005 | "count not zero"); | |
1006 | break; | |
1007 | case 0x05: | |
1008 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
1009 | "FORMAT 8 - End operation with transfer " | |
1010 | "count zero"); | |
1011 | break; | |
1012 | case 0x06: | |
1013 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
1014 | "FORMAT 8 - DPS checks after a system " | |
1015 | "reset or selective reset"); | |
1016 | break; | |
1017 | case 0x07: | |
1018 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
1019 | "FORMAT 8 - DPS cannot be filled"); | |
1020 | break; | |
1021 | case 0x08: | |
1022 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
1023 | "FORMAT 8 - Short busy time-out during " | |
1024 | "device selection"); | |
1025 | break; | |
1026 | case 0x09: | |
1027 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
1028 | "FORMAT 8 - DASD controller failed to " | |
1029 | "set or reset the long busy latch"); | |
1030 | break; | |
1031 | case 0x0A: | |
1032 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
1033 | "FORMAT 8 - No interruption from device " | |
1034 | "during a command chain"); | |
1035 | break; | |
1036 | default: | |
1037 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
1038 | "FORMAT 8 - Reserved"); | |
1039 | } | |
1040 | break; | |
1041 | ||
1042 | case 0x90: /* Format 9 - Device Read, Write, and Seek Checks */ | |
1043 | switch (msg_no) { | |
1044 | case 0x00: | |
1045 | break; /* No Message */ | |
1046 | case 0x06: | |
1047 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
1048 | "FORMAT 9 - Device check-2 error"); | |
1049 | break; | |
1050 | case 0x07: | |
1051 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
1052 | "FORMAT 9 - Head address did not compare"); | |
1053 | break; | |
1054 | case 0x0A: | |
1055 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
1056 | "FORMAT 9 - Track physical address did " | |
1057 | "not compare while oriented"); | |
1058 | break; | |
1059 | case 0x0E: | |
1060 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
1061 | "FORMAT 9 - Cylinder address did not " | |
1062 | "compare"); | |
1063 | break; | |
1064 | default: | |
1065 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
1066 | "FORMAT 9 - Reserved"); | |
1067 | } | |
1068 | break; | |
1069 | ||
1070 | case 0xF0: /* Format F - Cache Storage Checks */ | |
1071 | switch (msg_no) { | |
1072 | case 0x00: | |
1073 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
1074 | "FORMAT F - Operation Terminated"); | |
1075 | break; | |
1076 | case 0x01: | |
1077 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
1078 | "FORMAT F - Subsystem Processing Error"); | |
1079 | break; | |
1080 | case 0x02: | |
1081 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
1082 | "FORMAT F - Cache or nonvolatile storage " | |
1083 | "equipment failure"); | |
1084 | break; | |
1085 | case 0x04: | |
1086 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
1087 | "FORMAT F - Caching terminated"); | |
1088 | break; | |
1089 | case 0x06: | |
1090 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
1091 | "FORMAT F - Cache fast write access not " | |
1092 | "authorized"); | |
1093 | break; | |
1094 | case 0x07: | |
1095 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
1096 | "FORMAT F - Track format incorrect"); | |
1097 | break; | |
1098 | case 0x09: | |
1099 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
1100 | "FORMAT F - Caching reinitiated"); | |
1101 | break; | |
1102 | case 0x0A: | |
1103 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
1104 | "FORMAT F - Nonvolatile storage " | |
1105 | "terminated"); | |
1106 | break; | |
1107 | case 0x0B: | |
1108 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
1109 | "FORMAT F - Volume is suspended duplex"); | |
20c64468 SW |
1110 | /* call extended error reporting (EER) */ |
1111 | dasd_eer_write(device, erp->refers, | |
1112 | DASD_EER_PPRCSUSPEND); | |
1da177e4 LT |
1113 | break; |
1114 | case 0x0C: | |
1115 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
1116 | "FORMAT F - Subsystem status connot be " | |
1117 | "determined"); | |
1118 | break; | |
1119 | case 0x0D: | |
1120 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
1121 | "FORMAT F - Caching status reset to " | |
1122 | "default"); | |
1123 | break; | |
1124 | case 0x0E: | |
1125 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
1126 | "FORMAT F - DASD Fast Write inhibited"); | |
1127 | break; | |
1128 | default: | |
1129 | DEV_MESSAGE(KERN_WARNING, device, "%s", | |
1130 | "FORMAT D - Reserved"); | |
1131 | } | |
1132 | break; | |
1133 | ||
1134 | default: /* unknown message format - should not happen */ | |
1135 | DEV_MESSAGE (KERN_WARNING, device, | |
1136 | "unknown message format %02x", | |
1137 | msg_format); | |
1138 | break; | |
1139 | } /* end switch message format */ | |
1140 | ||
1141 | } /* end dasd_3990_handle_env_data */ | |
1142 | ||
1143 | /* | |
1144 | * DASD_3990_ERP_COM_REJ | |
1145 | * | |
1146 | * DESCRIPTION | |
1147 | * Handles 24 byte 'Command Reject' error. | |
1148 | * | |
1149 | * PARAMETER | |
1150 | * erp current erp_head | |
1151 | * sense current sense data | |
138c014d | 1152 | * |
1da177e4 | 1153 | * RETURN VALUES |
138c014d | 1154 | * erp 'new' erp_head - pointer to new ERP |
1da177e4 LT |
1155 | */ |
1156 | static struct dasd_ccw_req * | |
1157 | dasd_3990_erp_com_rej(struct dasd_ccw_req * erp, char *sense) | |
1158 | { | |
1159 | ||
1160 | struct dasd_device *device = erp->device; | |
1161 | ||
1162 | erp->function = dasd_3990_erp_com_rej; | |
1163 | ||
1164 | /* env data present (ACTION 10 - retry should work) */ | |
1165 | if (sense[2] & SNS2_ENV_DATA_PRESENT) { | |
1166 | ||
1167 | DEV_MESSAGE(KERN_DEBUG, device, "%s", | |
1168 | "Command Reject - environmental data present"); | |
1169 | ||
1170 | dasd_3990_handle_env_data(erp, sense); | |
1171 | ||
1172 | erp->retries = 5; | |
1173 | ||
1174 | } else { | |
1175 | /* fatal error - set status to FAILED */ | |
1176 | DEV_MESSAGE(KERN_ERR, device, "%s", | |
1177 | "Command Reject - Fatal error"); | |
1178 | ||
1179 | erp = dasd_3990_erp_cleanup(erp, DASD_CQR_FAILED); | |
1180 | } | |
1181 | ||
1182 | return erp; | |
1183 | ||
1184 | } /* end dasd_3990_erp_com_rej */ | |
1185 | ||
1186 | /* | |
138c014d | 1187 | * DASD_3990_ERP_BUS_OUT |
1da177e4 LT |
1188 | * |
1189 | * DESCRIPTION | |
1190 | * Handles 24 byte 'Bus Out Parity Check' error. | |
1191 | * | |
1192 | * PARAMETER | |
1193 | * erp current erp_head | |
1194 | * RETURN VALUES | |
1195 | * erp new erp_head - pointer to new ERP | |
1196 | */ | |
1197 | static struct dasd_ccw_req * | |
1198 | dasd_3990_erp_bus_out(struct dasd_ccw_req * erp) | |
1199 | { | |
1200 | ||
1201 | struct dasd_device *device = erp->device; | |
1202 | ||
1203 | /* first time set initial retry counter and erp_function */ | |
1204 | /* and retry once without blocking queue */ | |
1205 | /* (this enables easier enqueing of the cqr) */ | |
1206 | if (erp->function != dasd_3990_erp_bus_out) { | |
1207 | erp->retries = 256; | |
1208 | erp->function = dasd_3990_erp_bus_out; | |
1209 | ||
1210 | } else { | |
1211 | ||
1212 | /* issue a message and wait for 'device ready' interrupt */ | |
1213 | DEV_MESSAGE(KERN_DEBUG, device, "%s", | |
1214 | "bus out parity error or BOPC requested by " | |
1215 | "channel"); | |
1216 | ||
1217 | dasd_3990_erp_block_queue(erp, 60*HZ); | |
1218 | ||
1219 | } | |
1220 | ||
1221 | return erp; | |
1222 | ||
1223 | } /* end dasd_3990_erp_bus_out */ | |
1224 | ||
1225 | /* | |
1226 | * DASD_3990_ERP_EQUIP_CHECK | |
1227 | * | |
1228 | * DESCRIPTION | |
1229 | * Handles 24 byte 'Equipment Check' error. | |
1230 | * | |
1231 | * PARAMETER | |
1232 | * erp current erp_head | |
1233 | * RETURN VALUES | |
1234 | * erp new erp_head - pointer to new ERP | |
1235 | */ | |
1236 | static struct dasd_ccw_req * | |
1237 | dasd_3990_erp_equip_check(struct dasd_ccw_req * erp, char *sense) | |
1238 | { | |
1239 | ||
1240 | struct dasd_device *device = erp->device; | |
1241 | ||
1242 | erp->function = dasd_3990_erp_equip_check; | |
1243 | ||
1244 | if (sense[1] & SNS1_WRITE_INHIBITED) { | |
1245 | ||
1246 | DEV_MESSAGE(KERN_DEBUG, device, "%s", | |
1247 | "Write inhibited path encountered"); | |
1248 | ||
1249 | /* vary path offline */ | |
1250 | DEV_MESSAGE(KERN_ERR, device, "%s", | |
1251 | "Path should be varied off-line. " | |
1252 | "This is not implemented yet \n - please report " | |
1253 | "to linux390@de.ibm.com"); | |
1254 | ||
1255 | erp = dasd_3990_erp_action_1(erp); | |
1256 | ||
1257 | } else if (sense[2] & SNS2_ENV_DATA_PRESENT) { | |
1258 | ||
1259 | DEV_MESSAGE(KERN_DEBUG, device, "%s", | |
1260 | "Equipment Check - " "environmental data present"); | |
1261 | ||
1262 | dasd_3990_handle_env_data(erp, sense); | |
1263 | ||
1264 | erp = dasd_3990_erp_action_4(erp, sense); | |
1265 | ||
1266 | } else if (sense[1] & SNS1_PERM_ERR) { | |
1267 | ||
1268 | DEV_MESSAGE(KERN_DEBUG, device, "%s", | |
1269 | "Equipment Check - retry exhausted or " | |
1270 | "undesirable"); | |
1271 | ||
1272 | erp = dasd_3990_erp_action_1(erp); | |
1273 | ||
1274 | } else { | |
1275 | /* all other equipment checks - Action 5 */ | |
1276 | /* rest is done when retries == 0 */ | |
1277 | DEV_MESSAGE(KERN_DEBUG, device, "%s", | |
1278 | "Equipment check or processing error"); | |
1279 | ||
1280 | erp = dasd_3990_erp_action_5(erp); | |
1281 | } | |
1282 | ||
1283 | return erp; | |
1284 | ||
1285 | } /* end dasd_3990_erp_equip_check */ | |
1286 | ||
1287 | /* | |
1288 | * DASD_3990_ERP_DATA_CHECK | |
1289 | * | |
1290 | * DESCRIPTION | |
1291 | * Handles 24 byte 'Data Check' error. | |
1292 | * | |
1293 | * PARAMETER | |
1294 | * erp current erp_head | |
1295 | * RETURN VALUES | |
1296 | * erp new erp_head - pointer to new ERP | |
1297 | */ | |
1298 | static struct dasd_ccw_req * | |
1299 | dasd_3990_erp_data_check(struct dasd_ccw_req * erp, char *sense) | |
1300 | { | |
1301 | ||
1302 | struct dasd_device *device = erp->device; | |
1303 | ||
1304 | erp->function = dasd_3990_erp_data_check; | |
1305 | ||
1306 | if (sense[2] & SNS2_CORRECTABLE) { /* correctable data check */ | |
1307 | ||
1308 | /* issue message that the data has been corrected */ | |
1309 | DEV_MESSAGE(KERN_EMERG, device, "%s", | |
1310 | "Data recovered during retry with PCI " | |
1311 | "fetch mode active"); | |
1312 | ||
1313 | /* not possible to handle this situation in Linux */ | |
1314 | panic("No way to inform application about the possibly " | |
1315 | "incorrect data"); | |
1316 | ||
1317 | } else if (sense[2] & SNS2_ENV_DATA_PRESENT) { | |
1318 | ||
1319 | DEV_MESSAGE(KERN_DEBUG, device, "%s", | |
1320 | "Uncorrectable data check recovered secondary " | |
1321 | "addr of duplex pair"); | |
1322 | ||
1323 | erp = dasd_3990_erp_action_4(erp, sense); | |
1324 | ||
1325 | } else if (sense[1] & SNS1_PERM_ERR) { | |
1326 | ||
1327 | DEV_MESSAGE(KERN_DEBUG, device, "%s", | |
1328 | "Uncorrectable data check with internal " | |
1329 | "retry exhausted"); | |
1330 | ||
1331 | erp = dasd_3990_erp_action_1(erp); | |
1332 | ||
1333 | } else { | |
1334 | /* all other data checks */ | |
1335 | DEV_MESSAGE(KERN_DEBUG, device, "%s", | |
1336 | "Uncorrectable data check with retry count " | |
1337 | "exhausted..."); | |
1338 | ||
1339 | erp = dasd_3990_erp_action_5(erp); | |
1340 | } | |
1341 | ||
1342 | return erp; | |
1343 | ||
1344 | } /* end dasd_3990_erp_data_check */ | |
1345 | ||
1346 | /* | |
1347 | * DASD_3990_ERP_OVERRUN | |
1348 | * | |
1349 | * DESCRIPTION | |
1350 | * Handles 24 byte 'Overrun' error. | |
1351 | * | |
1352 | * PARAMETER | |
1353 | * erp current erp_head | |
1354 | * RETURN VALUES | |
1355 | * erp new erp_head - pointer to new ERP | |
1356 | */ | |
1357 | static struct dasd_ccw_req * | |
1358 | dasd_3990_erp_overrun(struct dasd_ccw_req * erp, char *sense) | |
1359 | { | |
1360 | ||
1361 | struct dasd_device *device = erp->device; | |
1362 | ||
1363 | erp->function = dasd_3990_erp_overrun; | |
1364 | ||
1365 | DEV_MESSAGE(KERN_DEBUG, device, "%s", | |
1366 | "Overrun - service overrun or overrun" | |
1367 | " error requested by channel"); | |
1368 | ||
1369 | erp = dasd_3990_erp_action_5(erp); | |
1370 | ||
1371 | return erp; | |
1372 | ||
1373 | } /* end dasd_3990_erp_overrun */ | |
1374 | ||
1375 | /* | |
1376 | * DASD_3990_ERP_INV_FORMAT | |
1377 | * | |
1378 | * DESCRIPTION | |
1379 | * Handles 24 byte 'Invalid Track Format' error. | |
1380 | * | |
1381 | * PARAMETER | |
1382 | * erp current erp_head | |
1383 | * RETURN VALUES | |
1384 | * erp new erp_head - pointer to new ERP | |
1385 | */ | |
1386 | static struct dasd_ccw_req * | |
1387 | dasd_3990_erp_inv_format(struct dasd_ccw_req * erp, char *sense) | |
1388 | { | |
1389 | ||
1390 | struct dasd_device *device = erp->device; | |
1391 | ||
1392 | erp->function = dasd_3990_erp_inv_format; | |
1393 | ||
1394 | if (sense[2] & SNS2_ENV_DATA_PRESENT) { | |
1395 | ||
1396 | DEV_MESSAGE(KERN_DEBUG, device, "%s", | |
1397 | "Track format error when destaging or " | |
1398 | "staging data"); | |
1399 | ||
1400 | dasd_3990_handle_env_data(erp, sense); | |
1401 | ||
1402 | erp = dasd_3990_erp_action_4(erp, sense); | |
1403 | ||
1404 | } else { | |
1405 | DEV_MESSAGE(KERN_ERR, device, "%s", | |
1406 | "Invalid Track Format - Fatal error should have " | |
1407 | "been handled within the interrupt handler"); | |
1408 | ||
1409 | erp = dasd_3990_erp_cleanup(erp, DASD_CQR_FAILED); | |
1410 | } | |
1411 | ||
1412 | return erp; | |
1413 | ||
1414 | } /* end dasd_3990_erp_inv_format */ | |
1415 | ||
1416 | /* | |
1417 | * DASD_3990_ERP_EOC | |
1418 | * | |
1419 | * DESCRIPTION | |
1420 | * Handles 24 byte 'End-of-Cylinder' error. | |
1421 | * | |
1422 | * PARAMETER | |
1423 | * erp already added default erp | |
1424 | * RETURN VALUES | |
1425 | * erp pointer to original (failed) cqr. | |
1426 | */ | |
1427 | static struct dasd_ccw_req * | |
1428 | dasd_3990_erp_EOC(struct dasd_ccw_req * default_erp, char *sense) | |
1429 | { | |
1430 | ||
1431 | struct dasd_device *device = default_erp->device; | |
1432 | ||
1433 | DEV_MESSAGE(KERN_ERR, device, "%s", | |
1434 | "End-of-Cylinder - must never happen"); | |
1435 | ||
1436 | /* implement action 7 - BUG */ | |
1437 | return dasd_3990_erp_cleanup(default_erp, DASD_CQR_FAILED); | |
1438 | ||
1439 | } /* end dasd_3990_erp_EOC */ | |
1440 | ||
1441 | /* | |
1442 | * DASD_3990_ERP_ENV_DATA | |
1443 | * | |
1444 | * DESCRIPTION | |
1445 | * Handles 24 byte 'Environmental-Data Present' error. | |
1446 | * | |
1447 | * PARAMETER | |
1448 | * erp current erp_head | |
1449 | * RETURN VALUES | |
1450 | * erp new erp_head - pointer to new ERP | |
1451 | */ | |
1452 | static struct dasd_ccw_req * | |
1453 | dasd_3990_erp_env_data(struct dasd_ccw_req * erp, char *sense) | |
1454 | { | |
1455 | ||
1456 | struct dasd_device *device = erp->device; | |
1457 | ||
1458 | erp->function = dasd_3990_erp_env_data; | |
1459 | ||
1460 | DEV_MESSAGE(KERN_DEBUG, device, "%s", "Environmental data present"); | |
1461 | ||
1462 | dasd_3990_handle_env_data(erp, sense); | |
1463 | ||
1464 | /* don't retry on disabled interface */ | |
1465 | if (sense[7] != 0x0F) { | |
1466 | ||
1467 | erp = dasd_3990_erp_action_4(erp, sense); | |
1468 | } else { | |
1469 | ||
1470 | erp = dasd_3990_erp_cleanup(erp, DASD_CQR_IN_IO); | |
1471 | } | |
1472 | ||
1473 | return erp; | |
1474 | ||
1475 | } /* end dasd_3990_erp_env_data */ | |
1476 | ||
1477 | /* | |
1478 | * DASD_3990_ERP_NO_REC | |
1479 | * | |
1480 | * DESCRIPTION | |
1481 | * Handles 24 byte 'No Record Found' error. | |
1482 | * | |
1483 | * PARAMETER | |
1484 | * erp already added default ERP | |
138c014d | 1485 | * |
1da177e4 LT |
1486 | * RETURN VALUES |
1487 | * erp new erp_head - pointer to new ERP | |
1488 | */ | |
1489 | static struct dasd_ccw_req * | |
1490 | dasd_3990_erp_no_rec(struct dasd_ccw_req * default_erp, char *sense) | |
1491 | { | |
1492 | ||
1493 | struct dasd_device *device = default_erp->device; | |
1494 | ||
1495 | DEV_MESSAGE(KERN_ERR, device, "%s", | |
1496 | "No Record Found - Fatal error should " | |
1497 | "have been handled within the interrupt handler"); | |
1498 | ||
1499 | return dasd_3990_erp_cleanup(default_erp, DASD_CQR_FAILED); | |
1500 | ||
1501 | } /* end dasd_3990_erp_no_rec */ | |
1502 | ||
1503 | /* | |
1504 | * DASD_3990_ERP_FILE_PROT | |
1505 | * | |
1506 | * DESCRIPTION | |
1507 | * Handles 24 byte 'File Protected' error. | |
1508 | * Note: Seek related recovery is not implemented because | |
1509 | * wee don't use the seek command yet. | |
1510 | * | |
1511 | * PARAMETER | |
1512 | * erp current erp_head | |
1513 | * RETURN VALUES | |
1514 | * erp new erp_head - pointer to new ERP | |
1515 | */ | |
1516 | static struct dasd_ccw_req * | |
1517 | dasd_3990_erp_file_prot(struct dasd_ccw_req * erp) | |
1518 | { | |
1519 | ||
1520 | struct dasd_device *device = erp->device; | |
1521 | ||
1522 | DEV_MESSAGE(KERN_ERR, device, "%s", "File Protected"); | |
1523 | ||
1524 | return dasd_3990_erp_cleanup(erp, DASD_CQR_FAILED); | |
1525 | ||
1526 | } /* end dasd_3990_erp_file_prot */ | |
1527 | ||
1528 | /* | |
138c014d | 1529 | * DASD_3990_ERP_INSPECT_24 |
1da177e4 LT |
1530 | * |
1531 | * DESCRIPTION | |
1532 | * Does a detailed inspection of the 24 byte sense data | |
138c014d | 1533 | * and sets up a related error recovery action. |
1da177e4 LT |
1534 | * |
1535 | * PARAMETER | |
1536 | * sense sense data of the actual error | |
1537 | * erp pointer to the currently created default ERP | |
1538 | * | |
1539 | * RETURN VALUES | |
1540 | * erp pointer to the (addtitional) ERP | |
1541 | */ | |
1542 | static struct dasd_ccw_req * | |
1543 | dasd_3990_erp_inspect_24(struct dasd_ccw_req * erp, char *sense) | |
1544 | { | |
1545 | ||
1546 | struct dasd_ccw_req *erp_filled = NULL; | |
1547 | ||
1548 | /* Check sense for .... */ | |
1549 | /* 'Command Reject' */ | |
1550 | if ((erp_filled == NULL) && (sense[0] & SNS0_CMD_REJECT)) { | |
1551 | erp_filled = dasd_3990_erp_com_rej(erp, sense); | |
1552 | } | |
1553 | /* 'Intervention Required' */ | |
1554 | if ((erp_filled == NULL) && (sense[0] & SNS0_INTERVENTION_REQ)) { | |
1555 | erp_filled = dasd_3990_erp_int_req(erp); | |
1556 | } | |
1557 | /* 'Bus Out Parity Check' */ | |
1558 | if ((erp_filled == NULL) && (sense[0] & SNS0_BUS_OUT_CHECK)) { | |
1559 | erp_filled = dasd_3990_erp_bus_out(erp); | |
1560 | } | |
1561 | /* 'Equipment Check' */ | |
1562 | if ((erp_filled == NULL) && (sense[0] & SNS0_EQUIPMENT_CHECK)) { | |
1563 | erp_filled = dasd_3990_erp_equip_check(erp, sense); | |
1564 | } | |
1565 | /* 'Data Check' */ | |
1566 | if ((erp_filled == NULL) && (sense[0] & SNS0_DATA_CHECK)) { | |
1567 | erp_filled = dasd_3990_erp_data_check(erp, sense); | |
1568 | } | |
1569 | /* 'Overrun' */ | |
1570 | if ((erp_filled == NULL) && (sense[0] & SNS0_OVERRUN)) { | |
1571 | erp_filled = dasd_3990_erp_overrun(erp, sense); | |
1572 | } | |
1573 | /* 'Invalid Track Format' */ | |
1574 | if ((erp_filled == NULL) && (sense[1] & SNS1_INV_TRACK_FORMAT)) { | |
1575 | erp_filled = dasd_3990_erp_inv_format(erp, sense); | |
1576 | } | |
1577 | /* 'End-of-Cylinder' */ | |
1578 | if ((erp_filled == NULL) && (sense[1] & SNS1_EOC)) { | |
1579 | erp_filled = dasd_3990_erp_EOC(erp, sense); | |
1580 | } | |
1581 | /* 'Environmental Data' */ | |
1582 | if ((erp_filled == NULL) && (sense[2] & SNS2_ENV_DATA_PRESENT)) { | |
1583 | erp_filled = dasd_3990_erp_env_data(erp, sense); | |
1584 | } | |
1585 | /* 'No Record Found' */ | |
1586 | if ((erp_filled == NULL) && (sense[1] & SNS1_NO_REC_FOUND)) { | |
1587 | erp_filled = dasd_3990_erp_no_rec(erp, sense); | |
1588 | } | |
1589 | /* 'File Protected' */ | |
1590 | if ((erp_filled == NULL) && (sense[1] & SNS1_FILE_PROTECTED)) { | |
1591 | erp_filled = dasd_3990_erp_file_prot(erp); | |
1592 | } | |
1593 | /* other (unknown) error - do default ERP */ | |
1594 | if (erp_filled == NULL) { | |
1595 | ||
1596 | erp_filled = erp; | |
1597 | } | |
1598 | ||
1599 | return erp_filled; | |
1600 | ||
1601 | } /* END dasd_3990_erp_inspect_24 */ | |
1602 | ||
1603 | /* | |
138c014d | 1604 | ***************************************************************************** |
1da177e4 | 1605 | * 32 byte sense ERP functions (only) |
138c014d | 1606 | ***************************************************************************** |
1da177e4 LT |
1607 | */ |
1608 | ||
1609 | /* | |
138c014d | 1610 | * DASD_3990_ERPACTION_10_32 |
1da177e4 LT |
1611 | * |
1612 | * DESCRIPTION | |
1613 | * Handles 32 byte 'Action 10' of Single Program Action Codes. | |
1614 | * Just retry and if retry doesn't work, return with error. | |
1615 | * | |
1616 | * PARAMETER | |
1617 | * erp current erp_head | |
138c014d | 1618 | * sense current sense data |
1da177e4 LT |
1619 | * RETURN VALUES |
1620 | * erp modified erp_head | |
1621 | */ | |
1622 | static struct dasd_ccw_req * | |
1623 | dasd_3990_erp_action_10_32(struct dasd_ccw_req * erp, char *sense) | |
1624 | { | |
1625 | ||
1626 | struct dasd_device *device = erp->device; | |
1627 | ||
1628 | erp->retries = 256; | |
1629 | erp->function = dasd_3990_erp_action_10_32; | |
1630 | ||
1631 | DEV_MESSAGE(KERN_DEBUG, device, "%s", "Perform logging requested"); | |
1632 | ||
1633 | return erp; | |
1634 | ||
1635 | } /* end dasd_3990_erp_action_10_32 */ | |
1636 | ||
1637 | /* | |
1638 | * DASD_3990_ERP_ACTION_1B_32 | |
1639 | * | |
1640 | * DESCRIPTION | |
1641 | * Handles 32 byte 'Action 1B' of Single Program Action Codes. | |
138c014d | 1642 | * A write operation could not be finished because of an unexpected |
1da177e4 | 1643 | * condition. |
138c014d HH |
1644 | * The already created 'default erp' is used to get the link to |
1645 | * the erp chain, but it can not be used for this recovery | |
1da177e4 LT |
1646 | * action because it contains no DE/LO data space. |
1647 | * | |
1648 | * PARAMETER | |
1649 | * default_erp already added default erp. | |
138c014d | 1650 | * sense current sense data |
1da177e4 LT |
1651 | * |
1652 | * RETURN VALUES | |
138c014d | 1653 | * erp new erp or |
1da177e4 LT |
1654 | * default_erp in case of imprecise ending or error |
1655 | */ | |
1656 | static struct dasd_ccw_req * | |
1657 | dasd_3990_erp_action_1B_32(struct dasd_ccw_req * default_erp, char *sense) | |
1658 | { | |
1659 | ||
1660 | struct dasd_device *device = default_erp->device; | |
1661 | __u32 cpa = 0; | |
1662 | struct dasd_ccw_req *cqr; | |
1663 | struct dasd_ccw_req *erp; | |
1664 | struct DE_eckd_data *DE_data; | |
1665 | char *LO_data; /* LO_eckd_data_t */ | |
1666 | struct ccw1 *ccw; | |
1667 | ||
1668 | DEV_MESSAGE(KERN_DEBUG, device, "%s", | |
1669 | "Write not finished because of unexpected condition"); | |
1670 | ||
1671 | default_erp->function = dasd_3990_erp_action_1B_32; | |
1672 | ||
1673 | /* determine the original cqr */ | |
1674 | cqr = default_erp; | |
1675 | ||
1676 | while (cqr->refers != NULL) { | |
1677 | cqr = cqr->refers; | |
1678 | } | |
1679 | ||
1680 | /* for imprecise ending just do default erp */ | |
1681 | if (sense[1] & 0x01) { | |
1682 | ||
1683 | DEV_MESSAGE(KERN_DEBUG, device, "%s", | |
1684 | "Imprecise ending is set - just retry"); | |
1685 | ||
1686 | return default_erp; | |
1687 | } | |
1688 | ||
1689 | /* determine the address of the CCW to be restarted */ | |
1690 | /* Imprecise ending is not set -> addr from IRB-SCSW */ | |
1691 | cpa = default_erp->refers->irb.scsw.cpa; | |
1692 | ||
1693 | if (cpa == 0) { | |
1694 | ||
1695 | DEV_MESSAGE(KERN_DEBUG, device, "%s", | |
1696 | "Unable to determine address of the CCW " | |
1697 | "to be restarted"); | |
1698 | ||
1699 | return dasd_3990_erp_cleanup(default_erp, DASD_CQR_FAILED); | |
1700 | } | |
1701 | ||
1702 | /* Build new ERP request including DE/LO */ | |
1703 | erp = dasd_alloc_erp_request((char *) &cqr->magic, | |
1704 | 2 + 1,/* DE/LO + TIC */ | |
1705 | sizeof (struct DE_eckd_data) + | |
1706 | sizeof (struct LO_eckd_data), device); | |
1707 | ||
1708 | if (IS_ERR(erp)) { | |
1709 | DEV_MESSAGE(KERN_ERR, device, "%s", "Unable to allocate ERP"); | |
1710 | return dasd_3990_erp_cleanup(default_erp, DASD_CQR_FAILED); | |
1711 | } | |
1712 | ||
1713 | /* use original DE */ | |
1714 | DE_data = erp->data; | |
1715 | memcpy(DE_data, cqr->data, sizeof (struct DE_eckd_data)); | |
1716 | ||
1717 | /* create LO */ | |
1718 | LO_data = erp->data + sizeof (struct DE_eckd_data); | |
1719 | ||
1720 | if ((sense[3] == 0x01) && (LO_data[1] & 0x01)) { | |
1721 | ||
1722 | DEV_MESSAGE(KERN_ERR, device, "%s", | |
1723 | "BUG - this should not happen"); | |
1724 | ||
1725 | return dasd_3990_erp_cleanup(default_erp, DASD_CQR_FAILED); | |
1726 | } | |
1727 | ||
1728 | if ((sense[7] & 0x3F) == 0x01) { | |
1729 | /* operation code is WRITE DATA -> data area orientation */ | |
1730 | LO_data[0] = 0x81; | |
1731 | ||
1732 | } else if ((sense[7] & 0x3F) == 0x03) { | |
1733 | /* operation code is FORMAT WRITE -> index orientation */ | |
1734 | LO_data[0] = 0xC3; | |
1735 | ||
1736 | } else { | |
1737 | LO_data[0] = sense[7]; /* operation */ | |
1738 | } | |
1739 | ||
1740 | LO_data[1] = sense[8]; /* auxiliary */ | |
1741 | LO_data[2] = sense[9]; | |
1742 | LO_data[3] = sense[3]; /* count */ | |
1743 | LO_data[4] = sense[29]; /* seek_addr.cyl */ | |
1744 | LO_data[5] = sense[30]; /* seek_addr.cyl 2nd byte */ | |
1745 | LO_data[7] = sense[31]; /* seek_addr.head 2nd byte */ | |
1746 | ||
1747 | memcpy(&(LO_data[8]), &(sense[11]), 8); | |
1748 | ||
1749 | /* create DE ccw */ | |
1750 | ccw = erp->cpaddr; | |
1751 | memset(ccw, 0, sizeof (struct ccw1)); | |
1752 | ccw->cmd_code = DASD_ECKD_CCW_DEFINE_EXTENT; | |
1753 | ccw->flags = CCW_FLAG_CC; | |
1754 | ccw->count = 16; | |
1755 | ccw->cda = (__u32)(addr_t) DE_data; | |
1756 | ||
1757 | /* create LO ccw */ | |
1758 | ccw++; | |
1759 | memset(ccw, 0, sizeof (struct ccw1)); | |
1760 | ccw->cmd_code = DASD_ECKD_CCW_LOCATE_RECORD; | |
1761 | ccw->flags = CCW_FLAG_CC; | |
1762 | ccw->count = 16; | |
1763 | ccw->cda = (__u32)(addr_t) LO_data; | |
1764 | ||
1765 | /* TIC to the failed ccw */ | |
1766 | ccw++; | |
1767 | ccw->cmd_code = CCW_CMD_TIC; | |
1768 | ccw->cda = cpa; | |
1769 | ||
1770 | /* fill erp related fields */ | |
1771 | erp->function = dasd_3990_erp_action_1B_32; | |
1772 | erp->refers = default_erp->refers; | |
1773 | erp->device = device; | |
1774 | erp->magic = default_erp->magic; | |
1775 | erp->expires = 0; | |
1776 | erp->retries = 256; | |
1777 | erp->buildclk = get_clock(); | |
1778 | erp->status = DASD_CQR_FILLED; | |
1779 | ||
1780 | /* remove the default erp */ | |
1781 | dasd_free_erp_request(default_erp, device); | |
1782 | ||
1783 | return erp; | |
1784 | ||
1785 | } /* end dasd_3990_erp_action_1B_32 */ | |
1786 | ||
1787 | /* | |
1788 | * DASD_3990_UPDATE_1B | |
1789 | * | |
1790 | * DESCRIPTION | |
138c014d | 1791 | * Handles the update to the 32 byte 'Action 1B' of Single Program |
1da177e4 LT |
1792 | * Action Codes in case the first action was not successful. |
1793 | * The already created 'previous_erp' is the currently not successful | |
138c014d | 1794 | * ERP. |
1da177e4 LT |
1795 | * |
1796 | * PARAMETER | |
1797 | * previous_erp already created previous erp. | |
138c014d | 1798 | * sense current sense data |
1da177e4 | 1799 | * RETURN VALUES |
138c014d | 1800 | * erp modified erp |
1da177e4 LT |
1801 | */ |
1802 | static struct dasd_ccw_req * | |
1803 | dasd_3990_update_1B(struct dasd_ccw_req * previous_erp, char *sense) | |
1804 | { | |
1805 | ||
1806 | struct dasd_device *device = previous_erp->device; | |
1807 | __u32 cpa = 0; | |
1808 | struct dasd_ccw_req *cqr; | |
1809 | struct dasd_ccw_req *erp; | |
1810 | char *LO_data; /* struct LO_eckd_data */ | |
1811 | struct ccw1 *ccw; | |
1812 | ||
1813 | DEV_MESSAGE(KERN_DEBUG, device, "%s", | |
1814 | "Write not finished because of unexpected condition" | |
1815 | " - follow on"); | |
1816 | ||
1817 | /* determine the original cqr */ | |
1818 | cqr = previous_erp; | |
1819 | ||
1820 | while (cqr->refers != NULL) { | |
1821 | cqr = cqr->refers; | |
1822 | } | |
1823 | ||
1824 | /* for imprecise ending just do default erp */ | |
1825 | if (sense[1] & 0x01) { | |
1826 | ||
1827 | DEV_MESSAGE(KERN_DEBUG, device, "%s", | |
1828 | "Imprecise ending is set - just retry"); | |
1829 | ||
1830 | previous_erp->status = DASD_CQR_QUEUED; | |
1831 | ||
1832 | return previous_erp; | |
1833 | } | |
1834 | ||
1835 | /* determine the address of the CCW to be restarted */ | |
1836 | /* Imprecise ending is not set -> addr from IRB-SCSW */ | |
1837 | cpa = previous_erp->irb.scsw.cpa; | |
1838 | ||
1839 | if (cpa == 0) { | |
1840 | ||
1841 | DEV_MESSAGE(KERN_DEBUG, device, "%s", | |
1842 | "Unable to determine address of the CCW " | |
1843 | "to be restarted"); | |
1844 | ||
1845 | previous_erp->status = DASD_CQR_FAILED; | |
1846 | ||
1847 | return previous_erp; | |
1848 | } | |
1849 | ||
1850 | erp = previous_erp; | |
1851 | ||
1852 | /* update the LO with the new returned sense data */ | |
1853 | LO_data = erp->data + sizeof (struct DE_eckd_data); | |
1854 | ||
1855 | if ((sense[3] == 0x01) && (LO_data[1] & 0x01)) { | |
1856 | ||
1857 | DEV_MESSAGE(KERN_ERR, device, "%s", | |
1858 | "BUG - this should not happen"); | |
1859 | ||
1860 | previous_erp->status = DASD_CQR_FAILED; | |
1861 | ||
1862 | return previous_erp; | |
1863 | } | |
1864 | ||
1865 | if ((sense[7] & 0x3F) == 0x01) { | |
1866 | /* operation code is WRITE DATA -> data area orientation */ | |
1867 | LO_data[0] = 0x81; | |
1868 | ||
1869 | } else if ((sense[7] & 0x3F) == 0x03) { | |
1870 | /* operation code is FORMAT WRITE -> index orientation */ | |
1871 | LO_data[0] = 0xC3; | |
1872 | ||
1873 | } else { | |
1874 | LO_data[0] = sense[7]; /* operation */ | |
1875 | } | |
1876 | ||
1877 | LO_data[1] = sense[8]; /* auxiliary */ | |
1878 | LO_data[2] = sense[9]; | |
1879 | LO_data[3] = sense[3]; /* count */ | |
1880 | LO_data[4] = sense[29]; /* seek_addr.cyl */ | |
1881 | LO_data[5] = sense[30]; /* seek_addr.cyl 2nd byte */ | |
1882 | LO_data[7] = sense[31]; /* seek_addr.head 2nd byte */ | |
1883 | ||
1884 | memcpy(&(LO_data[8]), &(sense[11]), 8); | |
1885 | ||
1886 | /* TIC to the failed ccw */ | |
1887 | ccw = erp->cpaddr; /* addr of DE ccw */ | |
1888 | ccw++; /* addr of LE ccw */ | |
1889 | ccw++; /* addr of TIC ccw */ | |
1890 | ccw->cda = cpa; | |
1891 | ||
1892 | erp->status = DASD_CQR_QUEUED; | |
1893 | ||
1894 | return erp; | |
1895 | ||
1896 | } /* end dasd_3990_update_1B */ | |
1897 | ||
1898 | /* | |
138c014d | 1899 | * DASD_3990_ERP_COMPOUND_RETRY |
1da177e4 LT |
1900 | * |
1901 | * DESCRIPTION | |
1902 | * Handles the compound ERP action retry code. | |
1903 | * NOTE: At least one retry is done even if zero is specified | |
1904 | * by the sense data. This makes enqueueing of the request | |
1905 | * easier. | |
1906 | * | |
1907 | * PARAMETER | |
1908 | * sense sense data of the actual error | |
1909 | * erp pointer to the currently created ERP | |
1910 | * | |
1911 | * RETURN VALUES | |
1912 | * erp modified ERP pointer | |
1913 | * | |
1914 | */ | |
1915 | static void | |
1916 | dasd_3990_erp_compound_retry(struct dasd_ccw_req * erp, char *sense) | |
1917 | { | |
1918 | ||
1919 | switch (sense[25] & 0x03) { | |
1920 | case 0x00: /* no not retry */ | |
1921 | erp->retries = 1; | |
1922 | break; | |
1923 | ||
1924 | case 0x01: /* retry 2 times */ | |
1925 | erp->retries = 2; | |
1926 | break; | |
1927 | ||
1928 | case 0x02: /* retry 10 times */ | |
1929 | erp->retries = 10; | |
1930 | break; | |
1931 | ||
1932 | case 0x03: /* retry 256 times */ | |
1933 | erp->retries = 256; | |
1934 | break; | |
1935 | ||
1936 | default: | |
1937 | BUG(); | |
1938 | } | |
1939 | ||
1940 | erp->function = dasd_3990_erp_compound_retry; | |
1941 | ||
1942 | } /* end dasd_3990_erp_compound_retry */ | |
1943 | ||
1944 | /* | |
138c014d | 1945 | * DASD_3990_ERP_COMPOUND_PATH |
1da177e4 LT |
1946 | * |
1947 | * DESCRIPTION | |
1948 | * Handles the compound ERP action for retry on alternate | |
1949 | * channel path. | |
1950 | * | |
1951 | * PARAMETER | |
1952 | * sense sense data of the actual error | |
1953 | * erp pointer to the currently created ERP | |
1954 | * | |
1955 | * RETURN VALUES | |
1956 | * erp modified ERP pointer | |
1957 | * | |
1958 | */ | |
1959 | static void | |
1960 | dasd_3990_erp_compound_path(struct dasd_ccw_req * erp, char *sense) | |
1961 | { | |
1962 | ||
1963 | if (sense[25] & DASD_SENSE_BIT_3) { | |
1964 | dasd_3990_erp_alternate_path(erp); | |
1965 | ||
1966 | if (erp->status == DASD_CQR_FAILED) { | |
138c014d | 1967 | /* reset the lpm and the status to be able to |
1da177e4 LT |
1968 | * try further actions. */ |
1969 | ||
1970 | erp->lpm = 0; | |
1971 | ||
1972 | erp->status = DASD_CQR_ERROR; | |
1973 | ||
1974 | } | |
1975 | } | |
1976 | ||
1977 | erp->function = dasd_3990_erp_compound_path; | |
1978 | ||
1979 | } /* end dasd_3990_erp_compound_path */ | |
1980 | ||
1981 | /* | |
138c014d | 1982 | * DASD_3990_ERP_COMPOUND_CODE |
1da177e4 LT |
1983 | * |
1984 | * DESCRIPTION | |
1985 | * Handles the compound ERP action for retry code. | |
1986 | * | |
1987 | * PARAMETER | |
1988 | * sense sense data of the actual error | |
1989 | * erp pointer to the currently created ERP | |
1990 | * | |
1991 | * RETURN VALUES | |
1992 | * erp NEW ERP pointer | |
1993 | * | |
1994 | */ | |
1995 | static struct dasd_ccw_req * | |
1996 | dasd_3990_erp_compound_code(struct dasd_ccw_req * erp, char *sense) | |
1997 | { | |
1998 | ||
1999 | if (sense[25] & DASD_SENSE_BIT_2) { | |
2000 | ||
2001 | switch (sense[28]) { | |
2002 | case 0x17: | |
138c014d | 2003 | /* issue a Diagnostic Control command with an |
3a4fa0a2 | 2004 | * Inhibit Write subcommand and controller modifier */ |
1da177e4 LT |
2005 | erp = dasd_3990_erp_DCTL(erp, 0x20); |
2006 | break; | |
138c014d | 2007 | |
1da177e4 LT |
2008 | case 0x25: |
2009 | /* wait for 5 seconds and retry again */ | |
2010 | erp->retries = 1; | |
138c014d | 2011 | |
1da177e4 LT |
2012 | dasd_3990_erp_block_queue (erp, 5*HZ); |
2013 | break; | |
138c014d | 2014 | |
1da177e4 LT |
2015 | default: |
2016 | /* should not happen - continue */ | |
2017 | break; | |
2018 | } | |
2019 | } | |
2020 | ||
2021 | erp->function = dasd_3990_erp_compound_code; | |
2022 | ||
2023 | return erp; | |
2024 | ||
2025 | } /* end dasd_3990_erp_compound_code */ | |
2026 | ||
2027 | /* | |
138c014d | 2028 | * DASD_3990_ERP_COMPOUND_CONFIG |
1da177e4 LT |
2029 | * |
2030 | * DESCRIPTION | |
2031 | * Handles the compound ERP action for configruation | |
2032 | * dependent error. | |
2033 | * Note: duplex handling is not implemented (yet). | |
2034 | * | |
2035 | * PARAMETER | |
2036 | * sense sense data of the actual error | |
2037 | * erp pointer to the currently created ERP | |
2038 | * | |
2039 | * RETURN VALUES | |
2040 | * erp modified ERP pointer | |
2041 | * | |
2042 | */ | |
2043 | static void | |
2044 | dasd_3990_erp_compound_config(struct dasd_ccw_req * erp, char *sense) | |
2045 | { | |
2046 | ||
2047 | if ((sense[25] & DASD_SENSE_BIT_1) && (sense[26] & DASD_SENSE_BIT_2)) { | |
2048 | ||
2049 | /* set to suspended duplex state then restart */ | |
2050 | struct dasd_device *device = erp->device; | |
2051 | ||
2052 | DEV_MESSAGE(KERN_ERR, device, "%s", | |
2053 | "Set device to suspended duplex state should be " | |
2054 | "done!\n" | |
2055 | "This is not implemented yet (for compound ERP)" | |
2056 | " - please report to linux390@de.ibm.com"); | |
2057 | ||
2058 | } | |
2059 | ||
2060 | erp->function = dasd_3990_erp_compound_config; | |
2061 | ||
2062 | } /* end dasd_3990_erp_compound_config */ | |
2063 | ||
2064 | /* | |
138c014d | 2065 | * DASD_3990_ERP_COMPOUND |
1da177e4 LT |
2066 | * |
2067 | * DESCRIPTION | |
138c014d | 2068 | * Does the further compound program action if |
1da177e4 LT |
2069 | * compound retry was not successful. |
2070 | * | |
2071 | * PARAMETER | |
2072 | * sense sense data of the actual error | |
2073 | * erp pointer to the current (failed) ERP | |
2074 | * | |
2075 | * RETURN VALUES | |
2076 | * erp (additional) ERP pointer | |
2077 | * | |
2078 | */ | |
2079 | static struct dasd_ccw_req * | |
2080 | dasd_3990_erp_compound(struct dasd_ccw_req * erp, char *sense) | |
2081 | { | |
2082 | ||
2083 | if ((erp->function == dasd_3990_erp_compound_retry) && | |
2084 | (erp->status == DASD_CQR_ERROR)) { | |
2085 | ||
2086 | dasd_3990_erp_compound_path(erp, sense); | |
2087 | } | |
2088 | ||
2089 | if ((erp->function == dasd_3990_erp_compound_path) && | |
2090 | (erp->status == DASD_CQR_ERROR)) { | |
2091 | ||
2092 | erp = dasd_3990_erp_compound_code(erp, sense); | |
2093 | } | |
2094 | ||
2095 | if ((erp->function == dasd_3990_erp_compound_code) && | |
2096 | (erp->status == DASD_CQR_ERROR)) { | |
2097 | ||
2098 | dasd_3990_erp_compound_config(erp, sense); | |
2099 | } | |
2100 | ||
2101 | /* if no compound action ERP specified, the request failed */ | |
2102 | if (erp->status == DASD_CQR_ERROR) { | |
2103 | ||
2104 | erp->status = DASD_CQR_FAILED; | |
2105 | } | |
2106 | ||
2107 | return erp; | |
2108 | ||
2109 | } /* end dasd_3990_erp_compound */ | |
2110 | ||
2111 | /* | |
138c014d | 2112 | * DASD_3990_ERP_INSPECT_32 |
1da177e4 LT |
2113 | * |
2114 | * DESCRIPTION | |
2115 | * Does a detailed inspection of the 32 byte sense data | |
138c014d | 2116 | * and sets up a related error recovery action. |
1da177e4 LT |
2117 | * |
2118 | * PARAMETER | |
2119 | * sense sense data of the actual error | |
2120 | * erp pointer to the currently created default ERP | |
2121 | * | |
2122 | * RETURN VALUES | |
2123 | * erp_filled pointer to the ERP | |
2124 | * | |
2125 | */ | |
2126 | static struct dasd_ccw_req * | |
2127 | dasd_3990_erp_inspect_32(struct dasd_ccw_req * erp, char *sense) | |
2128 | { | |
2129 | ||
2130 | struct dasd_device *device = erp->device; | |
2131 | ||
2132 | erp->function = dasd_3990_erp_inspect_32; | |
2133 | ||
2134 | if (sense[25] & DASD_SENSE_BIT_0) { | |
2135 | ||
2136 | /* compound program action codes (byte25 bit 0 == '1') */ | |
2137 | dasd_3990_erp_compound_retry(erp, sense); | |
2138 | ||
2139 | } else { | |
2140 | ||
2141 | /* single program action codes (byte25 bit 0 == '0') */ | |
2142 | switch (sense[25]) { | |
2143 | ||
2144 | case 0x00: /* success - use default ERP for retries */ | |
2145 | DEV_MESSAGE(KERN_DEBUG, device, "%s", | |
2146 | "ERP called for successful request" | |
2147 | " - just retry"); | |
2148 | break; | |
2149 | ||
2150 | case 0x01: /* fatal error */ | |
2151 | DEV_MESSAGE(KERN_ERR, device, "%s", | |
2152 | "Fatal error should have been " | |
2153 | "handled within the interrupt handler"); | |
2154 | ||
2155 | erp = dasd_3990_erp_cleanup(erp, DASD_CQR_FAILED); | |
2156 | break; | |
2157 | ||
2158 | case 0x02: /* intervention required */ | |
2159 | case 0x03: /* intervention required during dual copy */ | |
2160 | erp = dasd_3990_erp_int_req(erp); | |
2161 | break; | |
2162 | ||
2163 | case 0x0F: /* length mismatch during update write command */ | |
2164 | DEV_MESSAGE(KERN_ERR, device, "%s", | |
2165 | "update write command error - should not " | |
2166 | "happen;\n" | |
2167 | "Please send this message together with " | |
2168 | "the above sense data to linux390@de." | |
2169 | "ibm.com"); | |
2170 | ||
2171 | erp = dasd_3990_erp_cleanup(erp, DASD_CQR_FAILED); | |
2172 | break; | |
2173 | ||
2174 | case 0x10: /* logging required for other channel program */ | |
2175 | erp = dasd_3990_erp_action_10_32(erp, sense); | |
2176 | break; | |
2177 | ||
2178 | case 0x15: /* next track outside defined extend */ | |
2179 | DEV_MESSAGE(KERN_ERR, device, "%s", | |
2180 | "next track outside defined extend - " | |
2181 | "should not happen;\n" | |
2182 | "Please send this message together with " | |
2183 | "the above sense data to linux390@de." | |
2184 | "ibm.com"); | |
2185 | ||
2186 | erp = dasd_3990_erp_cleanup(erp, DASD_CQR_FAILED); | |
2187 | break; | |
2188 | ||
2189 | case 0x1B: /* unexpected condition during write */ | |
2190 | ||
2191 | erp = dasd_3990_erp_action_1B_32(erp, sense); | |
2192 | break; | |
2193 | ||
2194 | case 0x1C: /* invalid data */ | |
2195 | DEV_MESSAGE(KERN_EMERG, device, "%s", | |
2196 | "Data recovered during retry with PCI " | |
2197 | "fetch mode active"); | |
2198 | ||
2199 | /* not possible to handle this situation in Linux */ | |
2200 | panic | |
2201 | ("Invalid data - No way to inform application " | |
2202 | "about the possibly incorrect data"); | |
2203 | break; | |
2204 | ||
2205 | case 0x1D: /* state-change pending */ | |
2206 | DEV_MESSAGE(KERN_DEBUG, device, "%s", | |
2207 | "A State change pending condition exists " | |
2208 | "for the subsystem or device"); | |
2209 | ||
2210 | erp = dasd_3990_erp_action_4(erp, sense); | |
2211 | break; | |
2212 | ||
2213 | case 0x1E: /* busy */ | |
2214 | DEV_MESSAGE(KERN_DEBUG, device, "%s", | |
2215 | "Busy condition exists " | |
2216 | "for the subsystem or device"); | |
2217 | erp = dasd_3990_erp_action_4(erp, sense); | |
2218 | break; | |
2219 | ||
2220 | default: /* all others errors - default erp */ | |
2221 | break; | |
2222 | } | |
2223 | } | |
2224 | ||
2225 | return erp; | |
2226 | ||
2227 | } /* end dasd_3990_erp_inspect_32 */ | |
2228 | ||
2229 | /* | |
138c014d | 2230 | ***************************************************************************** |
1da177e4 | 2231 | * main ERP control fuctions (24 and 32 byte sense) |
138c014d | 2232 | ***************************************************************************** |
1da177e4 LT |
2233 | */ |
2234 | ||
2235 | /* | |
2236 | * DASD_3990_ERP_INSPECT | |
2237 | * | |
2238 | * DESCRIPTION | |
2239 | * Does a detailed inspection for sense data by calling either | |
2240 | * the 24-byte or the 32-byte inspection routine. | |
2241 | * | |
2242 | * PARAMETER | |
2243 | * erp pointer to the currently created default ERP | |
2244 | * RETURN VALUES | |
138c014d | 2245 | * erp_new contens was possibly modified |
1da177e4 LT |
2246 | */ |
2247 | static struct dasd_ccw_req * | |
2248 | dasd_3990_erp_inspect(struct dasd_ccw_req * erp) | |
2249 | { | |
2250 | ||
2251 | struct dasd_ccw_req *erp_new = NULL; | |
2252 | /* sense data are located in the refers record of the */ | |
2253 | /* already set up new ERP ! */ | |
2254 | char *sense = erp->refers->irb.ecw; | |
2255 | ||
2256 | /* distinguish between 24 and 32 byte sense data */ | |
2257 | if (sense[27] & DASD_SENSE_BIT_0) { | |
2258 | ||
2259 | /* inspect the 24 byte sense data */ | |
2260 | erp_new = dasd_3990_erp_inspect_24(erp, sense); | |
2261 | ||
2262 | } else { | |
2263 | ||
2264 | /* inspect the 32 byte sense data */ | |
2265 | erp_new = dasd_3990_erp_inspect_32(erp, sense); | |
2266 | ||
2267 | } /* end distinguish between 24 and 32 byte sense data */ | |
2268 | ||
2269 | return erp_new; | |
2270 | } | |
2271 | ||
2272 | /* | |
2273 | * DASD_3990_ERP_ADD_ERP | |
138c014d | 2274 | * |
1da177e4 LT |
2275 | * DESCRIPTION |
2276 | * This funtion adds an additional request block (ERP) to the head of | |
2277 | * the given cqr (or erp). | |
2278 | * This erp is initialized as an default erp (retry TIC) | |
2279 | * | |
2280 | * PARAMETER | |
138c014d | 2281 | * cqr head of the current ERP-chain (or single cqr if |
1da177e4 LT |
2282 | * first error) |
2283 | * RETURN VALUES | |
2284 | * erp pointer to new ERP-chain head | |
2285 | */ | |
2286 | static struct dasd_ccw_req * | |
2287 | dasd_3990_erp_add_erp(struct dasd_ccw_req * cqr) | |
2288 | { | |
2289 | ||
2290 | struct dasd_device *device = cqr->device; | |
2291 | struct ccw1 *ccw; | |
2292 | ||
2293 | /* allocate additional request block */ | |
2294 | struct dasd_ccw_req *erp; | |
2295 | ||
2296 | erp = dasd_alloc_erp_request((char *) &cqr->magic, 2, 0, cqr->device); | |
2297 | if (IS_ERR(erp)) { | |
2298 | if (cqr->retries <= 0) { | |
2299 | DEV_MESSAGE(KERN_ERR, device, "%s", | |
2300 | "Unable to allocate ERP request"); | |
2301 | cqr->status = DASD_CQR_FAILED; | |
2302 | cqr->stopclk = get_clock (); | |
2303 | } else { | |
2304 | DEV_MESSAGE (KERN_ERR, device, | |
2305 | "Unable to allocate ERP request " | |
2306 | "(%i retries left)", | |
2307 | cqr->retries); | |
2308 | dasd_set_timer(device, (HZ << 3)); | |
2309 | } | |
2310 | return cqr; | |
2311 | } | |
2312 | ||
2313 | /* initialize request with default TIC to current ERP/CQR */ | |
2314 | ccw = erp->cpaddr; | |
2315 | ccw->cmd_code = CCW_CMD_NOOP; | |
2316 | ccw->flags = CCW_FLAG_CC; | |
2317 | ccw++; | |
2318 | ccw->cmd_code = CCW_CMD_TIC; | |
2319 | ccw->cda = (long)(cqr->cpaddr); | |
2320 | erp->function = dasd_3990_erp_add_erp; | |
2321 | erp->refers = cqr; | |
2322 | erp->device = cqr->device; | |
2323 | erp->magic = cqr->magic; | |
2324 | erp->expires = 0; | |
2325 | erp->retries = 256; | |
2326 | erp->buildclk = get_clock(); | |
2327 | ||
2328 | erp->status = DASD_CQR_FILLED; | |
2329 | ||
2330 | return erp; | |
2331 | } | |
2332 | ||
2333 | /* | |
138c014d HH |
2334 | * DASD_3990_ERP_ADDITIONAL_ERP |
2335 | * | |
1da177e4 LT |
2336 | * DESCRIPTION |
2337 | * An additional ERP is needed to handle the current error. | |
2338 | * Add ERP to the head of the ERP-chain containing the ERP processing | |
2339 | * determined based on the sense data. | |
2340 | * | |
2341 | * PARAMETER | |
138c014d | 2342 | * cqr head of the current ERP-chain (or single cqr if |
1da177e4 LT |
2343 | * first error) |
2344 | * | |
2345 | * RETURN VALUES | |
2346 | * erp pointer to new ERP-chain head | |
2347 | */ | |
2348 | static struct dasd_ccw_req * | |
2349 | dasd_3990_erp_additional_erp(struct dasd_ccw_req * cqr) | |
2350 | { | |
2351 | ||
2352 | struct dasd_ccw_req *erp = NULL; | |
2353 | ||
2354 | /* add erp and initialize with default TIC */ | |
2355 | erp = dasd_3990_erp_add_erp(cqr); | |
2356 | ||
2357 | /* inspect sense, determine specific ERP if possible */ | |
2358 | if (erp != cqr) { | |
2359 | ||
2360 | erp = dasd_3990_erp_inspect(erp); | |
2361 | } | |
2362 | ||
2363 | return erp; | |
2364 | ||
2365 | } /* end dasd_3990_erp_additional_erp */ | |
2366 | ||
2367 | /* | |
2368 | * DASD_3990_ERP_ERROR_MATCH | |
2369 | * | |
2370 | * DESCRIPTION | |
2371 | * Check if the device status of the given cqr is the same. | |
2372 | * This means that the failed CCW and the relevant sense data | |
2373 | * must match. | |
2374 | * I don't distinguish between 24 and 32 byte sense because in case of | |
2375 | * 24 byte sense byte 25 and 27 is set as well. | |
2376 | * | |
2377 | * PARAMETER | |
138c014d | 2378 | * cqr1 first cqr, which will be compared with the |
1da177e4 LT |
2379 | * cqr2 second cqr. |
2380 | * | |
2381 | * RETURN VALUES | |
2382 | * match 'boolean' for match found | |
2383 | * returns 1 if match found, otherwise 0. | |
2384 | */ | |
2385 | static int | |
2386 | dasd_3990_erp_error_match(struct dasd_ccw_req *cqr1, struct dasd_ccw_req *cqr2) | |
2387 | { | |
2388 | ||
2389 | /* check failed CCW */ | |
2390 | if (cqr1->irb.scsw.cpa != cqr2->irb.scsw.cpa) { | |
2391 | // return 0; /* CCW doesn't match */ | |
2392 | } | |
2393 | ||
2394 | /* check sense data; byte 0-2,25,27 */ | |
2395 | if (!((memcmp (cqr1->irb.ecw, cqr2->irb.ecw, 3) == 0) && | |
2396 | (cqr1->irb.ecw[27] == cqr2->irb.ecw[27]) && | |
2397 | (cqr1->irb.ecw[25] == cqr2->irb.ecw[25]))) { | |
2398 | ||
2399 | return 0; /* sense doesn't match */ | |
2400 | } | |
2401 | ||
2402 | return 1; /* match */ | |
2403 | ||
2404 | } /* end dasd_3990_erp_error_match */ | |
2405 | ||
2406 | /* | |
2407 | * DASD_3990_ERP_IN_ERP | |
2408 | * | |
2409 | * DESCRIPTION | |
2410 | * check if the current error already happened before. | |
2411 | * quick exit if current cqr is not an ERP (cqr->refers=NULL) | |
2412 | * | |
2413 | * PARAMETER | |
2414 | * cqr failed cqr (either original cqr or already an erp) | |
2415 | * | |
2416 | * RETURN VALUES | |
138c014d | 2417 | * erp erp-pointer to the already defined error |
1da177e4 LT |
2418 | * recovery procedure OR |
2419 | * NULL if a 'new' error occurred. | |
2420 | */ | |
2421 | static struct dasd_ccw_req * | |
2422 | dasd_3990_erp_in_erp(struct dasd_ccw_req *cqr) | |
2423 | { | |
2424 | ||
2425 | struct dasd_ccw_req *erp_head = cqr, /* save erp chain head */ | |
2426 | *erp_match = NULL; /* save erp chain head */ | |
2427 | int match = 0; /* 'boolean' for matching error found */ | |
2428 | ||
2429 | if (cqr->refers == NULL) { /* return if not in erp */ | |
2430 | return NULL; | |
2431 | } | |
2432 | ||
2433 | /* check the erp/cqr chain for current error */ | |
2434 | do { | |
2435 | match = dasd_3990_erp_error_match(erp_head, cqr->refers); | |
2436 | erp_match = cqr; /* save possible matching erp */ | |
2437 | cqr = cqr->refers; /* check next erp/cqr in queue */ | |
2438 | ||
2439 | } while ((cqr->refers != NULL) && (!match)); | |
2440 | ||
2441 | if (!match) { | |
2442 | return NULL; /* no match was found */ | |
2443 | } | |
2444 | ||
2445 | return erp_match; /* return address of matching erp */ | |
2446 | ||
2447 | } /* END dasd_3990_erp_in_erp */ | |
2448 | ||
2449 | /* | |
2450 | * DASD_3990_ERP_FURTHER_ERP (24 & 32 byte sense) | |
2451 | * | |
2452 | * DESCRIPTION | |
138c014d | 2453 | * No retry is left for the current ERP. Check what has to be done |
1da177e4 LT |
2454 | * with the ERP. |
2455 | * - do further defined ERP action or | |
138c014d | 2456 | * - wait for interrupt or |
1da177e4 LT |
2457 | * - exit with permanent error |
2458 | * | |
2459 | * PARAMETER | |
2460 | * erp ERP which is in progress with no retry left | |
2461 | * | |
2462 | * RETURN VALUES | |
2463 | * erp modified/additional ERP | |
2464 | */ | |
2465 | static struct dasd_ccw_req * | |
2466 | dasd_3990_erp_further_erp(struct dasd_ccw_req *erp) | |
2467 | { | |
2468 | ||
2469 | struct dasd_device *device = erp->device; | |
2470 | char *sense = erp->irb.ecw; | |
2471 | ||
2472 | /* check for 24 byte sense ERP */ | |
2473 | if ((erp->function == dasd_3990_erp_bus_out) || | |
2474 | (erp->function == dasd_3990_erp_action_1) || | |
2475 | (erp->function == dasd_3990_erp_action_4)) { | |
2476 | ||
2477 | erp = dasd_3990_erp_action_1(erp); | |
2478 | ||
2479 | } else if (erp->function == dasd_3990_erp_action_5) { | |
2480 | ||
2481 | /* retries have not been successful */ | |
2482 | /* prepare erp for retry on different channel path */ | |
2483 | erp = dasd_3990_erp_action_1(erp); | |
2484 | ||
2485 | if (!(sense[2] & DASD_SENSE_BIT_0)) { | |
2486 | ||
138c014d | 2487 | /* issue a Diagnostic Control command with an |
1da177e4 LT |
2488 | * Inhibit Write subcommand */ |
2489 | ||
2490 | switch (sense[25]) { | |
2491 | case 0x17: | |
2492 | case 0x57:{ /* controller */ | |
2493 | erp = dasd_3990_erp_DCTL(erp, 0x20); | |
2494 | break; | |
2495 | } | |
2496 | case 0x18: | |
2497 | case 0x58:{ /* channel path */ | |
2498 | erp = dasd_3990_erp_DCTL(erp, 0x40); | |
2499 | break; | |
2500 | } | |
2501 | case 0x19: | |
2502 | case 0x59:{ /* storage director */ | |
2503 | erp = dasd_3990_erp_DCTL(erp, 0x80); | |
2504 | break; | |
2505 | } | |
2506 | default: | |
2507 | DEV_MESSAGE(KERN_DEBUG, device, | |
2508 | "invalid subcommand modifier 0x%x " | |
2509 | "for Diagnostic Control Command", | |
2510 | sense[25]); | |
2511 | } | |
2512 | } | |
2513 | ||
2514 | /* check for 32 byte sense ERP */ | |
2515 | } else if ((erp->function == dasd_3990_erp_compound_retry) || | |
2516 | (erp->function == dasd_3990_erp_compound_path) || | |
2517 | (erp->function == dasd_3990_erp_compound_code) || | |
2518 | (erp->function == dasd_3990_erp_compound_config)) { | |
2519 | ||
2520 | erp = dasd_3990_erp_compound(erp, sense); | |
2521 | ||
2522 | } else { | |
2523 | /* No retry left and no additional special handling */ | |
2524 | /*necessary */ | |
2525 | DEV_MESSAGE(KERN_ERR, device, | |
2526 | "no retries left for erp %p - " | |
2527 | "set status to FAILED", erp); | |
2528 | ||
2529 | erp->status = DASD_CQR_FAILED; | |
2530 | } | |
2531 | ||
2532 | return erp; | |
2533 | ||
2534 | } /* end dasd_3990_erp_further_erp */ | |
2535 | ||
2536 | /* | |
138c014d | 2537 | * DASD_3990_ERP_HANDLE_MATCH_ERP |
1da177e4 LT |
2538 | * |
2539 | * DESCRIPTION | |
2540 | * An error occurred again and an ERP has been detected which is already | |
138c014d | 2541 | * used to handle this error (e.g. retries). |
1da177e4 LT |
2542 | * All prior ERP's are asumed to be successful and therefore removed |
2543 | * from queue. | |
138c014d | 2544 | * If retry counter of matching erp is already 0, it is checked if further |
1da177e4 LT |
2545 | * action is needed (besides retry) or if the ERP has failed. |
2546 | * | |
2547 | * PARAMETER | |
2548 | * erp_head first ERP in ERP-chain | |
2549 | * erp ERP that handles the actual error. | |
2550 | * (matching erp) | |
2551 | * | |
2552 | * RETURN VALUES | |
2553 | * erp modified/additional ERP | |
2554 | */ | |
2555 | static struct dasd_ccw_req * | |
2556 | dasd_3990_erp_handle_match_erp(struct dasd_ccw_req *erp_head, | |
2557 | struct dasd_ccw_req *erp) | |
2558 | { | |
2559 | ||
2560 | struct dasd_device *device = erp_head->device; | |
2561 | struct dasd_ccw_req *erp_done = erp_head; /* finished req */ | |
2562 | struct dasd_ccw_req *erp_free = NULL; /* req to be freed */ | |
2563 | ||
2564 | /* loop over successful ERPs and remove them from chanq */ | |
2565 | while (erp_done != erp) { | |
2566 | ||
2567 | if (erp_done == NULL) /* end of chain reached */ | |
2568 | panic(PRINTK_HEADER "Programming error in ERP! The " | |
2569 | "original request was lost\n"); | |
2570 | ||
2571 | /* remove the request from the device queue */ | |
2572 | list_del(&erp_done->list); | |
2573 | ||
2574 | erp_free = erp_done; | |
2575 | erp_done = erp_done->refers; | |
2576 | ||
2577 | /* free the finished erp request */ | |
2578 | dasd_free_erp_request(erp_free, erp_free->device); | |
2579 | ||
2580 | } /* end while */ | |
2581 | ||
2582 | if (erp->retries > 0) { | |
2583 | ||
2584 | char *sense = erp->refers->irb.ecw; | |
2585 | ||
2586 | /* check for special retries */ | |
2587 | if (erp->function == dasd_3990_erp_action_4) { | |
2588 | ||
2589 | erp = dasd_3990_erp_action_4(erp, sense); | |
2590 | ||
2591 | } else if (erp->function == dasd_3990_erp_action_1B_32) { | |
2592 | ||
2593 | erp = dasd_3990_update_1B(erp, sense); | |
2594 | ||
2595 | } else if (erp->function == dasd_3990_erp_int_req) { | |
2596 | ||
2597 | erp = dasd_3990_erp_int_req(erp); | |
2598 | ||
2599 | } else { | |
2600 | /* simple retry */ | |
2601 | DEV_MESSAGE(KERN_DEBUG, device, | |
2602 | "%i retries left for erp %p", | |
2603 | erp->retries, erp); | |
2604 | ||
2605 | /* handle the request again... */ | |
2606 | erp->status = DASD_CQR_QUEUED; | |
2607 | } | |
2608 | ||
2609 | } else { | |
2610 | /* no retry left - check for further necessary action */ | |
2611 | /* if no further actions, handle rest as permanent error */ | |
2612 | erp = dasd_3990_erp_further_erp(erp); | |
2613 | } | |
2614 | ||
2615 | return erp; | |
2616 | ||
2617 | } /* end dasd_3990_erp_handle_match_erp */ | |
2618 | ||
2619 | /* | |
2620 | * DASD_3990_ERP_ACTION | |
2621 | * | |
2622 | * DESCRIPTION | |
2623 | * controll routine for 3990 erp actions. | |
2624 | * Has to be called with the queue lock (namely the s390_irq_lock) acquired. | |
2625 | * | |
2626 | * PARAMETER | |
2627 | * cqr failed cqr (either original cqr or already an erp) | |
2628 | * | |
2629 | * RETURN VALUES | |
2630 | * erp erp-pointer to the head of the ERP action chain. | |
2631 | * This means: | |
2632 | * - either a ptr to an additional ERP cqr or | |
138c014d | 2633 | * - the original given cqr (which's status might |
1da177e4 LT |
2634 | * be modified) |
2635 | */ | |
2636 | struct dasd_ccw_req * | |
2637 | dasd_3990_erp_action(struct dasd_ccw_req * cqr) | |
2638 | { | |
2639 | ||
2640 | struct dasd_ccw_req *erp = NULL; | |
2641 | struct dasd_device *device = cqr->device; | |
9575bf26 | 2642 | struct dasd_ccw_req *temp_erp = NULL; |
1da177e4 | 2643 | |
9575bf26 HH |
2644 | if (device->features & DASD_FEATURE_ERPLOG) { |
2645 | /* print current erp_chain */ | |
2646 | DEV_MESSAGE(KERN_ERR, device, "%s", | |
2647 | "ERP chain at BEGINNING of ERP-ACTION"); | |
1da177e4 LT |
2648 | for (temp_erp = cqr; |
2649 | temp_erp != NULL; temp_erp = temp_erp->refers) { | |
2650 | ||
2651 | DEV_MESSAGE(KERN_ERR, device, | |
2652 | " erp %p (%02x) refers to %p", | |
2653 | temp_erp, temp_erp->status, | |
2654 | temp_erp->refers); | |
2655 | } | |
2656 | } | |
1da177e4 LT |
2657 | |
2658 | /* double-check if current erp/cqr was successfull */ | |
2659 | if ((cqr->irb.scsw.cstat == 0x00) && | |
2660 | (cqr->irb.scsw.dstat == (DEV_STAT_CHN_END|DEV_STAT_DEV_END))) { | |
2661 | ||
2662 | DEV_MESSAGE(KERN_DEBUG, device, | |
2663 | "ERP called for successful request %p" | |
2664 | " - NO ERP necessary", cqr); | |
2665 | ||
2666 | cqr->status = DASD_CQR_DONE; | |
2667 | ||
2668 | return cqr; | |
2669 | } | |
2670 | /* check if sense data are available */ | |
2671 | if (!cqr->irb.ecw) { | |
2672 | DEV_MESSAGE(KERN_DEBUG, device, | |
2673 | "ERP called witout sense data avail ..." | |
2674 | "request %p - NO ERP possible", cqr); | |
2675 | ||
2676 | cqr->status = DASD_CQR_FAILED; | |
2677 | ||
2678 | return cqr; | |
2679 | ||
2680 | } | |
2681 | ||
2682 | /* check if error happened before */ | |
2683 | erp = dasd_3990_erp_in_erp(cqr); | |
2684 | ||
2685 | if (erp == NULL) { | |
2686 | /* no matching erp found - set up erp */ | |
2687 | erp = dasd_3990_erp_additional_erp(cqr); | |
2688 | } else { | |
2689 | /* matching erp found - set all leading erp's to DONE */ | |
2690 | erp = dasd_3990_erp_handle_match_erp(cqr, erp); | |
2691 | } | |
2692 | ||
9575bf26 HH |
2693 | if (device->features & DASD_FEATURE_ERPLOG) { |
2694 | /* print current erp_chain */ | |
2695 | DEV_MESSAGE(KERN_ERR, device, "%s", | |
2696 | "ERP chain at END of ERP-ACTION"); | |
1da177e4 LT |
2697 | for (temp_erp = erp; |
2698 | temp_erp != NULL; temp_erp = temp_erp->refers) { | |
2699 | ||
2700 | DEV_MESSAGE(KERN_ERR, device, | |
2701 | " erp %p (%02x) refers to %p", | |
2702 | temp_erp, temp_erp->status, | |
2703 | temp_erp->refers); | |
2704 | } | |
2705 | } | |
1da177e4 | 2706 | |
1da177e4 LT |
2707 | /* enqueue added ERP request */ |
2708 | if (erp->status == DASD_CQR_FILLED) { | |
2709 | erp->status = DASD_CQR_QUEUED; | |
2710 | list_add(&erp->list, &device->ccw_queue); | |
2711 | } | |
2712 | ||
2713 | return erp; | |
2714 | ||
2715 | } /* end dasd_3990_erp_action */ |