Commit ef3eb71d8ba4fd9d48c5f9310bc9d90ca00323b4

Authored by Felix Beck
Committed by James Bottomley
1 parent dcc18f48a2

[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
... ... @@ -111,6 +111,7 @@
111 111 struct {
112 112 u64 cmnd;
113 113 u64 serial;
  114 + u32 data_dir;
114 115 } fcp;
115 116 struct {
116 117 u64 wwpn;
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
... ... @@ -220,6 +220,9 @@
220 220 memcpy(fcp->fc_cdb, scsi->cmnd, scsi->cmd_len);
221 221  
222 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 /**
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
... ... @@ -193,10 +193,6 @@
193 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 196 return bytes;
201 197 }
202 198  
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