aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390
diff options
context:
space:
mode:
authorFelix Beck <felix.beck@de.ibm.com>2010-07-16 09:37:42 -0400
committerJames Bottomley <James.Bottomley@suse.de>2010-07-28 10:48:56 -0400
commitef3eb71d8ba4fd9d48c5f9310bc9d90ca00323b4 (patch)
tree9903cbae6c03184687c51b4be926572913cda93f /drivers/s390
parentdcc18f48a2f1a44c5e8848f30d0cf53a8066c62a (diff)
[SCSI] zfcp: Introduce experimental support for DIF/DIX
Introduce support for DIF/DIX in zfcp: Report the capabilities for the Scsi_host, map the protection data when issuing I/O requests and handle the new error codes. Also add the fsf data_direction field to the hba trace, it is useful information for debugging in that area. This is an EXPERIMENTAL feature for now. Signed-off-by: Felix Beck <felix.beck@de.ibm.com> Signed-off-by: Christof Schmitt <christof.schmitt@de.ibm.com> Signed-off-by: James Bottomley <James.Bottomley@suse.de>
Diffstat (limited to 'drivers/s390')
-rw-r--r--drivers/s390/scsi/zfcp_dbf.c3
-rw-r--r--drivers/s390/scsi/zfcp_dbf.h1
-rw-r--r--drivers/s390/scsi/zfcp_ext.h2
-rw-r--r--drivers/s390/scsi/zfcp_fc.h3
-rw-r--r--drivers/s390/scsi/zfcp_fsf.c109
-rw-r--r--drivers/s390/scsi/zfcp_fsf.h24
-rw-r--r--drivers/s390/scsi/zfcp_qdio.c4
-rw-r--r--drivers/s390/scsi/zfcp_qdio.h16
-rw-r--r--drivers/s390/scsi/zfcp_scsi.c53
9 files changed, 185 insertions, 30 deletions
diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c
index a08d33a96ec9..a86117b0d6e1 100644
--- a/drivers/s390/scsi/zfcp_dbf.c
+++ b/drivers/s390/scsi/zfcp_dbf.c
@@ -155,6 +155,8 @@ void _zfcp_dbf_hba_fsf_response(const char *tag2, int level,
155 if (scsi_cmnd) { 155 if (scsi_cmnd) {
156 response->u.fcp.cmnd = (unsigned long)scsi_cmnd; 156 response->u.fcp.cmnd = (unsigned long)scsi_cmnd;
157 response->u.fcp.serial = scsi_cmnd->serial_number; 157 response->u.fcp.serial = scsi_cmnd->serial_number;
158 response->u.fcp.data_dir =
159 qtcb->bottom.io.data_direction;
158 } 160 }
159 break; 161 break;
160 162
@@ -326,6 +328,7 @@ static void zfcp_dbf_hba_view_response(char **p,
326 case FSF_QTCB_FCP_CMND: 328 case FSF_QTCB_FCP_CMND:
327 if (r->fsf_req_status & ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT) 329 if (r->fsf_req_status & ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT)
328 break; 330 break;
331 zfcp_dbf_out(p, "data_direction", "0x%04x", r->u.fcp.data_dir);
329 zfcp_dbf_out(p, "scsi_cmnd", "0x%0Lx", r->u.fcp.cmnd); 332 zfcp_dbf_out(p, "scsi_cmnd", "0x%0Lx", r->u.fcp.cmnd);
330 zfcp_dbf_out(p, "scsi_serial", "0x%016Lx", r->u.fcp.serial); 333 zfcp_dbf_out(p, "scsi_serial", "0x%016Lx", r->u.fcp.serial);
331 *p += sprintf(*p, "\n"); 334 *p += sprintf(*p, "\n");
diff --git a/drivers/s390/scsi/zfcp_dbf.h b/drivers/s390/scsi/zfcp_dbf.h
index 457e046f2d28..2bcc3403126a 100644
--- a/drivers/s390/scsi/zfcp_dbf.h
+++ b/drivers/s390/scsi/zfcp_dbf.h
@@ -111,6 +111,7 @@ struct zfcp_dbf_hba_record_response {
111 struct { 111 struct {
112 u64 cmnd; 112 u64 cmnd;
113 u64 serial; 113 u64 serial;
114 u32 data_dir;
114 } fcp; 115 } fcp;
115 struct { 116 struct {
116 u64 wwpn; 117 u64 wwpn;
diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h
index a8bb7488dc98..de0925f25dcc 100644
--- a/drivers/s390/scsi/zfcp_ext.h
+++ b/drivers/s390/scsi/zfcp_ext.h
@@ -164,6 +164,8 @@ extern void zfcp_scsi_schedule_rport_block(struct zfcp_port *);
164extern void zfcp_scsi_schedule_rports_block(struct zfcp_adapter *); 164extern void zfcp_scsi_schedule_rports_block(struct zfcp_adapter *);
165extern void zfcp_scsi_scan(struct zfcp_unit *); 165extern void zfcp_scsi_scan(struct zfcp_unit *);
166extern void zfcp_scsi_scan_work(struct work_struct *); 166extern void zfcp_scsi_scan_work(struct work_struct *);
167extern void zfcp_scsi_set_prot(struct zfcp_adapter *);
168extern void zfcp_scsi_dif_sense_error(struct scsi_cmnd *, int);
167 169
168/* zfcp_sysfs.c */ 170/* zfcp_sysfs.c */
169extern struct attribute_group zfcp_sysfs_unit_attrs; 171extern struct attribute_group zfcp_sysfs_unit_attrs;
diff --git a/drivers/s390/scsi/zfcp_fc.h b/drivers/s390/scsi/zfcp_fc.h
index 85c37d2b82c2..938d50360166 100644
--- a/drivers/s390/scsi/zfcp_fc.h
+++ b/drivers/s390/scsi/zfcp_fc.h
@@ -220,6 +220,9 @@ void zfcp_fc_scsi_to_fcp(struct fcp_cmnd *fcp, struct scsi_cmnd *scsi)
220 memcpy(fcp->fc_cdb, scsi->cmnd, scsi->cmd_len); 220 memcpy(fcp->fc_cdb, scsi->cmnd, scsi->cmd_len);
221 221
222 fcp->fc_dl = scsi_bufflen(scsi); 222 fcp->fc_dl = scsi_bufflen(scsi);
223
224 if (scsi_get_prot_type(scsi) == SCSI_PROT_DIF_TYPE1)
225 fcp->fc_dl += fcp->fc_dl / scsi->device->sector_size * 8;
223} 226}
224 227
225/** 228/**
diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c
index 63402fd5f9ae..f9be5d60d92a 100644
--- a/drivers/s390/scsi/zfcp_fsf.c
+++ b/drivers/s390/scsi/zfcp_fsf.c
@@ -526,6 +526,8 @@ static int zfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *req)
526 return -EIO; 526 return -EIO;
527 } 527 }
528 528
529 zfcp_scsi_set_prot(adapter);
530
529 return 0; 531 return 0;
530} 532}
531 533
@@ -988,6 +990,7 @@ static int zfcp_fsf_setup_ct_els_sbals(struct zfcp_fsf_req *req,
988 bytes = zfcp_qdio_sbals_from_sg(adapter->qdio, &req->qdio_req, sg_req); 990 bytes = zfcp_qdio_sbals_from_sg(adapter->qdio, &req->qdio_req, sg_req);
989 if (bytes <= 0) 991 if (bytes <= 0)
990 return -EIO; 992 return -EIO;
993 zfcp_qdio_set_sbale_last(adapter->qdio, &req->qdio_req);
991 req->qtcb->bottom.support.req_buf_length = bytes; 994 req->qtcb->bottom.support.req_buf_length = bytes;
992 zfcp_qdio_skip_to_last_sbale(&req->qdio_req); 995 zfcp_qdio_skip_to_last_sbale(&req->qdio_req);
993 996
@@ -996,6 +999,7 @@ static int zfcp_fsf_setup_ct_els_sbals(struct zfcp_fsf_req *req,
996 req->qtcb->bottom.support.resp_buf_length = bytes; 999 req->qtcb->bottom.support.resp_buf_length = bytes;
997 if (bytes <= 0) 1000 if (bytes <= 0)
998 return -EIO; 1001 return -EIO;
1002 zfcp_qdio_set_sbale_last(adapter->qdio, &req->qdio_req);
999 1003
1000 return 0; 1004 return 0;
1001} 1005}
@@ -2038,9 +2042,13 @@ static void zfcp_fsf_req_trace(struct zfcp_fsf_req *req, struct scsi_cmnd *scsi)
2038 blktrc.fabric_lat = lat_in->fabric_lat * ticks; 2042 blktrc.fabric_lat = lat_in->fabric_lat * ticks;
2039 2043
2040 switch (req->qtcb->bottom.io.data_direction) { 2044 switch (req->qtcb->bottom.io.data_direction) {
2045 case FSF_DATADIR_DIF_READ_STRIP:
2046 case FSF_DATADIR_DIF_READ_CONVERT:
2041 case FSF_DATADIR_READ: 2047 case FSF_DATADIR_READ:
2042 lat = &unit->latencies.read; 2048 lat = &unit->latencies.read;
2043 break; 2049 break;
2050 case FSF_DATADIR_DIF_WRITE_INSERT:
2051 case FSF_DATADIR_DIF_WRITE_CONVERT:
2044 case FSF_DATADIR_WRITE: 2052 case FSF_DATADIR_WRITE:
2045 lat = &unit->latencies.write; 2053 lat = &unit->latencies.write;
2046 break; 2054 break;
@@ -2081,6 +2089,21 @@ static void zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *req)
2081 goto skip_fsfstatus; 2089 goto skip_fsfstatus;
2082 } 2090 }
2083 2091
2092 switch (req->qtcb->header.fsf_status) {
2093 case FSF_INCONSISTENT_PROT_DATA:
2094 case FSF_INVALID_PROT_PARM:
2095 set_host_byte(scpnt, DID_ERROR);
2096 goto skip_fsfstatus;
2097 case FSF_BLOCK_GUARD_CHECK_FAILURE:
2098 zfcp_scsi_dif_sense_error(scpnt, 0x1);
2099 goto skip_fsfstatus;
2100 case FSF_APP_TAG_CHECK_FAILURE:
2101 zfcp_scsi_dif_sense_error(scpnt, 0x2);
2102 goto skip_fsfstatus;
2103 case FSF_REF_TAG_CHECK_FAILURE:
2104 zfcp_scsi_dif_sense_error(scpnt, 0x3);
2105 goto skip_fsfstatus;
2106 }
2084 fcp_rsp = (struct fcp_resp_with_ext *) &req->qtcb->bottom.io.fcp_rsp; 2107 fcp_rsp = (struct fcp_resp_with_ext *) &req->qtcb->bottom.io.fcp_rsp;
2085 zfcp_fc_eval_fcp_rsp(fcp_rsp, scpnt); 2108 zfcp_fc_eval_fcp_rsp(fcp_rsp, scpnt);
2086 2109
@@ -2190,6 +2213,44 @@ skip_fsfstatus:
2190 } 2213 }
2191} 2214}
2192 2215
2216static int zfcp_fsf_set_data_dir(struct scsi_cmnd *scsi_cmnd, u32 *data_dir)
2217{
2218 switch (scsi_get_prot_op(scsi_cmnd)) {
2219 case SCSI_PROT_NORMAL:
2220 switch (scsi_cmnd->sc_data_direction) {
2221 case DMA_NONE:
2222 *data_dir = FSF_DATADIR_CMND;
2223 break;
2224 case DMA_FROM_DEVICE:
2225 *data_dir = FSF_DATADIR_READ;
2226 break;
2227 case DMA_TO_DEVICE:
2228 *data_dir = FSF_DATADIR_WRITE;
2229 break;
2230 case DMA_BIDIRECTIONAL:
2231 return -EINVAL;
2232 }
2233 break;
2234
2235 case SCSI_PROT_READ_STRIP:
2236 *data_dir = FSF_DATADIR_DIF_READ_STRIP;
2237 break;
2238 case SCSI_PROT_WRITE_INSERT:
2239 *data_dir = FSF_DATADIR_DIF_WRITE_INSERT;
2240 break;
2241 case SCSI_PROT_READ_PASS:
2242 *data_dir = FSF_DATADIR_DIF_READ_CONVERT;
2243 break;
2244 case SCSI_PROT_WRITE_PASS:
2245 *data_dir = FSF_DATADIR_DIF_WRITE_CONVERT;
2246 break;
2247 default:
2248 return -EINVAL;
2249 }
2250
2251 return 0;
2252}
2253
2193/** 2254/**
2194 * zfcp_fsf_send_fcp_command_task - initiate an FCP command (for a SCSI command) 2255 * zfcp_fsf_send_fcp_command_task - initiate an FCP command (for a SCSI command)
2195 * @unit: unit where command is sent to 2256 * @unit: unit where command is sent to
@@ -2201,9 +2262,10 @@ int zfcp_fsf_send_fcp_command_task(struct zfcp_unit *unit,
2201 struct zfcp_fsf_req *req; 2262 struct zfcp_fsf_req *req;
2202 struct fcp_cmnd *fcp_cmnd; 2263 struct fcp_cmnd *fcp_cmnd;
2203 unsigned int sbtype = SBAL_FLAGS0_TYPE_READ; 2264 unsigned int sbtype = SBAL_FLAGS0_TYPE_READ;
2204 int real_bytes, retval = -EIO; 2265 int real_bytes, retval = -EIO, dix_bytes = 0;
2205 struct zfcp_adapter *adapter = unit->port->adapter; 2266 struct zfcp_adapter *adapter = unit->port->adapter;
2206 struct zfcp_qdio *qdio = adapter->qdio; 2267 struct zfcp_qdio *qdio = adapter->qdio;
2268 struct fsf_qtcb_bottom_io *io;
2207 2269
2208 if (unlikely(!(atomic_read(&unit->status) & 2270 if (unlikely(!(atomic_read(&unit->status) &
2209 ZFCP_STATUS_COMMON_UNBLOCKED))) 2271 ZFCP_STATUS_COMMON_UNBLOCKED)))
@@ -2226,46 +2288,46 @@ int zfcp_fsf_send_fcp_command_task(struct zfcp_unit *unit,
2226 goto out; 2288 goto out;
2227 } 2289 }
2228 2290
2291 scsi_cmnd->host_scribble = (unsigned char *) req->req_id;
2292
2293 io = &req->qtcb->bottom.io;
2229 req->status |= ZFCP_STATUS_FSFREQ_CLEANUP; 2294 req->status |= ZFCP_STATUS_FSFREQ_CLEANUP;
2230 req->unit = unit; 2295 req->unit = unit;
2231 req->data = scsi_cmnd; 2296 req->data = scsi_cmnd;
2232 req->handler = zfcp_fsf_send_fcp_command_handler; 2297 req->handler = zfcp_fsf_send_fcp_command_handler;
2233 req->qtcb->header.lun_handle = unit->handle; 2298 req->qtcb->header.lun_handle = unit->handle;
2234 req->qtcb->header.port_handle = unit->port->handle; 2299 req->qtcb->header.port_handle = unit->port->handle;
2235 req->qtcb->bottom.io.service_class = FSF_CLASS_3; 2300 io->service_class = FSF_CLASS_3;
2236 req->qtcb->bottom.io.fcp_cmnd_length = FCP_CMND_LEN; 2301 io->fcp_cmnd_length = FCP_CMND_LEN;
2237 2302
2238 scsi_cmnd->host_scribble = (unsigned char *) req->req_id; 2303 if (scsi_get_prot_op(scsi_cmnd) != SCSI_PROT_NORMAL) {
2239 2304 io->data_block_length = scsi_cmnd->device->sector_size;
2240 /* 2305 io->ref_tag_value = scsi_get_lba(scsi_cmnd) & 0xFFFFFFFF;
2241 * set depending on data direction:
2242 * data direction bits in SBALE (SB Type)
2243 * data direction bits in QTCB
2244 */
2245 switch (scsi_cmnd->sc_data_direction) {
2246 case DMA_NONE:
2247 req->qtcb->bottom.io.data_direction = FSF_DATADIR_CMND;
2248 break;
2249 case DMA_FROM_DEVICE:
2250 req->qtcb->bottom.io.data_direction = FSF_DATADIR_READ;
2251 break;
2252 case DMA_TO_DEVICE:
2253 req->qtcb->bottom.io.data_direction = FSF_DATADIR_WRITE;
2254 break;
2255 case DMA_BIDIRECTIONAL:
2256 goto failed_scsi_cmnd;
2257 } 2306 }
2258 2307
2308 zfcp_fsf_set_data_dir(scsi_cmnd, &io->data_direction);
2309
2259 get_device(&unit->dev); 2310 get_device(&unit->dev);
2260 2311
2261 fcp_cmnd = (struct fcp_cmnd *) &req->qtcb->bottom.io.fcp_cmnd; 2312 fcp_cmnd = (struct fcp_cmnd *) &req->qtcb->bottom.io.fcp_cmnd;
2262 zfcp_fc_scsi_to_fcp(fcp_cmnd, scsi_cmnd); 2313 zfcp_fc_scsi_to_fcp(fcp_cmnd, scsi_cmnd);
2263 2314
2315 if (scsi_prot_sg_count(scsi_cmnd)) {
2316 zfcp_qdio_set_data_div(qdio, &req->qdio_req,
2317 scsi_prot_sg_count(scsi_cmnd));
2318 dix_bytes = zfcp_qdio_sbals_from_sg(qdio, &req->qdio_req,
2319 scsi_prot_sglist(scsi_cmnd));
2320 io->prot_data_length = dix_bytes;
2321 }
2322
2264 real_bytes = zfcp_qdio_sbals_from_sg(qdio, &req->qdio_req, 2323 real_bytes = zfcp_qdio_sbals_from_sg(qdio, &req->qdio_req,
2265 scsi_sglist(scsi_cmnd)); 2324 scsi_sglist(scsi_cmnd));
2266 if (unlikely(real_bytes < 0)) 2325
2326 if (unlikely(real_bytes < 0) || unlikely(dix_bytes < 0))
2267 goto failed_scsi_cmnd; 2327 goto failed_scsi_cmnd;
2268 2328
2329 zfcp_qdio_set_sbale_last(adapter->qdio, &req->qdio_req);
2330
2269 retval = zfcp_fsf_req_send(req); 2331 retval = zfcp_fsf_req_send(req);
2270 if (unlikely(retval)) 2332 if (unlikely(retval))
2271 goto failed_scsi_cmnd; 2333 goto failed_scsi_cmnd;
@@ -2389,6 +2451,7 @@ struct zfcp_fsf_req *zfcp_fsf_control_file(struct zfcp_adapter *adapter,
2389 zfcp_fsf_req_free(req); 2451 zfcp_fsf_req_free(req);
2390 goto out; 2452 goto out;
2391 } 2453 }
2454 zfcp_qdio_set_sbale_last(adapter->qdio, &req->qdio_req);
2392 2455
2393 zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT); 2456 zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT);
2394 retval = zfcp_fsf_req_send(req); 2457 retval = zfcp_fsf_req_send(req);
diff --git a/drivers/s390/scsi/zfcp_fsf.h b/drivers/s390/scsi/zfcp_fsf.h
index ca110e386761..db8c85382dca 100644
--- a/drivers/s390/scsi/zfcp_fsf.h
+++ b/drivers/s390/scsi/zfcp_fsf.h
@@ -80,11 +80,15 @@
80#define FSF_REQUEST_SIZE_TOO_LARGE 0x00000061 80#define FSF_REQUEST_SIZE_TOO_LARGE 0x00000061
81#define FSF_RESPONSE_SIZE_TOO_LARGE 0x00000062 81#define FSF_RESPONSE_SIZE_TOO_LARGE 0x00000062
82#define FSF_SBAL_MISMATCH 0x00000063 82#define FSF_SBAL_MISMATCH 0x00000063
83#define FSF_INCONSISTENT_PROT_DATA 0x00000070
84#define FSF_INVALID_PROT_PARM 0x00000071
85#define FSF_BLOCK_GUARD_CHECK_FAILURE 0x00000081
86#define FSF_APP_TAG_CHECK_FAILURE 0x00000082
87#define FSF_REF_TAG_CHECK_FAILURE 0x00000083
83#define FSF_ADAPTER_STATUS_AVAILABLE 0x000000AD 88#define FSF_ADAPTER_STATUS_AVAILABLE 0x000000AD
84#define FSF_UNKNOWN_COMMAND 0x000000E2 89#define FSF_UNKNOWN_COMMAND 0x000000E2
85#define FSF_UNKNOWN_OP_SUBTYPE 0x000000E3 90#define FSF_UNKNOWN_OP_SUBTYPE 0x000000E3
86#define FSF_INVALID_COMMAND_OPTION 0x000000E5 91#define FSF_INVALID_COMMAND_OPTION 0x000000E5
87/* #define FSF_ERROR 0x000000FF */
88 92
89#define FSF_PROT_STATUS_QUAL_SIZE 16 93#define FSF_PROT_STATUS_QUAL_SIZE 16
90#define FSF_STATUS_QUALIFIER_SIZE 16 94#define FSF_STATUS_QUALIFIER_SIZE 16
@@ -147,6 +151,13 @@
147#define FSF_DATADIR_WRITE 0x00000001 151#define FSF_DATADIR_WRITE 0x00000001
148#define FSF_DATADIR_READ 0x00000002 152#define FSF_DATADIR_READ 0x00000002
149#define FSF_DATADIR_CMND 0x00000004 153#define FSF_DATADIR_CMND 0x00000004
154#define FSF_DATADIR_DIF_WRITE_INSERT 0x00000009
155#define FSF_DATADIR_DIF_READ_STRIP 0x0000000a
156#define FSF_DATADIR_DIF_WRITE_CONVERT 0x0000000b
157#define FSF_DATADIR_DIF_READ_CONVERT 0X0000000c
158
159/* data protection control flags */
160#define FSF_APP_TAG_CHECK_ENABLE 0x10
150 161
151/* fc service class */ 162/* fc service class */
152#define FSF_CLASS_3 0x00000003 163#define FSF_CLASS_3 0x00000003
@@ -162,6 +173,8 @@
162#define FSF_FEATURE_ELS_CT_CHAINED_SBALS 0x00000020 173#define FSF_FEATURE_ELS_CT_CHAINED_SBALS 0x00000020
163#define FSF_FEATURE_UPDATE_ALERT 0x00000100 174#define FSF_FEATURE_UPDATE_ALERT 0x00000100
164#define FSF_FEATURE_MEASUREMENT_DATA 0x00000200 175#define FSF_FEATURE_MEASUREMENT_DATA 0x00000200
176#define FSF_FEATURE_DIF_PROT_TYPE1 0x00010000
177#define FSF_FEATURE_DIX_PROT_TCPIP 0x00020000
165 178
166/* host connection features */ 179/* host connection features */
167#define FSF_FEATURE_NPIV_MODE 0x00000001 180#define FSF_FEATURE_NPIV_MODE 0x00000001
@@ -316,9 +329,14 @@ struct fsf_qtcb_header {
316struct fsf_qtcb_bottom_io { 329struct fsf_qtcb_bottom_io {
317 u32 data_direction; 330 u32 data_direction;
318 u32 service_class; 331 u32 service_class;
319 u8 res1[8]; 332 u8 res1;
333 u8 data_prot_flags;
334 u16 app_tag_value;
335 u32 ref_tag_value;
320 u32 fcp_cmnd_length; 336 u32 fcp_cmnd_length;
321 u8 res2[12]; 337 u32 data_block_length;
338 u32 prot_data_length;
339 u8 res2[4];
322 u8 fcp_cmnd[FSF_FCP_CMND_SIZE]; 340 u8 fcp_cmnd[FSF_FCP_CMND_SIZE];
323 u8 fcp_rsp[FSF_FCP_RSP_SIZE]; 341 u8 fcp_rsp[FSF_FCP_RSP_SIZE];
324 u8 res3[64]; 342 u8 res3[64];
diff --git a/drivers/s390/scsi/zfcp_qdio.c b/drivers/s390/scsi/zfcp_qdio.c
index c4559b29bebc..aceced8ec7e4 100644
--- a/drivers/s390/scsi/zfcp_qdio.c
+++ b/drivers/s390/scsi/zfcp_qdio.c
@@ -193,10 +193,6 @@ int zfcp_qdio_sbals_from_sg(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req,
193 bytes += sg->length; 193 bytes += sg->length;
194 } 194 }
195 195
196 /* assume that no other SBALEs are to follow in the same SBAL */
197 sbale = zfcp_qdio_sbale_curr(qdio, q_req);
198 sbale->flags |= SBAL_FLAGS_LAST_ENTRY;
199
200 return bytes; 196 return bytes;
201} 197}
202 198
diff --git a/drivers/s390/scsi/zfcp_qdio.h b/drivers/s390/scsi/zfcp_qdio.h
index 10d0df99dbf4..2297d8d3e947 100644
--- a/drivers/s390/scsi/zfcp_qdio.h
+++ b/drivers/s390/scsi/zfcp_qdio.h
@@ -215,4 +215,20 @@ void zfcp_qdio_sbal_limit(struct zfcp_qdio *qdio,
215 QDIO_MAX_BUFFERS_PER_Q; 215 QDIO_MAX_BUFFERS_PER_Q;
216} 216}
217 217
218/**
219 * zfcp_qdio_set_data_div - set data division count
220 * @qdio: pointer to struct zfcp_qdio
221 * @q_req: The current zfcp_qdio_req
222 * @count: The data division count
223 */
224static inline
225void zfcp_qdio_set_data_div(struct zfcp_qdio *qdio,
226 struct zfcp_qdio_req *q_req, u32 count)
227{
228 struct qdio_buffer_element *sbale;
229
230 sbale = &qdio->req_q[q_req->sbal_first]->element[0];
231 sbale->length = count;
232}
233
218#endif /* ZFCP_QDIO_H */ 234#endif /* ZFCP_QDIO_H */
diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c
index eb471a1723cd..cb000c9833bb 100644
--- a/drivers/s390/scsi/zfcp_scsi.c
+++ b/drivers/s390/scsi/zfcp_scsi.c
@@ -12,6 +12,7 @@
12#include <linux/types.h> 12#include <linux/types.h>
13#include <linux/slab.h> 13#include <linux/slab.h>
14#include <scsi/fc/fc_fcp.h> 14#include <scsi/fc/fc_fcp.h>
15#include <scsi/scsi_eh.h>
15#include <asm/atomic.h> 16#include <asm/atomic.h>
16#include "zfcp_ext.h" 17#include "zfcp_ext.h"
17#include "zfcp_dbf.h" 18#include "zfcp_dbf.h"
@@ -22,6 +23,13 @@ static unsigned int default_depth = 32;
22module_param_named(queue_depth, default_depth, uint, 0600); 23module_param_named(queue_depth, default_depth, uint, 0600);
23MODULE_PARM_DESC(queue_depth, "Default queue depth for new SCSI devices"); 24MODULE_PARM_DESC(queue_depth, "Default queue depth for new SCSI devices");
24 25
26static bool enable_dif;
27
28#ifdef CONFIG_ZFCP_DIF
29module_param_named(dif, enable_dif, bool, 0600);
30MODULE_PARM_DESC(dif, "Enable DIF/DIX data integrity support");
31#endif
32
25static int zfcp_scsi_change_queue_depth(struct scsi_device *sdev, int depth, 33static int zfcp_scsi_change_queue_depth(struct scsi_device *sdev, int depth,
26 int reason) 34 int reason)
27{ 35{
@@ -652,6 +660,51 @@ void zfcp_scsi_scan_work(struct work_struct *work)
652 put_device(&unit->dev); 660 put_device(&unit->dev);
653} 661}
654 662
663/**
664 * zfcp_scsi_set_prot - Configure DIF/DIX support in scsi_host
665 * @adapter: The adapter where to configure DIF/DIX for the SCSI host
666 */
667void zfcp_scsi_set_prot(struct zfcp_adapter *adapter)
668{
669 unsigned int mask = 0;
670 unsigned int data_div;
671 struct Scsi_Host *shost = adapter->scsi_host;
672
673 data_div = atomic_read(&adapter->status) &
674 ZFCP_STATUS_ADAPTER_DATA_DIV_ENABLED;
675
676 if (enable_dif &&
677 adapter->adapter_features & FSF_FEATURE_DIF_PROT_TYPE1)
678 mask |= SHOST_DIF_TYPE1_PROTECTION;
679
680 if (enable_dif && data_div &&
681 adapter->adapter_features & FSF_FEATURE_DIX_PROT_TCPIP) {
682 mask |= SHOST_DIX_TYPE1_PROTECTION;
683 scsi_host_set_guard(shost, SHOST_DIX_GUARD_IP);
684 shost->sg_tablesize = ZFCP_QDIO_MAX_SBALES_PER_REQ / 2;
685 shost->max_sectors = ZFCP_QDIO_MAX_SBALES_PER_REQ * 8 / 2;
686 }
687
688 scsi_host_set_prot(shost, mask);
689}
690
691/**
692 * zfcp_scsi_dif_sense_error - Report DIF/DIX error as driver sense error
693 * @scmd: The SCSI command to report the error for
694 * @ascq: The ASCQ to put in the sense buffer
695 *
696 * See the error handling in sd_done for the sense codes used here.
697 * Set DID_SOFT_ERROR to retry the request, if possible.
698 */
699void zfcp_scsi_dif_sense_error(struct scsi_cmnd *scmd, int ascq)
700{
701 scsi_build_sense_buffer(1, scmd->sense_buffer,
702 ILLEGAL_REQUEST, 0x10, ascq);
703 set_driver_byte(scmd, DRIVER_SENSE);
704 scmd->result |= SAM_STAT_CHECK_CONDITION;
705 set_host_byte(scmd, DID_SOFT_ERROR);
706}
707
655struct fc_function_template zfcp_transport_functions = { 708struct fc_function_template zfcp_transport_functions = {
656 .show_starget_port_id = 1, 709 .show_starget_port_id = 1,
657 .show_starget_port_name = 1, 710 .show_starget_port_name = 1,