Commit ef3eb71d8ba4fd9d48c5f9310bc9d90ca00323b4
Committed by
James Bottomley
1 parent
dcc18f48a2
Exists in
master
and in
20 other branches
[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>
Showing 10 changed files with 189 additions and 30 deletions Side-by-side Diff
drivers/s390/scsi/zfcp_dbf.c
... | ... | @@ -155,6 +155,8 @@ |
155 | 155 | if (scsi_cmnd) { |
156 | 156 | response->u.fcp.cmnd = (unsigned long)scsi_cmnd; |
157 | 157 | response->u.fcp.serial = scsi_cmnd->serial_number; |
158 | + response->u.fcp.data_dir = | |
159 | + qtcb->bottom.io.data_direction; | |
158 | 160 | } |
159 | 161 | break; |
160 | 162 | |
... | ... | @@ -326,6 +328,7 @@ |
326 | 328 | case FSF_QTCB_FCP_CMND: |
327 | 329 | if (r->fsf_req_status & ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT) |
328 | 330 | break; |
331 | + zfcp_dbf_out(p, "data_direction", "0x%04x", r->u.fcp.data_dir); | |
329 | 332 | zfcp_dbf_out(p, "scsi_cmnd", "0x%0Lx", r->u.fcp.cmnd); |
330 | 333 | zfcp_dbf_out(p, "scsi_serial", "0x%016Lx", r->u.fcp.serial); |
331 | 334 | *p += sprintf(*p, "\n"); |
drivers/s390/scsi/zfcp_dbf.h
drivers/s390/scsi/zfcp_ext.h
... | ... | @@ -164,6 +164,8 @@ |
164 | 164 | extern void zfcp_scsi_schedule_rports_block(struct zfcp_adapter *); |
165 | 165 | extern void zfcp_scsi_scan(struct zfcp_unit *); |
166 | 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 | 170 | /* zfcp_sysfs.c */ |
169 | 171 | extern struct attribute_group zfcp_sysfs_unit_attrs; |
drivers/s390/scsi/zfcp_fc.h
drivers/s390/scsi/zfcp_fsf.c
... | ... | @@ -526,6 +526,8 @@ |
526 | 526 | return -EIO; |
527 | 527 | } |
528 | 528 | |
529 | + zfcp_scsi_set_prot(adapter); | |
530 | + | |
529 | 531 | return 0; |
530 | 532 | } |
531 | 533 | |
... | ... | @@ -988,6 +990,7 @@ |
988 | 990 | bytes = zfcp_qdio_sbals_from_sg(adapter->qdio, &req->qdio_req, sg_req); |
989 | 991 | if (bytes <= 0) |
990 | 992 | return -EIO; |
993 | + zfcp_qdio_set_sbale_last(adapter->qdio, &req->qdio_req); | |
991 | 994 | req->qtcb->bottom.support.req_buf_length = bytes; |
992 | 995 | zfcp_qdio_skip_to_last_sbale(&req->qdio_req); |
993 | 996 | |
... | ... | @@ -996,6 +999,7 @@ |
996 | 999 | req->qtcb->bottom.support.resp_buf_length = bytes; |
997 | 1000 | if (bytes <= 0) |
998 | 1001 | return -EIO; |
1002 | + zfcp_qdio_set_sbale_last(adapter->qdio, &req->qdio_req); | |
999 | 1003 | |
1000 | 1004 | return 0; |
1001 | 1005 | } |
1002 | 1006 | |
... | ... | @@ -2038,9 +2042,13 @@ |
2038 | 2042 | blktrc.fabric_lat = lat_in->fabric_lat * ticks; |
2039 | 2043 | |
2040 | 2044 | switch (req->qtcb->bottom.io.data_direction) { |
2045 | + case FSF_DATADIR_DIF_READ_STRIP: | |
2046 | + case FSF_DATADIR_DIF_READ_CONVERT: | |
2041 | 2047 | case FSF_DATADIR_READ: |
2042 | 2048 | lat = &unit->latencies.read; |
2043 | 2049 | break; |
2050 | + case FSF_DATADIR_DIF_WRITE_INSERT: | |
2051 | + case FSF_DATADIR_DIF_WRITE_CONVERT: | |
2044 | 2052 | case FSF_DATADIR_WRITE: |
2045 | 2053 | lat = &unit->latencies.write; |
2046 | 2054 | break; |
... | ... | @@ -2081,6 +2089,21 @@ |
2081 | 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 | 2107 | fcp_rsp = (struct fcp_resp_with_ext *) &req->qtcb->bottom.io.fcp_rsp; |
2085 | 2108 | zfcp_fc_eval_fcp_rsp(fcp_rsp, scpnt); |
2086 | 2109 | |
... | ... | @@ -2190,6 +2213,44 @@ |
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 | 2255 | * zfcp_fsf_send_fcp_command_task - initiate an FCP command (for a SCSI command) |
2195 | 2256 | * @unit: unit where command is sent to |
2196 | 2257 | |
... | ... | @@ -2201,9 +2262,10 @@ |
2201 | 2262 | struct zfcp_fsf_req *req; |
2202 | 2263 | struct fcp_cmnd *fcp_cmnd; |
2203 | 2264 | unsigned int sbtype = SBAL_FLAGS0_TYPE_READ; |
2204 | - int real_bytes, retval = -EIO; | |
2265 | + int real_bytes, retval = -EIO, dix_bytes = 0; | |
2205 | 2266 | struct zfcp_adapter *adapter = unit->port->adapter; |
2206 | 2267 | struct zfcp_qdio *qdio = adapter->qdio; |
2268 | + struct fsf_qtcb_bottom_io *io; | |
2207 | 2269 | |
2208 | 2270 | if (unlikely(!(atomic_read(&unit->status) & |
2209 | 2271 | ZFCP_STATUS_COMMON_UNBLOCKED))) |
2210 | 2272 | |
2211 | 2273 | |
2212 | 2274 | |
2213 | 2275 | |
2214 | 2276 | |
2215 | 2277 | |
... | ... | @@ -2226,46 +2288,46 @@ |
2226 | 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 | 2294 | req->status |= ZFCP_STATUS_FSFREQ_CLEANUP; |
2230 | 2295 | req->unit = unit; |
2231 | 2296 | req->data = scsi_cmnd; |
2232 | 2297 | req->handler = zfcp_fsf_send_fcp_command_handler; |
2233 | 2298 | req->qtcb->header.lun_handle = unit->handle; |
2234 | 2299 | req->qtcb->header.port_handle = unit->port->handle; |
2235 | - req->qtcb->bottom.io.service_class = FSF_CLASS_3; | |
2236 | - req->qtcb->bottom.io.fcp_cmnd_length = FCP_CMND_LEN; | |
2300 | + io->service_class = FSF_CLASS_3; | |
2301 | + io->fcp_cmnd_length = FCP_CMND_LEN; | |
2237 | 2302 | |
2238 | - scsi_cmnd->host_scribble = (unsigned char *) req->req_id; | |
2239 | - | |
2240 | - /* | |
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; | |
2303 | + if (scsi_get_prot_op(scsi_cmnd) != SCSI_PROT_NORMAL) { | |
2304 | + io->data_block_length = scsi_cmnd->device->sector_size; | |
2305 | + io->ref_tag_value = scsi_get_lba(scsi_cmnd) & 0xFFFFFFFF; | |
2257 | 2306 | } |
2258 | 2307 | |
2308 | + zfcp_fsf_set_data_dir(scsi_cmnd, &io->data_direction); | |
2309 | + | |
2259 | 2310 | get_device(&unit->dev); |
2260 | 2311 | |
2261 | 2312 | fcp_cmnd = (struct fcp_cmnd *) &req->qtcb->bottom.io.fcp_cmnd; |
2262 | 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 | 2323 | real_bytes = zfcp_qdio_sbals_from_sg(qdio, &req->qdio_req, |
2265 | 2324 | scsi_sglist(scsi_cmnd)); |
2266 | - if (unlikely(real_bytes < 0)) | |
2325 | + | |
2326 | + if (unlikely(real_bytes < 0) || unlikely(dix_bytes < 0)) | |
2267 | 2327 | goto failed_scsi_cmnd; |
2268 | 2328 | |
2329 | + zfcp_qdio_set_sbale_last(adapter->qdio, &req->qdio_req); | |
2330 | + | |
2269 | 2331 | retval = zfcp_fsf_req_send(req); |
2270 | 2332 | if (unlikely(retval)) |
2271 | 2333 | goto failed_scsi_cmnd; |
... | ... | @@ -2389,6 +2451,7 @@ |
2389 | 2451 | zfcp_fsf_req_free(req); |
2390 | 2452 | goto out; |
2391 | 2453 | } |
2454 | + zfcp_qdio_set_sbale_last(adapter->qdio, &req->qdio_req); | |
2392 | 2455 | |
2393 | 2456 | zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT); |
2394 | 2457 | retval = zfcp_fsf_req_send(req); |
drivers/s390/scsi/zfcp_fsf.h
... | ... | @@ -80,11 +80,15 @@ |
80 | 80 | #define FSF_REQUEST_SIZE_TOO_LARGE 0x00000061 |
81 | 81 | #define FSF_RESPONSE_SIZE_TOO_LARGE 0x00000062 |
82 | 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 | 88 | #define FSF_ADAPTER_STATUS_AVAILABLE 0x000000AD |
84 | 89 | #define FSF_UNKNOWN_COMMAND 0x000000E2 |
85 | 90 | #define FSF_UNKNOWN_OP_SUBTYPE 0x000000E3 |
86 | 91 | #define FSF_INVALID_COMMAND_OPTION 0x000000E5 |
87 | -/* #define FSF_ERROR 0x000000FF */ | |
88 | 92 | |
89 | 93 | #define FSF_PROT_STATUS_QUAL_SIZE 16 |
90 | 94 | #define FSF_STATUS_QUALIFIER_SIZE 16 |
91 | 95 | |
... | ... | @@ -147,7 +151,14 @@ |
147 | 151 | #define FSF_DATADIR_WRITE 0x00000001 |
148 | 152 | #define FSF_DATADIR_READ 0x00000002 |
149 | 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 | |
150 | 158 | |
159 | +/* data protection control flags */ | |
160 | +#define FSF_APP_TAG_CHECK_ENABLE 0x10 | |
161 | + | |
151 | 162 | /* fc service class */ |
152 | 163 | #define FSF_CLASS_3 0x00000003 |
153 | 164 | |
... | ... | @@ -162,6 +173,8 @@ |
162 | 173 | #define FSF_FEATURE_ELS_CT_CHAINED_SBALS 0x00000020 |
163 | 174 | #define FSF_FEATURE_UPDATE_ALERT 0x00000100 |
164 | 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 | 179 | /* host connection features */ |
167 | 180 | #define FSF_FEATURE_NPIV_MODE 0x00000001 |
168 | 181 | |
... | ... | @@ -316,9 +329,14 @@ |
316 | 329 | struct fsf_qtcb_bottom_io { |
317 | 330 | u32 data_direction; |
318 | 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 | 336 | u32 fcp_cmnd_length; |
321 | - u8 res2[12]; | |
337 | + u32 data_block_length; | |
338 | + u32 prot_data_length; | |
339 | + u8 res2[4]; | |
322 | 340 | u8 fcp_cmnd[FSF_FCP_CMND_SIZE]; |
323 | 341 | u8 fcp_rsp[FSF_FCP_RSP_SIZE]; |
324 | 342 | u8 res3[64]; |
drivers/s390/scsi/zfcp_qdio.c
drivers/s390/scsi/zfcp_qdio.h
... | ... | @@ -215,5 +215,21 @@ |
215 | 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 | 234 | #endif /* ZFCP_QDIO_H */ |
drivers/s390/scsi/zfcp_scsi.c
... | ... | @@ -12,6 +12,7 @@ |
12 | 12 | #include <linux/types.h> |
13 | 13 | #include <linux/slab.h> |
14 | 14 | #include <scsi/fc/fc_fcp.h> |
15 | +#include <scsi/scsi_eh.h> | |
15 | 16 | #include <asm/atomic.h> |
16 | 17 | #include "zfcp_ext.h" |
17 | 18 | #include "zfcp_dbf.h" |
... | ... | @@ -22,6 +23,13 @@ |
22 | 23 | module_param_named(queue_depth, default_depth, uint, 0600); |
23 | 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 | 33 | static int zfcp_scsi_change_queue_depth(struct scsi_device *sdev, int depth, |
26 | 34 | int reason) |
27 | 35 | { |
... | ... | @@ -650,6 +658,51 @@ |
650 | 658 | |
651 | 659 | zfcp_scsi_scan(unit); |
652 | 660 | put_device(&unit->dev); |
661 | +} | |
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); | |
653 | 706 | } |
654 | 707 | |
655 | 708 | struct fc_function_template zfcp_transport_functions = { |
drivers/scsi/Kconfig
... | ... | @@ -1847,6 +1847,10 @@ |
1847 | 1847 | called zfcp. If you want to compile it as a module, say M here |
1848 | 1848 | and read <file:Documentation/kbuild/modules.txt>. |
1849 | 1849 | |
1850 | +config ZFCP_DIF | |
1851 | + tristate "T10 DIF/DIX support for the zfcp driver (EXPERIMENTAL)" | |
1852 | + depends on ZFCP && EXPERIMENTAL | |
1853 | + | |
1850 | 1854 | config SCSI_PMCRAID |
1851 | 1855 | tristate "PMC SIERRA Linux MaxRAID adapter support" |
1852 | 1856 | depends on PCI && SCSI |