diff options
author | Felix Beck <felix.beck@de.ibm.com> | 2010-07-16 09:37:42 -0400 |
---|---|---|
committer | James Bottomley <James.Bottomley@suse.de> | 2010-07-28 10:48:56 -0400 |
commit | ef3eb71d8ba4fd9d48c5f9310bc9d90ca00323b4 (patch) | |
tree | 9903cbae6c03184687c51b4be926572913cda93f /drivers/s390 | |
parent | dcc18f48a2f1a44c5e8848f30d0cf53a8066c62a (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.c | 3 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_dbf.h | 1 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_ext.h | 2 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_fc.h | 3 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_fsf.c | 109 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_fsf.h | 24 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_qdio.c | 4 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_qdio.h | 16 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_scsi.c | 53 |
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 *); | |||
164 | extern void zfcp_scsi_schedule_rports_block(struct zfcp_adapter *); | 164 | extern void zfcp_scsi_schedule_rports_block(struct zfcp_adapter *); |
165 | extern void zfcp_scsi_scan(struct zfcp_unit *); | 165 | extern void zfcp_scsi_scan(struct zfcp_unit *); |
166 | extern void zfcp_scsi_scan_work(struct work_struct *); | 166 | extern void zfcp_scsi_scan_work(struct work_struct *); |
167 | extern void zfcp_scsi_set_prot(struct zfcp_adapter *); | ||
168 | extern void zfcp_scsi_dif_sense_error(struct scsi_cmnd *, int); | ||
167 | 169 | ||
168 | /* zfcp_sysfs.c */ | 170 | /* zfcp_sysfs.c */ |
169 | extern struct attribute_group zfcp_sysfs_unit_attrs; | 171 | extern 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 | ||
2216 | static 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 { | |||
316 | struct fsf_qtcb_bottom_io { | 329 | struct 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 | */ | ||
224 | static inline | ||
225 | void 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; | |||
22 | module_param_named(queue_depth, default_depth, uint, 0600); | 23 | module_param_named(queue_depth, default_depth, uint, 0600); |
23 | MODULE_PARM_DESC(queue_depth, "Default queue depth for new SCSI devices"); | 24 | MODULE_PARM_DESC(queue_depth, "Default queue depth for new SCSI devices"); |
24 | 25 | ||
26 | static bool enable_dif; | ||
27 | |||
28 | #ifdef CONFIG_ZFCP_DIF | ||
29 | module_param_named(dif, enable_dif, bool, 0600); | ||
30 | MODULE_PARM_DESC(dif, "Enable DIF/DIX data integrity support"); | ||
31 | #endif | ||
32 | |||
25 | static int zfcp_scsi_change_queue_depth(struct scsi_device *sdev, int depth, | 33 | static 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 | */ | ||
667 | void 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 | */ | ||
699 | void 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 | |||
655 | struct fc_function_template zfcp_transport_functions = { | 708 | struct 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, |