diff options
author | Swen Schillig <swen@vnet.ibm.com> | 2011-08-15 08:40:32 -0400 |
---|---|---|
committer | James Bottomley <JBottomley@Parallels.com> | 2011-08-27 10:37:03 -0400 |
commit | 86a9668a8d29ea711613e1cb37efa68e7c4db564 (patch) | |
tree | 58a39ba842f928bd9629cfb8468322a96fe7459f | |
parent | dfe5bb506172307e43287b8962348fb85801c0f4 (diff) |
[SCSI] zfcp: support for hardware data router
FICON Express8S supports hardware data router, which requires an
adapted qdio request format.
This part 2/2 exploits the functionality in zfcp.
Signed-off-by: Swen Schillig <swen@vnet.ibm.com>
Signed-off-by: Steffen Maier <maier@linux.vnet.ibm.com>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
-rw-r--r-- | drivers/s390/scsi/zfcp_dbf.c | 36 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_def.h | 7 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_ext.h | 1 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_fsf.c | 77 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_qdio.c | 58 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_qdio.h | 66 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_scsi.c | 10 |
7 files changed, 195 insertions, 60 deletions
diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c index 96d1462e0bf5..967e7b70e977 100644 --- a/drivers/s390/scsi/zfcp_dbf.c +++ b/drivers/s390/scsi/zfcp_dbf.c | |||
@@ -163,6 +163,42 @@ void zfcp_dbf_hba_bit_err(char *tag, struct zfcp_fsf_req *req) | |||
163 | spin_unlock_irqrestore(&dbf->hba_lock, flags); | 163 | spin_unlock_irqrestore(&dbf->hba_lock, flags); |
164 | } | 164 | } |
165 | 165 | ||
166 | /** | ||
167 | * zfcp_dbf_hba_def_err - trace event for deferred error messages | ||
168 | * @adapter: pointer to struct zfcp_adapter | ||
169 | * @req_id: request id which caused the deferred error message | ||
170 | * @scount: number of sbals incl. the signaling sbal | ||
171 | * @pl: array of all involved sbals | ||
172 | */ | ||
173 | void zfcp_dbf_hba_def_err(struct zfcp_adapter *adapter, u64 req_id, u16 scount, | ||
174 | void **pl) | ||
175 | { | ||
176 | struct zfcp_dbf *dbf = adapter->dbf; | ||
177 | struct zfcp_dbf_pay *payload = &dbf->pay_buf; | ||
178 | unsigned long flags; | ||
179 | u16 length; | ||
180 | |||
181 | if (!pl) | ||
182 | return; | ||
183 | |||
184 | spin_lock_irqsave(&dbf->pay_lock, flags); | ||
185 | memset(payload, 0, sizeof(*payload)); | ||
186 | |||
187 | memcpy(payload->area, "def_err", 7); | ||
188 | payload->fsf_req_id = req_id; | ||
189 | payload->counter = 0; | ||
190 | length = min((u16)sizeof(struct qdio_buffer), | ||
191 | (u16)ZFCP_DBF_PAY_MAX_REC); | ||
192 | |||
193 | while ((char *)pl[payload->counter] && payload->counter < scount) { | ||
194 | memcpy(payload->data, (char *)pl[payload->counter], length); | ||
195 | debug_event(dbf->pay, 1, payload, zfcp_dbf_plen(length)); | ||
196 | payload->counter++; | ||
197 | } | ||
198 | |||
199 | spin_unlock_irqrestore(&dbf->pay_lock, flags); | ||
200 | } | ||
201 | |||
166 | static void zfcp_dbf_set_common(struct zfcp_dbf_rec *rec, | 202 | static void zfcp_dbf_set_common(struct zfcp_dbf_rec *rec, |
167 | struct zfcp_adapter *adapter, | 203 | struct zfcp_adapter *adapter, |
168 | struct zfcp_port *port, | 204 | struct zfcp_port *port, |
diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h index 527ba48eea57..ed5d921e82cd 100644 --- a/drivers/s390/scsi/zfcp_def.h +++ b/drivers/s390/scsi/zfcp_def.h | |||
@@ -72,6 +72,7 @@ struct zfcp_reqlist; | |||
72 | #define ZFCP_STATUS_COMMON_NOESC 0x00200000 | 72 | #define ZFCP_STATUS_COMMON_NOESC 0x00200000 |
73 | 73 | ||
74 | /* adapter status */ | 74 | /* adapter status */ |
75 | #define ZFCP_STATUS_ADAPTER_MB_ACT 0x00000001 | ||
75 | #define ZFCP_STATUS_ADAPTER_QDIOUP 0x00000002 | 76 | #define ZFCP_STATUS_ADAPTER_QDIOUP 0x00000002 |
76 | #define ZFCP_STATUS_ADAPTER_SIOSL_ISSUED 0x00000004 | 77 | #define ZFCP_STATUS_ADAPTER_SIOSL_ISSUED 0x00000004 |
77 | #define ZFCP_STATUS_ADAPTER_XCONFIG_OK 0x00000008 | 78 | #define ZFCP_STATUS_ADAPTER_XCONFIG_OK 0x00000008 |
@@ -314,4 +315,10 @@ struct zfcp_fsf_req { | |||
314 | void (*handler)(struct zfcp_fsf_req *); | 315 | void (*handler)(struct zfcp_fsf_req *); |
315 | }; | 316 | }; |
316 | 317 | ||
318 | static inline | ||
319 | int zfcp_adapter_multi_buffer_active(struct zfcp_adapter *adapter) | ||
320 | { | ||
321 | return atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_MB_ACT; | ||
322 | } | ||
323 | |||
317 | #endif /* ZFCP_DEF_H */ | 324 | #endif /* ZFCP_DEF_H */ |
diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h index 03627cfd81cd..2302e1cfb76c 100644 --- a/drivers/s390/scsi/zfcp_ext.h +++ b/drivers/s390/scsi/zfcp_ext.h | |||
@@ -53,6 +53,7 @@ extern void zfcp_dbf_hba_fsf_uss(char *, struct zfcp_fsf_req *); | |||
53 | extern void zfcp_dbf_hba_fsf_res(char *, struct zfcp_fsf_req *); | 53 | extern void zfcp_dbf_hba_fsf_res(char *, struct zfcp_fsf_req *); |
54 | extern void zfcp_dbf_hba_bit_err(char *, struct zfcp_fsf_req *); | 54 | extern void zfcp_dbf_hba_bit_err(char *, struct zfcp_fsf_req *); |
55 | extern void zfcp_dbf_hba_berr(struct zfcp_dbf *, struct zfcp_fsf_req *); | 55 | extern void zfcp_dbf_hba_berr(struct zfcp_dbf *, struct zfcp_fsf_req *); |
56 | extern void zfcp_dbf_hba_def_err(struct zfcp_adapter *, u64, u16, void **); | ||
56 | extern void zfcp_dbf_san_req(char *, struct zfcp_fsf_req *, u32); | 57 | extern void zfcp_dbf_san_req(char *, struct zfcp_fsf_req *, u32); |
57 | extern void zfcp_dbf_san_res(char *, struct zfcp_fsf_req *); | 58 | extern void zfcp_dbf_san_res(char *, struct zfcp_fsf_req *); |
58 | extern void zfcp_dbf_san_in_els(char *, struct zfcp_fsf_req *); | 59 | extern void zfcp_dbf_san_in_els(char *, struct zfcp_fsf_req *); |
diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index fa86c6a28572..e9a787e2e6a5 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c | |||
@@ -936,39 +936,47 @@ static int zfcp_fsf_setup_ct_els_sbals(struct zfcp_fsf_req *req, | |||
936 | struct scatterlist *sg_resp) | 936 | struct scatterlist *sg_resp) |
937 | { | 937 | { |
938 | struct zfcp_adapter *adapter = req->adapter; | 938 | struct zfcp_adapter *adapter = req->adapter; |
939 | struct zfcp_qdio *qdio = adapter->qdio; | ||
940 | struct fsf_qtcb *qtcb = req->qtcb; | ||
939 | u32 feat = adapter->adapter_features; | 941 | u32 feat = adapter->adapter_features; |
940 | int bytes; | ||
941 | 942 | ||
942 | if (!(feat & FSF_FEATURE_ELS_CT_CHAINED_SBALS)) { | 943 | if (zfcp_adapter_multi_buffer_active(adapter)) { |
943 | if (!zfcp_qdio_sg_one_sbale(sg_req) || | 944 | if (zfcp_qdio_sbals_from_sg(qdio, &req->qdio_req, sg_req)) |
944 | !zfcp_qdio_sg_one_sbale(sg_resp)) | 945 | return -EIO; |
945 | return -EOPNOTSUPP; | 946 | if (zfcp_qdio_sbals_from_sg(qdio, &req->qdio_req, sg_resp)) |
947 | return -EIO; | ||
946 | 948 | ||
947 | zfcp_fsf_setup_ct_els_unchained(adapter->qdio, &req->qdio_req, | 949 | zfcp_qdio_set_data_div(qdio, &req->qdio_req, |
948 | sg_req, sg_resp); | 950 | zfcp_qdio_sbale_count(sg_req)); |
951 | zfcp_qdio_set_sbale_last(qdio, &req->qdio_req); | ||
952 | zfcp_qdio_set_scount(qdio, &req->qdio_req); | ||
949 | return 0; | 953 | return 0; |
950 | } | 954 | } |
951 | 955 | ||
952 | /* use single, unchained SBAL if it can hold the request */ | 956 | /* use single, unchained SBAL if it can hold the request */ |
953 | if (zfcp_qdio_sg_one_sbale(sg_req) && zfcp_qdio_sg_one_sbale(sg_resp)) { | 957 | if (zfcp_qdio_sg_one_sbale(sg_req) && zfcp_qdio_sg_one_sbale(sg_resp)) { |
954 | zfcp_fsf_setup_ct_els_unchained(adapter->qdio, &req->qdio_req, | 958 | zfcp_fsf_setup_ct_els_unchained(qdio, &req->qdio_req, |
955 | sg_req, sg_resp); | 959 | sg_req, sg_resp); |
956 | return 0; | 960 | return 0; |
957 | } | 961 | } |
958 | 962 | ||
959 | bytes = zfcp_qdio_sbals_from_sg(adapter->qdio, &req->qdio_req, sg_req); | 963 | if (!(feat & FSF_FEATURE_ELS_CT_CHAINED_SBALS)) |
960 | if (bytes <= 0) | 964 | return -EOPNOTSUPP; |
965 | |||
966 | if (zfcp_qdio_sbals_from_sg(qdio, &req->qdio_req, sg_req)) | ||
961 | return -EIO; | 967 | return -EIO; |
962 | zfcp_qdio_set_sbale_last(adapter->qdio, &req->qdio_req); | ||
963 | req->qtcb->bottom.support.req_buf_length = bytes; | ||
964 | zfcp_qdio_skip_to_last_sbale(&req->qdio_req); | ||
965 | 968 | ||
966 | bytes = zfcp_qdio_sbals_from_sg(adapter->qdio, &req->qdio_req, | 969 | qtcb->bottom.support.req_buf_length = zfcp_qdio_real_bytes(sg_req); |
967 | sg_resp); | 970 | |
968 | req->qtcb->bottom.support.resp_buf_length = bytes; | 971 | zfcp_qdio_set_sbale_last(qdio, &req->qdio_req); |
969 | if (bytes <= 0) | 972 | zfcp_qdio_skip_to_last_sbale(qdio, &req->qdio_req); |
973 | |||
974 | if (zfcp_qdio_sbals_from_sg(qdio, &req->qdio_req, sg_resp)) | ||
970 | return -EIO; | 975 | return -EIO; |
971 | zfcp_qdio_set_sbale_last(adapter->qdio, &req->qdio_req); | 976 | |
977 | qtcb->bottom.support.resp_buf_length = zfcp_qdio_real_bytes(sg_resp); | ||
978 | |||
979 | zfcp_qdio_set_sbale_last(qdio, &req->qdio_req); | ||
972 | 980 | ||
973 | return 0; | 981 | return 0; |
974 | } | 982 | } |
@@ -1119,7 +1127,8 @@ int zfcp_fsf_send_els(struct zfcp_adapter *adapter, u32 d_id, | |||
1119 | 1127 | ||
1120 | req->status |= ZFCP_STATUS_FSFREQ_CLEANUP; | 1128 | req->status |= ZFCP_STATUS_FSFREQ_CLEANUP; |
1121 | 1129 | ||
1122 | zfcp_qdio_sbal_limit(qdio, &req->qdio_req, 2); | 1130 | if (!zfcp_adapter_multi_buffer_active(adapter)) |
1131 | zfcp_qdio_sbal_limit(qdio, &req->qdio_req, 2); | ||
1123 | 1132 | ||
1124 | ret = zfcp_fsf_setup_ct_els(req, els->req, els->resp, timeout); | 1133 | ret = zfcp_fsf_setup_ct_els(req, els->req, els->resp, timeout); |
1125 | 1134 | ||
@@ -2162,7 +2171,7 @@ int zfcp_fsf_fcp_cmnd(struct scsi_cmnd *scsi_cmnd) | |||
2162 | struct zfcp_fsf_req *req; | 2171 | struct zfcp_fsf_req *req; |
2163 | struct fcp_cmnd *fcp_cmnd; | 2172 | struct fcp_cmnd *fcp_cmnd; |
2164 | u8 sbtype = SBAL_SFLAGS0_TYPE_READ; | 2173 | u8 sbtype = SBAL_SFLAGS0_TYPE_READ; |
2165 | int real_bytes, retval = -EIO, dix_bytes = 0; | 2174 | int retval = -EIO; |
2166 | struct scsi_device *sdev = scsi_cmnd->device; | 2175 | struct scsi_device *sdev = scsi_cmnd->device; |
2167 | struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); | 2176 | struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); |
2168 | struct zfcp_adapter *adapter = zfcp_sdev->port->adapter; | 2177 | struct zfcp_adapter *adapter = zfcp_sdev->port->adapter; |
@@ -2216,18 +2225,22 @@ int zfcp_fsf_fcp_cmnd(struct scsi_cmnd *scsi_cmnd) | |||
2216 | if (scsi_prot_sg_count(scsi_cmnd)) { | 2225 | if (scsi_prot_sg_count(scsi_cmnd)) { |
2217 | zfcp_qdio_set_data_div(qdio, &req->qdio_req, | 2226 | zfcp_qdio_set_data_div(qdio, &req->qdio_req, |
2218 | scsi_prot_sg_count(scsi_cmnd)); | 2227 | scsi_prot_sg_count(scsi_cmnd)); |
2219 | dix_bytes = zfcp_qdio_sbals_from_sg(qdio, &req->qdio_req, | 2228 | retval = zfcp_qdio_sbals_from_sg(qdio, &req->qdio_req, |
2229 | scsi_prot_sglist(scsi_cmnd)); | ||
2230 | if (retval) | ||
2231 | goto failed_scsi_cmnd; | ||
2232 | io->prot_data_length = zfcp_qdio_real_bytes( | ||
2220 | scsi_prot_sglist(scsi_cmnd)); | 2233 | scsi_prot_sglist(scsi_cmnd)); |
2221 | io->prot_data_length = dix_bytes; | ||
2222 | } | 2234 | } |
2223 | 2235 | ||
2224 | real_bytes = zfcp_qdio_sbals_from_sg(qdio, &req->qdio_req, | 2236 | retval = zfcp_qdio_sbals_from_sg(qdio, &req->qdio_req, |
2225 | scsi_sglist(scsi_cmnd)); | 2237 | scsi_sglist(scsi_cmnd)); |
2226 | 2238 | if (unlikely(retval)) | |
2227 | if (unlikely(real_bytes < 0) || unlikely(dix_bytes < 0)) | ||
2228 | goto failed_scsi_cmnd; | 2239 | goto failed_scsi_cmnd; |
2229 | 2240 | ||
2230 | zfcp_qdio_set_sbale_last(adapter->qdio, &req->qdio_req); | 2241 | zfcp_qdio_set_sbale_last(adapter->qdio, &req->qdio_req); |
2242 | if (zfcp_adapter_multi_buffer_active(adapter)) | ||
2243 | zfcp_qdio_set_scount(qdio, &req->qdio_req); | ||
2231 | 2244 | ||
2232 | retval = zfcp_fsf_req_send(req); | 2245 | retval = zfcp_fsf_req_send(req); |
2233 | if (unlikely(retval)) | 2246 | if (unlikely(retval)) |
@@ -2329,7 +2342,7 @@ struct zfcp_fsf_req *zfcp_fsf_control_file(struct zfcp_adapter *adapter, | |||
2329 | struct zfcp_qdio *qdio = adapter->qdio; | 2342 | struct zfcp_qdio *qdio = adapter->qdio; |
2330 | struct zfcp_fsf_req *req = NULL; | 2343 | struct zfcp_fsf_req *req = NULL; |
2331 | struct fsf_qtcb_bottom_support *bottom; | 2344 | struct fsf_qtcb_bottom_support *bottom; |
2332 | int retval = -EIO, bytes; | 2345 | int retval = -EIO; |
2333 | u8 direction; | 2346 | u8 direction; |
2334 | 2347 | ||
2335 | if (!(adapter->adapter_features & FSF_FEATURE_CFDC)) | 2348 | if (!(adapter->adapter_features & FSF_FEATURE_CFDC)) |
@@ -2362,13 +2375,17 @@ struct zfcp_fsf_req *zfcp_fsf_control_file(struct zfcp_adapter *adapter, | |||
2362 | bottom->operation_subtype = FSF_CFDC_OPERATION_SUBTYPE; | 2375 | bottom->operation_subtype = FSF_CFDC_OPERATION_SUBTYPE; |
2363 | bottom->option = fsf_cfdc->option; | 2376 | bottom->option = fsf_cfdc->option; |
2364 | 2377 | ||
2365 | bytes = zfcp_qdio_sbals_from_sg(qdio, &req->qdio_req, fsf_cfdc->sg); | 2378 | retval = zfcp_qdio_sbals_from_sg(qdio, &req->qdio_req, fsf_cfdc->sg); |
2366 | 2379 | ||
2367 | if (bytes != ZFCP_CFDC_MAX_SIZE) { | 2380 | if (retval || |
2381 | (zfcp_qdio_real_bytes(fsf_cfdc->sg) != ZFCP_CFDC_MAX_SIZE)) { | ||
2368 | zfcp_fsf_req_free(req); | 2382 | zfcp_fsf_req_free(req); |
2383 | retval = -EIO; | ||
2369 | goto out; | 2384 | goto out; |
2370 | } | 2385 | } |
2371 | zfcp_qdio_set_sbale_last(adapter->qdio, &req->qdio_req); | 2386 | zfcp_qdio_set_sbale_last(qdio, &req->qdio_req); |
2387 | if (zfcp_adapter_multi_buffer_active(adapter)) | ||
2388 | zfcp_qdio_set_scount(qdio, &req->qdio_req); | ||
2372 | 2389 | ||
2373 | zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT); | 2390 | zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT); |
2374 | retval = zfcp_fsf_req_send(req); | 2391 | retval = zfcp_fsf_req_send(req); |
diff --git a/drivers/s390/scsi/zfcp_qdio.c b/drivers/s390/scsi/zfcp_qdio.c index d9c40ea73eef..df9e69f54742 100644 --- a/drivers/s390/scsi/zfcp_qdio.c +++ b/drivers/s390/scsi/zfcp_qdio.c | |||
@@ -15,6 +15,10 @@ | |||
15 | 15 | ||
16 | #define QBUFF_PER_PAGE (PAGE_SIZE / sizeof(struct qdio_buffer)) | 16 | #define QBUFF_PER_PAGE (PAGE_SIZE / sizeof(struct qdio_buffer)) |
17 | 17 | ||
18 | static bool enable_multibuffer; | ||
19 | module_param_named(datarouter, enable_multibuffer, bool, 0400); | ||
20 | MODULE_PARM_DESC(datarouter, "Enable hardware data router support"); | ||
21 | |||
18 | static int zfcp_qdio_buffers_enqueue(struct qdio_buffer **sbal) | 22 | static int zfcp_qdio_buffers_enqueue(struct qdio_buffer **sbal) |
19 | { | 23 | { |
20 | int pos; | 24 | int pos; |
@@ -37,8 +41,11 @@ static void zfcp_qdio_handler_error(struct zfcp_qdio *qdio, char *id, | |||
37 | 41 | ||
38 | dev_warn(&adapter->ccw_device->dev, "A QDIO problem occurred\n"); | 42 | dev_warn(&adapter->ccw_device->dev, "A QDIO problem occurred\n"); |
39 | 43 | ||
40 | if (qdio_err & QDIO_ERROR_SLSB_STATE) | 44 | if (qdio_err & QDIO_ERROR_SLSB_STATE) { |
41 | zfcp_qdio_siosl(adapter); | 45 | zfcp_qdio_siosl(adapter); |
46 | zfcp_erp_adapter_shutdown(adapter, 0, id); | ||
47 | return; | ||
48 | } | ||
42 | zfcp_erp_adapter_reopen(adapter, | 49 | zfcp_erp_adapter_reopen(adapter, |
43 | ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED | | 50 | ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED | |
44 | ZFCP_STATUS_COMMON_ERP_FAILED, id); | 51 | ZFCP_STATUS_COMMON_ERP_FAILED, id); |
@@ -93,9 +100,27 @@ static void zfcp_qdio_int_resp(struct ccw_device *cdev, unsigned int qdio_err, | |||
93 | unsigned long parm) | 100 | unsigned long parm) |
94 | { | 101 | { |
95 | struct zfcp_qdio *qdio = (struct zfcp_qdio *) parm; | 102 | struct zfcp_qdio *qdio = (struct zfcp_qdio *) parm; |
96 | int sbal_idx, sbal_no; | 103 | struct zfcp_adapter *adapter = qdio->adapter; |
104 | struct qdio_buffer_element *sbale; | ||
105 | int sbal_no, sbal_idx; | ||
106 | void *pl[ZFCP_QDIO_MAX_SBALS_PER_REQ + 1]; | ||
107 | u64 req_id; | ||
108 | u8 scount; | ||
97 | 109 | ||
98 | if (unlikely(qdio_err)) { | 110 | if (unlikely(qdio_err)) { |
111 | memset(pl, 0, ZFCP_QDIO_MAX_SBALS_PER_REQ * sizeof(void *)); | ||
112 | if (zfcp_adapter_multi_buffer_active(adapter)) { | ||
113 | sbale = qdio->res_q[idx]->element; | ||
114 | req_id = (u64) sbale->addr; | ||
115 | scount = sbale->scount + 1; /* incl. signaling SBAL */ | ||
116 | |||
117 | for (sbal_no = 0; sbal_no < scount; sbal_no++) { | ||
118 | sbal_idx = (idx + sbal_no) % | ||
119 | QDIO_MAX_BUFFERS_PER_Q; | ||
120 | pl[sbal_no] = qdio->res_q[sbal_idx]; | ||
121 | } | ||
122 | zfcp_dbf_hba_def_err(adapter, req_id, scount, pl); | ||
123 | } | ||
99 | zfcp_qdio_handler_error(qdio, "qdires1", qdio_err); | 124 | zfcp_qdio_handler_error(qdio, "qdires1", qdio_err); |
100 | return; | 125 | return; |
101 | } | 126 | } |
@@ -155,7 +180,7 @@ zfcp_qdio_sbal_chain(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req) | |||
155 | static struct qdio_buffer_element * | 180 | static struct qdio_buffer_element * |
156 | zfcp_qdio_sbale_next(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req) | 181 | zfcp_qdio_sbale_next(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req) |
157 | { | 182 | { |
158 | if (q_req->sbale_curr == ZFCP_QDIO_LAST_SBALE_PER_SBAL) | 183 | if (q_req->sbale_curr == qdio->max_sbale_per_sbal - 1) |
159 | return zfcp_qdio_sbal_chain(qdio, q_req); | 184 | return zfcp_qdio_sbal_chain(qdio, q_req); |
160 | q_req->sbale_curr++; | 185 | q_req->sbale_curr++; |
161 | return zfcp_qdio_sbale_curr(qdio, q_req); | 186 | return zfcp_qdio_sbale_curr(qdio, q_req); |
@@ -167,13 +192,12 @@ zfcp_qdio_sbale_next(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req) | |||
167 | * @q_req: pointer to struct zfcp_qdio_req | 192 | * @q_req: pointer to struct zfcp_qdio_req |
168 | * @sg: scatter-gather list | 193 | * @sg: scatter-gather list |
169 | * @max_sbals: upper bound for number of SBALs to be used | 194 | * @max_sbals: upper bound for number of SBALs to be used |
170 | * Returns: number of bytes, or error (negativ) | 195 | * Returns: zero or -EINVAL on error |
171 | */ | 196 | */ |
172 | int zfcp_qdio_sbals_from_sg(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req, | 197 | int zfcp_qdio_sbals_from_sg(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req, |
173 | struct scatterlist *sg) | 198 | struct scatterlist *sg) |
174 | { | 199 | { |
175 | struct qdio_buffer_element *sbale; | 200 | struct qdio_buffer_element *sbale; |
176 | int bytes = 0; | ||
177 | 201 | ||
178 | /* set storage-block type for this request */ | 202 | /* set storage-block type for this request */ |
179 | sbale = zfcp_qdio_sbale_req(qdio, q_req); | 203 | sbale = zfcp_qdio_sbale_req(qdio, q_req); |
@@ -187,14 +211,10 @@ int zfcp_qdio_sbals_from_sg(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req, | |||
187 | q_req->sbal_number); | 211 | q_req->sbal_number); |
188 | return -EINVAL; | 212 | return -EINVAL; |
189 | } | 213 | } |
190 | |||
191 | sbale->addr = sg_virt(sg); | 214 | sbale->addr = sg_virt(sg); |
192 | sbale->length = sg->length; | 215 | sbale->length = sg->length; |
193 | |||
194 | bytes += sg->length; | ||
195 | } | 216 | } |
196 | 217 | return 0; | |
197 | return bytes; | ||
198 | } | 218 | } |
199 | 219 | ||
200 | static int zfcp_qdio_sbal_check(struct zfcp_qdio *qdio) | 220 | static int zfcp_qdio_sbal_check(struct zfcp_qdio *qdio) |
@@ -283,6 +303,8 @@ static void zfcp_qdio_setup_init_data(struct qdio_initialize *id, | |||
283 | memcpy(id->adapter_name, dev_name(&id->cdev->dev), 8); | 303 | memcpy(id->adapter_name, dev_name(&id->cdev->dev), 8); |
284 | ASCEBC(id->adapter_name, 8); | 304 | ASCEBC(id->adapter_name, 8); |
285 | id->qib_rflags = QIB_RFLAGS_ENABLE_DATA_DIV; | 305 | id->qib_rflags = QIB_RFLAGS_ENABLE_DATA_DIV; |
306 | if (enable_multibuffer) | ||
307 | id->qdr_ac |= QDR_AC_MULTI_BUFFER_ENABLE; | ||
286 | id->no_input_qs = 1; | 308 | id->no_input_qs = 1; |
287 | id->no_output_qs = 1; | 309 | id->no_output_qs = 1; |
288 | id->input_handler = zfcp_qdio_int_resp; | 310 | id->input_handler = zfcp_qdio_int_resp; |
@@ -378,6 +400,17 @@ int zfcp_qdio_open(struct zfcp_qdio *qdio) | |||
378 | atomic_set_mask(ZFCP_STATUS_ADAPTER_DATA_DIV_ENABLED, | 400 | atomic_set_mask(ZFCP_STATUS_ADAPTER_DATA_DIV_ENABLED, |
379 | &qdio->adapter->status); | 401 | &qdio->adapter->status); |
380 | 402 | ||
403 | if (ssqd.qdioac2 & CHSC_AC2_MULTI_BUFFER_ENABLED) { | ||
404 | atomic_set_mask(ZFCP_STATUS_ADAPTER_MB_ACT, &adapter->status); | ||
405 | qdio->max_sbale_per_sbal = QDIO_MAX_ELEMENTS_PER_BUFFER; | ||
406 | } else { | ||
407 | atomic_clear_mask(ZFCP_STATUS_ADAPTER_MB_ACT, &adapter->status); | ||
408 | qdio->max_sbale_per_sbal = QDIO_MAX_ELEMENTS_PER_BUFFER - 1; | ||
409 | } | ||
410 | |||
411 | qdio->max_sbale_per_req = | ||
412 | ZFCP_QDIO_MAX_SBALS_PER_REQ * qdio->max_sbale_per_sbal | ||
413 | - 2; | ||
381 | if (qdio_activate(cdev)) | 414 | if (qdio_activate(cdev)) |
382 | goto failed_qdio; | 415 | goto failed_qdio; |
383 | 416 | ||
@@ -397,6 +430,11 @@ int zfcp_qdio_open(struct zfcp_qdio *qdio) | |||
397 | atomic_set(&qdio->req_q_free, QDIO_MAX_BUFFERS_PER_Q); | 430 | atomic_set(&qdio->req_q_free, QDIO_MAX_BUFFERS_PER_Q); |
398 | atomic_set_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &qdio->adapter->status); | 431 | atomic_set_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &qdio->adapter->status); |
399 | 432 | ||
433 | if (adapter->scsi_host) { | ||
434 | adapter->scsi_host->sg_tablesize = qdio->max_sbale_per_req; | ||
435 | adapter->scsi_host->max_sectors = qdio->max_sbale_per_req * 8; | ||
436 | } | ||
437 | |||
400 | return 0; | 438 | return 0; |
401 | 439 | ||
402 | failed_qdio: | 440 | failed_qdio: |
diff --git a/drivers/s390/scsi/zfcp_qdio.h b/drivers/s390/scsi/zfcp_qdio.h index 54e22ace012b..8ac7f5342d29 100644 --- a/drivers/s390/scsi/zfcp_qdio.h +++ b/drivers/s390/scsi/zfcp_qdio.h | |||
@@ -13,20 +13,9 @@ | |||
13 | 13 | ||
14 | #define ZFCP_QDIO_SBALE_LEN PAGE_SIZE | 14 | #define ZFCP_QDIO_SBALE_LEN PAGE_SIZE |
15 | 15 | ||
16 | /* DMQ bug workaround: don't use last SBALE */ | ||
17 | #define ZFCP_QDIO_MAX_SBALES_PER_SBAL (QDIO_MAX_ELEMENTS_PER_BUFFER - 1) | ||
18 | |||
19 | /* index of last SBALE (with respect to DMQ bug workaround) */ | ||
20 | #define ZFCP_QDIO_LAST_SBALE_PER_SBAL (ZFCP_QDIO_MAX_SBALES_PER_SBAL - 1) | ||
21 | |||
22 | /* Max SBALS for chaining */ | 16 | /* Max SBALS for chaining */ |
23 | #define ZFCP_QDIO_MAX_SBALS_PER_REQ 36 | 17 | #define ZFCP_QDIO_MAX_SBALS_PER_REQ 36 |
24 | 18 | ||
25 | /* max. number of (data buffer) SBALEs in largest SBAL chain | ||
26 | * request ID + QTCB in SBALE 0 + 1 of first SBAL in chain */ | ||
27 | #define ZFCP_QDIO_MAX_SBALES_PER_REQ \ | ||
28 | (ZFCP_QDIO_MAX_SBALS_PER_REQ * ZFCP_QDIO_MAX_SBALES_PER_SBAL - 2) | ||
29 | |||
30 | /** | 19 | /** |
31 | * struct zfcp_qdio - basic qdio data structure | 20 | * struct zfcp_qdio - basic qdio data structure |
32 | * @res_q: response queue | 21 | * @res_q: response queue |
@@ -53,6 +42,8 @@ struct zfcp_qdio { | |||
53 | atomic_t req_q_full; | 42 | atomic_t req_q_full; |
54 | wait_queue_head_t req_q_wq; | 43 | wait_queue_head_t req_q_wq; |
55 | struct zfcp_adapter *adapter; | 44 | struct zfcp_adapter *adapter; |
45 | u16 max_sbale_per_sbal; | ||
46 | u16 max_sbale_per_req; | ||
56 | }; | 47 | }; |
57 | 48 | ||
58 | /** | 49 | /** |
@@ -155,7 +146,7 @@ void zfcp_qdio_fill_next(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req, | |||
155 | { | 146 | { |
156 | struct qdio_buffer_element *sbale; | 147 | struct qdio_buffer_element *sbale; |
157 | 148 | ||
158 | BUG_ON(q_req->sbale_curr == ZFCP_QDIO_LAST_SBALE_PER_SBAL); | 149 | BUG_ON(q_req->sbale_curr == qdio->max_sbale_per_sbal - 1); |
159 | q_req->sbale_curr++; | 150 | q_req->sbale_curr++; |
160 | sbale = zfcp_qdio_sbale_curr(qdio, q_req); | 151 | sbale = zfcp_qdio_sbale_curr(qdio, q_req); |
161 | sbale->addr = data; | 152 | sbale->addr = data; |
@@ -195,9 +186,10 @@ int zfcp_qdio_sg_one_sbale(struct scatterlist *sg) | |||
195 | * @q_req: The current zfcp_qdio_req | 186 | * @q_req: The current zfcp_qdio_req |
196 | */ | 187 | */ |
197 | static inline | 188 | static inline |
198 | void zfcp_qdio_skip_to_last_sbale(struct zfcp_qdio_req *q_req) | 189 | void zfcp_qdio_skip_to_last_sbale(struct zfcp_qdio *qdio, |
190 | struct zfcp_qdio_req *q_req) | ||
199 | { | 191 | { |
200 | q_req->sbale_curr = ZFCP_QDIO_LAST_SBALE_PER_SBAL; | 192 | q_req->sbale_curr = qdio->max_sbale_per_sbal - 1; |
201 | } | 193 | } |
202 | 194 | ||
203 | /** | 195 | /** |
@@ -228,8 +220,52 @@ void zfcp_qdio_set_data_div(struct zfcp_qdio *qdio, | |||
228 | { | 220 | { |
229 | struct qdio_buffer_element *sbale; | 221 | struct qdio_buffer_element *sbale; |
230 | 222 | ||
231 | sbale = &qdio->req_q[q_req->sbal_first]->element[0]; | 223 | sbale = qdio->req_q[q_req->sbal_first]->element; |
232 | sbale->length = count; | 224 | sbale->length = count; |
233 | } | 225 | } |
234 | 226 | ||
227 | /** | ||
228 | * zfcp_qdio_sbale_count - count sbale used | ||
229 | * @sg: pointer to struct scatterlist | ||
230 | */ | ||
231 | static inline | ||
232 | unsigned int zfcp_qdio_sbale_count(struct scatterlist *sg) | ||
233 | { | ||
234 | unsigned int count = 0; | ||
235 | |||
236 | for (; sg; sg = sg_next(sg)) | ||
237 | count++; | ||
238 | |||
239 | return count; | ||
240 | } | ||
241 | |||
242 | /** | ||
243 | * zfcp_qdio_real_bytes - count bytes used | ||
244 | * @sg: pointer to struct scatterlist | ||
245 | */ | ||
246 | static inline | ||
247 | unsigned int zfcp_qdio_real_bytes(struct scatterlist *sg) | ||
248 | { | ||
249 | unsigned int real_bytes = 0; | ||
250 | |||
251 | for (; sg; sg = sg_next(sg)) | ||
252 | real_bytes += sg->length; | ||
253 | |||
254 | return real_bytes; | ||
255 | } | ||
256 | |||
257 | /** | ||
258 | * zfcp_qdio_set_scount - set SBAL count value | ||
259 | * @qdio: pointer to struct zfcp_qdio | ||
260 | * @q_req: The current zfcp_qdio_req | ||
261 | */ | ||
262 | static inline | ||
263 | void zfcp_qdio_set_scount(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req) | ||
264 | { | ||
265 | struct qdio_buffer_element *sbale; | ||
266 | |||
267 | sbale = qdio->req_q[q_req->sbal_first]->element; | ||
268 | sbale->scount = q_req->sbal_number - 1; | ||
269 | } | ||
270 | |||
235 | #endif /* ZFCP_QDIO_H */ | 271 | #endif /* ZFCP_QDIO_H */ |
diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c index 96c31a70445f..09126a9d62ff 100644 --- a/drivers/s390/scsi/zfcp_scsi.c +++ b/drivers/s390/scsi/zfcp_scsi.c | |||
@@ -306,8 +306,8 @@ static struct scsi_host_template zfcp_scsi_host_template = { | |||
306 | .proc_name = "zfcp", | 306 | .proc_name = "zfcp", |
307 | .can_queue = 4096, | 307 | .can_queue = 4096, |
308 | .this_id = -1, | 308 | .this_id = -1, |
309 | .sg_tablesize = ZFCP_QDIO_MAX_SBALES_PER_REQ, | 309 | .sg_tablesize = 1, /* adjusted later */ |
310 | .max_sectors = (ZFCP_QDIO_MAX_SBALES_PER_REQ * 8), | 310 | .max_sectors = 8, /* adjusted later */ |
311 | .dma_boundary = ZFCP_QDIO_SBALE_LEN - 1, | 311 | .dma_boundary = ZFCP_QDIO_SBALE_LEN - 1, |
312 | .cmd_per_lun = 1, | 312 | .cmd_per_lun = 1, |
313 | .use_clustering = 1, | 313 | .use_clustering = 1, |
@@ -665,9 +665,9 @@ void zfcp_scsi_set_prot(struct zfcp_adapter *adapter) | |||
665 | adapter->adapter_features & FSF_FEATURE_DIX_PROT_TCPIP) { | 665 | adapter->adapter_features & FSF_FEATURE_DIX_PROT_TCPIP) { |
666 | mask |= SHOST_DIX_TYPE1_PROTECTION; | 666 | mask |= SHOST_DIX_TYPE1_PROTECTION; |
667 | scsi_host_set_guard(shost, SHOST_DIX_GUARD_IP); | 667 | scsi_host_set_guard(shost, SHOST_DIX_GUARD_IP); |
668 | shost->sg_prot_tablesize = ZFCP_QDIO_MAX_SBALES_PER_REQ / 2; | 668 | shost->sg_prot_tablesize = adapter->qdio->max_sbale_per_req / 2; |
669 | shost->sg_tablesize = ZFCP_QDIO_MAX_SBALES_PER_REQ / 2; | 669 | shost->sg_tablesize = adapter->qdio->max_sbale_per_req / 2; |
670 | shost->max_sectors = ZFCP_QDIO_MAX_SBALES_PER_REQ * 8 / 2; | 670 | shost->max_sectors = shost->sg_tablesize * 8; |
671 | } | 671 | } |
672 | 672 | ||
673 | scsi_host_set_prot(shost, mask); | 673 | scsi_host_set_prot(shost, mask); |