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/scsi/zfcp_fsf.c | |
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/scsi/zfcp_fsf.c')
-rw-r--r-- | drivers/s390/scsi/zfcp_fsf.c | 109 |
1 files changed, 86 insertions, 23 deletions
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); |