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