aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi
diff options
context:
space:
mode:
authorMartin K. Petersen <martin.petersen@oracle.com>2014-09-26 19:20:08 -0400
committerJens Axboe <axboe@fb.com>2014-09-30 17:17:35 -0400
commitc611529e7cd3465ec0eada0f44200e8420c38908 (patch)
treec1cbfbd9b3229906ec36c897761d06e1521823bd /drivers/scsi
parent582940508b5d589229d0232e0eeee8fef0d54809 (diff)
sd: Honor block layer integrity handling flags
A set of flags introduced in the block layer enable better control over how protection information is handled. These flags are useful for both error injection and data recovery purposes. Checking can be enabled and disabled for controller and disk, and the guard tag format is now a per-I/O property. Update sd_protect_op to communicate the relevant information to the low-level device driver via a set of flags in scsi_cmnd. Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com> Reviewed-by: Sagi Grimberg <sagig@mellanox.com> Acked-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Jens Axboe <axboe@fb.com>
Diffstat (limited to 'drivers/scsi')
-rw-r--r--drivers/scsi/sd.c73
-rw-r--r--drivers/scsi/sd.h66
-rw-r--r--drivers/scsi/sd_dif.c23
3 files changed, 116 insertions, 46 deletions
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index 2c2041ca4b70..9f7099f4b537 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -610,29 +610,44 @@ static void scsi_disk_put(struct scsi_disk *sdkp)
610 mutex_unlock(&sd_ref_mutex); 610 mutex_unlock(&sd_ref_mutex);
611} 611}
612 612
613static void sd_prot_op(struct scsi_cmnd *scmd, unsigned int dif) 613
614{ 614
615 unsigned int prot_op = SCSI_PROT_NORMAL; 615static unsigned char sd_setup_protect_cmnd(struct scsi_cmnd *scmd,
616 unsigned int dix = scsi_prot_sg_count(scmd); 616 unsigned int dix, unsigned int dif)
617 617{
618 if (scmd->sc_data_direction == DMA_FROM_DEVICE) { 618 struct bio *bio = scmd->request->bio;
619 if (dif && dix) 619 unsigned int prot_op = sd_prot_op(rq_data_dir(scmd->request), dix, dif);
620 prot_op = SCSI_PROT_READ_PASS; 620 unsigned int protect = 0;
621 else if (dif && !dix) 621
622 prot_op = SCSI_PROT_READ_STRIP; 622 if (dix) { /* DIX Type 0, 1, 2, 3 */
623 else if (!dif && dix) 623 if (bio_integrity_flagged(bio, BIP_IP_CHECKSUM))
624 prot_op = SCSI_PROT_READ_INSERT; 624 scmd->prot_flags |= SCSI_PROT_IP_CHECKSUM;
625 } else { 625
626 if (dif && dix) 626 if (bio_integrity_flagged(bio, BIP_CTRL_NOCHECK) == false)
627 prot_op = SCSI_PROT_WRITE_PASS; 627 scmd->prot_flags |= SCSI_PROT_GUARD_CHECK;
628 else if (dif && !dix) 628 }
629 prot_op = SCSI_PROT_WRITE_INSERT; 629
630 else if (!dif && dix) 630 if (dif != SD_DIF_TYPE3_PROTECTION) { /* DIX/DIF Type 0, 1, 2 */
631 prot_op = SCSI_PROT_WRITE_STRIP; 631 scmd->prot_flags |= SCSI_PROT_REF_INCREMENT;
632
633 if (bio_integrity_flagged(bio, BIP_CTRL_NOCHECK) == false)
634 scmd->prot_flags |= SCSI_PROT_REF_CHECK;
635 }
636
637 if (dif) { /* DIX/DIF Type 1, 2, 3 */
638 scmd->prot_flags |= SCSI_PROT_TRANSFER_PI;
639
640 if (bio_integrity_flagged(bio, BIP_DISK_NOCHECK))
641 protect = 3 << 5; /* Disable target PI checking */
642 else
643 protect = 1 << 5; /* Enable target PI checking */
632 } 644 }
633 645
634 scsi_set_prot_op(scmd, prot_op); 646 scsi_set_prot_op(scmd, prot_op);
635 scsi_set_prot_type(scmd, dif); 647 scsi_set_prot_type(scmd, dif);
648 scmd->prot_flags &= sd_prot_flag_mask(prot_op);
649
650 return protect;
636} 651}
637 652
638static void sd_config_discard(struct scsi_disk *sdkp, unsigned int mode) 653static void sd_config_discard(struct scsi_disk *sdkp, unsigned int mode)
@@ -893,7 +908,8 @@ static int sd_setup_read_write_cmnd(struct scsi_cmnd *SCpnt)
893 sector_t block = blk_rq_pos(rq); 908 sector_t block = blk_rq_pos(rq);
894 sector_t threshold; 909 sector_t threshold;
895 unsigned int this_count = blk_rq_sectors(rq); 910 unsigned int this_count = blk_rq_sectors(rq);
896 int ret, host_dif; 911 unsigned int dif, dix;
912 int ret;
897 unsigned char protect; 913 unsigned char protect;
898 914
899 ret = scsi_init_io(SCpnt, GFP_ATOMIC); 915 ret = scsi_init_io(SCpnt, GFP_ATOMIC);
@@ -995,7 +1011,7 @@ static int sd_setup_read_write_cmnd(struct scsi_cmnd *SCpnt)
995 SCpnt->cmnd[0] = WRITE_6; 1011 SCpnt->cmnd[0] = WRITE_6;
996 1012
997 if (blk_integrity_rq(rq)) 1013 if (blk_integrity_rq(rq))
998 sd_dif_prepare(rq, block, sdp->sector_size); 1014 sd_dif_prepare(SCpnt);
999 1015
1000 } else if (rq_data_dir(rq) == READ) { 1016 } else if (rq_data_dir(rq) == READ) {
1001 SCpnt->cmnd[0] = READ_6; 1017 SCpnt->cmnd[0] = READ_6;
@@ -1010,14 +1026,15 @@ static int sd_setup_read_write_cmnd(struct scsi_cmnd *SCpnt)
1010 "writing" : "reading", this_count, 1026 "writing" : "reading", this_count,
1011 blk_rq_sectors(rq))); 1027 blk_rq_sectors(rq)));
1012 1028
1013 /* Set RDPROTECT/WRPROTECT if disk is formatted with DIF */ 1029 dix = scsi_prot_sg_count(SCpnt);
1014 host_dif = scsi_host_dif_capable(sdp->host, sdkp->protection_type); 1030 dif = scsi_host_dif_capable(SCpnt->device->host, sdkp->protection_type);
1015 if (host_dif) 1031
1016 protect = 1 << 5; 1032 if (dif || dix)
1033 protect = sd_setup_protect_cmnd(SCpnt, dix, dif);
1017 else 1034 else
1018 protect = 0; 1035 protect = 0;
1019 1036
1020 if (host_dif == SD_DIF_TYPE2_PROTECTION) { 1037 if (protect && sdkp->protection_type == SD_DIF_TYPE2_PROTECTION) {
1021 SCpnt->cmnd = mempool_alloc(sd_cdb_pool, GFP_ATOMIC); 1038 SCpnt->cmnd = mempool_alloc(sd_cdb_pool, GFP_ATOMIC);
1022 1039
1023 if (unlikely(SCpnt->cmnd == NULL)) { 1040 if (unlikely(SCpnt->cmnd == NULL)) {
@@ -1102,10 +1119,6 @@ static int sd_setup_read_write_cmnd(struct scsi_cmnd *SCpnt)
1102 } 1119 }
1103 SCpnt->sdb.length = this_count * sdp->sector_size; 1120 SCpnt->sdb.length = this_count * sdp->sector_size;
1104 1121
1105 /* If DIF or DIX is enabled, tell HBA how to handle request */
1106 if (host_dif || scsi_prot_sg_count(SCpnt))
1107 sd_prot_op(SCpnt, host_dif);
1108
1109 /* 1122 /*
1110 * We shouldn't disconnect in the middle of a sector, so with a dumb 1123 * We shouldn't disconnect in the middle of a sector, so with a dumb
1111 * host adapter, it's safe to assume that we can at least transfer 1124 * host adapter, it's safe to assume that we can at least transfer
diff --git a/drivers/scsi/sd.h b/drivers/scsi/sd.h
index 4c3ab8377fd3..467377884b63 100644
--- a/drivers/scsi/sd.h
+++ b/drivers/scsi/sd.h
@@ -167,6 +167,68 @@ enum sd_dif_target_protection_types {
167}; 167};
168 168
169/* 169/*
170 * Look up the DIX operation based on whether the command is read or
171 * write and whether dix and dif are enabled.
172 */
173static inline unsigned int sd_prot_op(bool write, bool dix, bool dif)
174{
175 /* Lookup table: bit 2 (write), bit 1 (dix), bit 0 (dif) */
176 const unsigned int ops[] = { /* wrt dix dif */
177 SCSI_PROT_NORMAL, /* 0 0 0 */
178 SCSI_PROT_READ_STRIP, /* 0 0 1 */
179 SCSI_PROT_READ_INSERT, /* 0 1 0 */
180 SCSI_PROT_READ_PASS, /* 0 1 1 */
181 SCSI_PROT_NORMAL, /* 1 0 0 */
182 SCSI_PROT_WRITE_INSERT, /* 1 0 1 */
183 SCSI_PROT_WRITE_STRIP, /* 1 1 0 */
184 SCSI_PROT_WRITE_PASS, /* 1 1 1 */
185 };
186
187 return ops[write << 2 | dix << 1 | dif];
188}
189
190/*
191 * Returns a mask of the protection flags that are valid for a given DIX
192 * operation.
193 */
194static inline unsigned int sd_prot_flag_mask(unsigned int prot_op)
195{
196 const unsigned int flag_mask[] = {
197 [SCSI_PROT_NORMAL] = 0,
198
199 [SCSI_PROT_READ_STRIP] = SCSI_PROT_TRANSFER_PI |
200 SCSI_PROT_GUARD_CHECK |
201 SCSI_PROT_REF_CHECK |
202 SCSI_PROT_REF_INCREMENT,
203
204 [SCSI_PROT_READ_INSERT] = SCSI_PROT_REF_INCREMENT |
205 SCSI_PROT_IP_CHECKSUM,
206
207 [SCSI_PROT_READ_PASS] = SCSI_PROT_TRANSFER_PI |
208 SCSI_PROT_GUARD_CHECK |
209 SCSI_PROT_REF_CHECK |
210 SCSI_PROT_REF_INCREMENT |
211 SCSI_PROT_IP_CHECKSUM,
212
213 [SCSI_PROT_WRITE_INSERT] = SCSI_PROT_TRANSFER_PI |
214 SCSI_PROT_REF_INCREMENT,
215
216 [SCSI_PROT_WRITE_STRIP] = SCSI_PROT_GUARD_CHECK |
217 SCSI_PROT_REF_CHECK |
218 SCSI_PROT_REF_INCREMENT |
219 SCSI_PROT_IP_CHECKSUM,
220
221 [SCSI_PROT_WRITE_PASS] = SCSI_PROT_TRANSFER_PI |
222 SCSI_PROT_GUARD_CHECK |
223 SCSI_PROT_REF_CHECK |
224 SCSI_PROT_REF_INCREMENT |
225 SCSI_PROT_IP_CHECKSUM,
226 };
227
228 return flag_mask[prot_op];
229}
230
231/*
170 * Data Integrity Field tuple. 232 * Data Integrity Field tuple.
171 */ 233 */
172struct sd_dif_tuple { 234struct sd_dif_tuple {
@@ -178,7 +240,7 @@ struct sd_dif_tuple {
178#ifdef CONFIG_BLK_DEV_INTEGRITY 240#ifdef CONFIG_BLK_DEV_INTEGRITY
179 241
180extern void sd_dif_config_host(struct scsi_disk *); 242extern void sd_dif_config_host(struct scsi_disk *);
181extern void sd_dif_prepare(struct request *rq, sector_t, unsigned int); 243extern void sd_dif_prepare(struct scsi_cmnd *scmd);
182extern void sd_dif_complete(struct scsi_cmnd *, unsigned int); 244extern void sd_dif_complete(struct scsi_cmnd *, unsigned int);
183 245
184#else /* CONFIG_BLK_DEV_INTEGRITY */ 246#else /* CONFIG_BLK_DEV_INTEGRITY */
@@ -186,7 +248,7 @@ extern void sd_dif_complete(struct scsi_cmnd *, unsigned int);
186static inline void sd_dif_config_host(struct scsi_disk *disk) 248static inline void sd_dif_config_host(struct scsi_disk *disk)
187{ 249{
188} 250}
189static inline int sd_dif_prepare(struct request *rq, sector_t s, unsigned int a) 251static inline int sd_dif_prepare(struct scsi_cmnd *scmd)
190{ 252{
191 return 0; 253 return 0;
192} 254}
diff --git a/drivers/scsi/sd_dif.c b/drivers/scsi/sd_dif.c
index b7eaeadc18f9..14c7d42a11c2 100644
--- a/drivers/scsi/sd_dif.c
+++ b/drivers/scsi/sd_dif.c
@@ -106,8 +106,7 @@ void sd_dif_config_host(struct scsi_disk *sdkp)
106 * 106 *
107 * Type 3 does not have a reference tag so no remapping is required. 107 * Type 3 does not have a reference tag so no remapping is required.
108 */ 108 */
109void sd_dif_prepare(struct request *rq, sector_t hw_sector, 109void sd_dif_prepare(struct scsi_cmnd *scmd)
110 unsigned int sector_sz)
111{ 110{
112 const int tuple_sz = sizeof(struct t10_pi_tuple); 111 const int tuple_sz = sizeof(struct t10_pi_tuple);
113 struct bio *bio; 112 struct bio *bio;
@@ -115,14 +114,14 @@ void sd_dif_prepare(struct request *rq, sector_t hw_sector,
115 struct t10_pi_tuple *pi; 114 struct t10_pi_tuple *pi;
116 u32 phys, virt; 115 u32 phys, virt;
117 116
118 sdkp = rq->bio->bi_bdev->bd_disk->private_data; 117 sdkp = scsi_disk(scmd->request->rq_disk);
119 118
120 if (sdkp->protection_type == SD_DIF_TYPE3_PROTECTION) 119 if (sdkp->protection_type == SD_DIF_TYPE3_PROTECTION)
121 return; 120 return;
122 121
123 phys = hw_sector & 0xffffffff; 122 phys = scsi_prot_ref_tag(scmd);
124 123
125 __rq_for_each_bio(bio, rq) { 124 __rq_for_each_bio(bio, scmd->request) {
126 struct bio_integrity_payload *bip = bio_integrity(bio); 125 struct bio_integrity_payload *bip = bio_integrity(bio);
127 struct bio_vec iv; 126 struct bio_vec iv;
128 struct bvec_iter iter; 127 struct bvec_iter iter;
@@ -163,7 +162,7 @@ void sd_dif_complete(struct scsi_cmnd *scmd, unsigned int good_bytes)
163 struct scsi_disk *sdkp; 162 struct scsi_disk *sdkp;
164 struct bio *bio; 163 struct bio *bio;
165 struct t10_pi_tuple *pi; 164 struct t10_pi_tuple *pi;
166 unsigned int j, sectors, sector_sz; 165 unsigned int j, intervals;
167 u32 phys, virt; 166 u32 phys, virt;
168 167
169 sdkp = scsi_disk(scmd->request->rq_disk); 168 sdkp = scsi_disk(scmd->request->rq_disk);
@@ -171,12 +170,8 @@ void sd_dif_complete(struct scsi_cmnd *scmd, unsigned int good_bytes)
171 if (sdkp->protection_type == SD_DIF_TYPE3_PROTECTION || good_bytes == 0) 170 if (sdkp->protection_type == SD_DIF_TYPE3_PROTECTION || good_bytes == 0)
172 return; 171 return;
173 172
174 sector_sz = scmd->device->sector_size; 173 intervals = good_bytes / scsi_prot_interval(scmd);
175 sectors = good_bytes / sector_sz; 174 phys = scsi_prot_ref_tag(scmd);
176
177 phys = blk_rq_pos(scmd->request) & 0xffffffff;
178 if (sector_sz == 4096)
179 phys >>= 3;
180 175
181 __rq_for_each_bio(bio, scmd->request) { 176 __rq_for_each_bio(bio, scmd->request) {
182 struct bio_integrity_payload *bip = bio_integrity(bio); 177 struct bio_integrity_payload *bip = bio_integrity(bio);
@@ -190,7 +185,7 @@ void sd_dif_complete(struct scsi_cmnd *scmd, unsigned int good_bytes)
190 185
191 for (j = 0; j < iv.bv_len; j += tuple_sz, pi++) { 186 for (j = 0; j < iv.bv_len; j += tuple_sz, pi++) {
192 187
193 if (sectors == 0) { 188 if (intervals == 0) {
194 kunmap_atomic(pi); 189 kunmap_atomic(pi);
195 return; 190 return;
196 } 191 }
@@ -200,7 +195,7 @@ void sd_dif_complete(struct scsi_cmnd *scmd, unsigned int good_bytes)
200 195
201 virt++; 196 virt++;
202 phys++; 197 phys++;
203 sectors--; 198 intervals--;
204 } 199 }
205 200
206 kunmap_atomic(pi); 201 kunmap_atomic(pi);