]>
Commit | Line | Data |
---|---|---|
2cb7cef9 BS |
1 | From: Gerald Schaefer <geraldsc@de.ibm.com> |
2 | Subject: zfcp: Use only single SBAL commands from recovery | |
3 | References: bnc#518291,LTC#54462 | |
4 | ||
5 | Symptom: Issuing an ELS request might not detect a stalled | |
6 | outbound queue | |
7 | Problem: zfcp uses chained SBALs for ELS requests leading to the | |
8 | situation that the ELS request gets one free SBAL, but | |
9 | not the following ones. In this situation the ELS request | |
10 | fails but does not trigger the error handling for the | |
11 | stalled queue. | |
12 | Solution: Use unchained SBALs where possible, especially for | |
13 | commands from the erp. This guarantees that each erp | |
14 | command will get the required SBAL or trigger queue | |
15 | recovery. | |
16 | ||
17 | Acked-by: John Jolly <jjolly@suse.de> | |
18 | --- | |
19 | drivers/s390/scsi/zfcp_fsf.c | 33 +++++++++++++++++++++++++-------- | |
20 | 1 file changed, 25 insertions(+), 8 deletions(-) | |
21 | ||
22 | --- a/drivers/s390/scsi/zfcp_fsf.c 2009-07-01 12:26:28.000000000 +0200 | |
23 | +++ b/drivers/s390/scsi/zfcp_fsf.c 2009-07-01 12:28:43.000000000 +0200 | |
24 | @@ -1012,6 +1012,23 @@ skip_fsfstatus: | |
25 | send_ct->handler(send_ct->handler_data); | |
26 | } | |
27 | ||
28 | +static void zfcp_fsf_setup_ct_els_unchained(struct qdio_buffer_element *sbale, | |
29 | + struct scatterlist *sg_req, | |
30 | + struct scatterlist *sg_resp) | |
31 | +{ | |
32 | + sbale[0].flags |= SBAL_FLAGS0_TYPE_WRITE_READ; | |
33 | + sbale[2].addr = sg_virt(sg_req); | |
34 | + sbale[2].length = sg_req->length; | |
35 | + sbale[3].addr = sg_virt(sg_resp); | |
36 | + sbale[3].length = sg_resp->length; | |
37 | + sbale[3].flags |= SBAL_FLAGS_LAST_ENTRY; | |
38 | +} | |
39 | + | |
40 | +static int zfcp_fsf_one_sbal(struct scatterlist *sg) | |
41 | +{ | |
42 | + return sg_is_last(sg) && sg->length <= PAGE_SIZE; | |
43 | +} | |
44 | + | |
45 | static int zfcp_fsf_setup_ct_els_sbals(struct zfcp_fsf_req *req, | |
46 | struct scatterlist *sg_req, | |
47 | struct scatterlist *sg_resp, | |
48 | @@ -1022,16 +1039,16 @@ static int zfcp_fsf_setup_ct_els_sbals(s | |
49 | int bytes; | |
50 | ||
51 | if (!(feat & FSF_FEATURE_ELS_CT_CHAINED_SBALS)) { | |
52 | - if (sg_req->length > PAGE_SIZE || sg_resp->length > PAGE_SIZE || | |
53 | - !sg_is_last(sg_req) || !sg_is_last(sg_resp)) | |
54 | + if (!zfcp_fsf_one_sbal(sg_req) || !zfcp_fsf_one_sbal(sg_resp)) | |
55 | return -EOPNOTSUPP; | |
56 | ||
57 | - sbale[0].flags |= SBAL_FLAGS0_TYPE_WRITE_READ; | |
58 | - sbale[2].addr = sg_virt(sg_req); | |
59 | - sbale[2].length = sg_req->length; | |
60 | - sbale[3].addr = sg_virt(sg_resp); | |
61 | - sbale[3].length = sg_resp->length; | |
62 | - sbale[3].flags |= SBAL_FLAGS_LAST_ENTRY; | |
63 | + zfcp_fsf_setup_ct_els_unchained(sbale, sg_req, sg_resp); | |
64 | + return 0; | |
65 | + } | |
66 | + | |
67 | + /* use single, unchained SBAL if it can hold the request */ | |
68 | + if (zfcp_fsf_one_sbal(sg_req) && zfcp_fsf_one_sbal(sg_resp)) { | |
69 | + zfcp_fsf_setup_ct_els_unchained(sbale, sg_req, sg_resp); | |
70 | return 0; | |
71 | } | |
72 |