diff options
author | Christof Schmitt <christof.schmitt@de.ibm.com> | 2010-07-16 09:37:43 -0400 |
---|---|---|
committer | James Bottomley <James.Bottomley@suse.de> | 2010-07-28 10:48:58 -0400 |
commit | 339f4f4eab80caa6cf0d39fb057ad6ddb84ba91e (patch) | |
tree | 495dc5a18c128d3e802a8b1914f978bf4262ac3d | |
parent | ef3eb71d8ba4fd9d48c5f9310bc9d90ca00323b4 (diff) |
[SCSI] zfcp: Trigger logging in the FCP channel on qdio error conditions
Exploit the cio siosl function to trigger logging in the FCP channel
on qdio error conditions. Add a helper function in zfcp_qdio to ensure
that tracing is only triggered once before calling qdio_shutdown.
Trigger in zfcp for hardware logs are:
- timeout for FSF requests to the FCP channel
- "no recommendation" status from FCP channel
- invalid FSF protocol status
- stalled outbound queue
- unknown request id on inbound queue
- QDIO_ERROR_SLSB_STATE
All of the above triggers run from the Linux qdio softirq context, so
no additional synchronization is necessary for the handling of the
ZFCP_STATUS_ADAPTER_SIOSL_ISSUED flag.
Reviewed-by: Swen Schillig <swen@vnet.ibm.com>
Signed-off-by: Christof Schmitt <christof.schmitt@de.ibm.com>
Signed-off-by: James Bottomley <James.Bottomley@suse.de>
-rw-r--r-- | drivers/s390/scsi/zfcp_def.h | 1 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_ext.h | 1 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_fsf.c | 7 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_qdio.c | 35 |
4 files changed, 40 insertions, 4 deletions
diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h index 6c6374ba1807..e1c6b6e05a75 100644 --- a/drivers/s390/scsi/zfcp_def.h +++ b/drivers/s390/scsi/zfcp_def.h | |||
@@ -73,6 +73,7 @@ struct zfcp_reqlist; | |||
73 | 73 | ||
74 | /* adapter status */ | 74 | /* adapter status */ |
75 | #define ZFCP_STATUS_ADAPTER_QDIOUP 0x00000002 | 75 | #define ZFCP_STATUS_ADAPTER_QDIOUP 0x00000002 |
76 | #define ZFCP_STATUS_ADAPTER_SIOSL_ISSUED 0x00000004 | ||
76 | #define ZFCP_STATUS_ADAPTER_XCONFIG_OK 0x00000008 | 77 | #define ZFCP_STATUS_ADAPTER_XCONFIG_OK 0x00000008 |
77 | #define ZFCP_STATUS_ADAPTER_HOST_CON_INIT 0x00000010 | 78 | #define ZFCP_STATUS_ADAPTER_HOST_CON_INIT 0x00000010 |
78 | #define ZFCP_STATUS_ADAPTER_ERP_PENDING 0x00000100 | 79 | #define ZFCP_STATUS_ADAPTER_ERP_PENDING 0x00000100 |
diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h index de0925f25dcc..3b93239c6f69 100644 --- a/drivers/s390/scsi/zfcp_ext.h +++ b/drivers/s390/scsi/zfcp_ext.h | |||
@@ -152,6 +152,7 @@ extern int zfcp_qdio_sbals_from_sg(struct zfcp_qdio *, struct zfcp_qdio_req *, | |||
152 | struct scatterlist *); | 152 | struct scatterlist *); |
153 | extern int zfcp_qdio_open(struct zfcp_qdio *); | 153 | extern int zfcp_qdio_open(struct zfcp_qdio *); |
154 | extern void zfcp_qdio_close(struct zfcp_qdio *); | 154 | extern void zfcp_qdio_close(struct zfcp_qdio *); |
155 | extern void zfcp_qdio_siosl(struct zfcp_adapter *); | ||
155 | 156 | ||
156 | /* zfcp_scsi.c */ | 157 | /* zfcp_scsi.c */ |
157 | extern struct zfcp_data zfcp_data; | 158 | extern struct zfcp_data zfcp_data; |
diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index f9be5d60d92a..9d1d7d1842ce 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c | |||
@@ -21,6 +21,7 @@ | |||
21 | static void zfcp_fsf_request_timeout_handler(unsigned long data) | 21 | static void zfcp_fsf_request_timeout_handler(unsigned long data) |
22 | { | 22 | { |
23 | struct zfcp_adapter *adapter = (struct zfcp_adapter *) data; | 23 | struct zfcp_adapter *adapter = (struct zfcp_adapter *) data; |
24 | zfcp_qdio_siosl(adapter); | ||
24 | zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED, | 25 | zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED, |
25 | "fsrth_1", NULL); | 26 | "fsrth_1", NULL); |
26 | } | 27 | } |
@@ -326,6 +327,7 @@ static void zfcp_fsf_fsfstatus_qual_eval(struct zfcp_fsf_req *req) | |||
326 | dev_err(&req->adapter->ccw_device->dev, | 327 | dev_err(&req->adapter->ccw_device->dev, |
327 | "The FCP adapter reported a problem " | 328 | "The FCP adapter reported a problem " |
328 | "that cannot be recovered\n"); | 329 | "that cannot be recovered\n"); |
330 | zfcp_qdio_siosl(req->adapter); | ||
329 | zfcp_erp_adapter_shutdown(req->adapter, 0, "fsfsqe1", req); | 331 | zfcp_erp_adapter_shutdown(req->adapter, 0, "fsfsqe1", req); |
330 | break; | 332 | break; |
331 | } | 333 | } |
@@ -416,6 +418,7 @@ static void zfcp_fsf_protstatus_eval(struct zfcp_fsf_req *req) | |||
416 | dev_err(&adapter->ccw_device->dev, | 418 | dev_err(&adapter->ccw_device->dev, |
417 | "0x%x is not a valid transfer protocol status\n", | 419 | "0x%x is not a valid transfer protocol status\n", |
418 | qtcb->prefix.prot_status); | 420 | qtcb->prefix.prot_status); |
421 | zfcp_qdio_siosl(adapter); | ||
419 | zfcp_erp_adapter_shutdown(adapter, 0, "fspse_9", req); | 422 | zfcp_erp_adapter_shutdown(adapter, 0, "fspse_9", req); |
420 | } | 423 | } |
421 | req->status |= ZFCP_STATUS_FSFREQ_ERROR; | 424 | req->status |= ZFCP_STATUS_FSFREQ_ERROR; |
@@ -2485,13 +2488,15 @@ void zfcp_fsf_reqid_check(struct zfcp_qdio *qdio, int sbal_idx) | |||
2485 | req_id = (unsigned long) sbale->addr; | 2488 | req_id = (unsigned long) sbale->addr; |
2486 | fsf_req = zfcp_reqlist_find_rm(adapter->req_list, req_id); | 2489 | fsf_req = zfcp_reqlist_find_rm(adapter->req_list, req_id); |
2487 | 2490 | ||
2488 | if (!fsf_req) | 2491 | if (!fsf_req) { |
2489 | /* | 2492 | /* |
2490 | * Unknown request means that we have potentially memory | 2493 | * Unknown request means that we have potentially memory |
2491 | * corruption and must stop the machine immediately. | 2494 | * corruption and must stop the machine immediately. |
2492 | */ | 2495 | */ |
2496 | zfcp_qdio_siosl(adapter); | ||
2493 | panic("error: unknown req_id (%lx) on adapter %s.\n", | 2497 | panic("error: unknown req_id (%lx) on adapter %s.\n", |
2494 | req_id, dev_name(&adapter->ccw_device->dev)); | 2498 | req_id, dev_name(&adapter->ccw_device->dev)); |
2499 | } | ||
2495 | 2500 | ||
2496 | fsf_req->qdio_req.sbal_response = sbal_idx; | 2501 | fsf_req->qdio_req.sbal_response = sbal_idx; |
2497 | zfcp_fsf_req_complete(fsf_req); | 2502 | zfcp_fsf_req_complete(fsf_req); |
diff --git a/drivers/s390/scsi/zfcp_qdio.c b/drivers/s390/scsi/zfcp_qdio.c index aceced8ec7e4..b2635759721c 100644 --- a/drivers/s390/scsi/zfcp_qdio.c +++ b/drivers/s390/scsi/zfcp_qdio.c | |||
@@ -30,12 +30,15 @@ static int zfcp_qdio_buffers_enqueue(struct qdio_buffer **sbal) | |||
30 | return 0; | 30 | return 0; |
31 | } | 31 | } |
32 | 32 | ||
33 | static void zfcp_qdio_handler_error(struct zfcp_qdio *qdio, char *id) | 33 | static void zfcp_qdio_handler_error(struct zfcp_qdio *qdio, char *id, |
34 | unsigned int qdio_err) | ||
34 | { | 35 | { |
35 | struct zfcp_adapter *adapter = qdio->adapter; | 36 | struct zfcp_adapter *adapter = qdio->adapter; |
36 | 37 | ||
37 | dev_warn(&adapter->ccw_device->dev, "A QDIO problem occurred\n"); | 38 | dev_warn(&adapter->ccw_device->dev, "A QDIO problem occurred\n"); |
38 | 39 | ||
40 | if (qdio_err & QDIO_ERROR_SLSB_STATE) | ||
41 | zfcp_qdio_siosl(adapter); | ||
39 | zfcp_erp_adapter_reopen(adapter, | 42 | zfcp_erp_adapter_reopen(adapter, |
40 | ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED | | 43 | ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED | |
41 | ZFCP_STATUS_COMMON_ERP_FAILED, id, NULL); | 44 | ZFCP_STATUS_COMMON_ERP_FAILED, id, NULL); |
@@ -74,7 +77,7 @@ static void zfcp_qdio_int_req(struct ccw_device *cdev, unsigned int qdio_err, | |||
74 | 77 | ||
75 | if (unlikely(qdio_err)) { | 78 | if (unlikely(qdio_err)) { |
76 | zfcp_dbf_hba_qdio(qdio->adapter->dbf, qdio_err, idx, count); | 79 | zfcp_dbf_hba_qdio(qdio->adapter->dbf, qdio_err, idx, count); |
77 | zfcp_qdio_handler_error(qdio, "qdireq1"); | 80 | zfcp_qdio_handler_error(qdio, "qdireq1", qdio_err); |
78 | return; | 81 | return; |
79 | } | 82 | } |
80 | 83 | ||
@@ -95,7 +98,7 @@ static void zfcp_qdio_int_resp(struct ccw_device *cdev, unsigned int qdio_err, | |||
95 | 98 | ||
96 | if (unlikely(qdio_err)) { | 99 | if (unlikely(qdio_err)) { |
97 | zfcp_dbf_hba_qdio(qdio->adapter->dbf, qdio_err, idx, count); | 100 | zfcp_dbf_hba_qdio(qdio->adapter->dbf, qdio_err, idx, count); |
98 | zfcp_qdio_handler_error(qdio, "qdires1"); | 101 | zfcp_qdio_handler_error(qdio, "qdires1", qdio_err); |
99 | return; | 102 | return; |
100 | } | 103 | } |
101 | 104 | ||
@@ -361,6 +364,9 @@ int zfcp_qdio_open(struct zfcp_qdio *qdio) | |||
361 | if (atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP) | 364 | if (atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP) |
362 | return -EIO; | 365 | return -EIO; |
363 | 366 | ||
367 | atomic_clear_mask(ZFCP_STATUS_ADAPTER_SIOSL_ISSUED, | ||
368 | &qdio->adapter->status); | ||
369 | |||
364 | zfcp_qdio_setup_init_data(&init_data, qdio); | 370 | zfcp_qdio_setup_init_data(&init_data, qdio); |
365 | 371 | ||
366 | if (qdio_establish(&init_data)) | 372 | if (qdio_establish(&init_data)) |
@@ -440,3 +446,26 @@ int zfcp_qdio_setup(struct zfcp_adapter *adapter) | |||
440 | return 0; | 446 | return 0; |
441 | } | 447 | } |
442 | 448 | ||
449 | /** | ||
450 | * zfcp_qdio_siosl - Trigger logging in FCP channel | ||
451 | * @adapter: The zfcp_adapter where to trigger logging | ||
452 | * | ||
453 | * Call the cio siosl function to trigger hardware logging. This | ||
454 | * wrapper function sets a flag to ensure hardware logging is only | ||
455 | * triggered once before going through qdio shutdown. | ||
456 | * | ||
457 | * The triggers are always run from qdio tasklet context, so no | ||
458 | * additional synchronization is necessary. | ||
459 | */ | ||
460 | void zfcp_qdio_siosl(struct zfcp_adapter *adapter) | ||
461 | { | ||
462 | int rc; | ||
463 | |||
464 | if (atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_SIOSL_ISSUED) | ||
465 | return; | ||
466 | |||
467 | rc = ccw_device_siosl(adapter->ccw_device); | ||
468 | if (!rc) | ||
469 | atomic_set_mask(ZFCP_STATUS_ADAPTER_SIOSL_ISSUED, | ||
470 | &adapter->status); | ||
471 | } | ||