aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/scsi/sd.c73
-rw-r--r--drivers/scsi/sd.h66
-rw-r--r--drivers/scsi/sd_dif.c23
-rw-r--r--include/linux/bio.h33
-rw-r--r--include/scsi/scsi_cmnd.h36
5 files changed, 166 insertions, 65 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}