|
@@ -610,29 +610,44 @@ static void scsi_disk_put(struct scsi_disk *sdkp)
|
|
|
mutex_unlock(&sd_ref_mutex);
|
|
|
}
|
|
|
|
|
|
-static void sd_prot_op(struct scsi_cmnd *scmd, unsigned int dif)
|
|
|
-{
|
|
|
- unsigned int prot_op = SCSI_PROT_NORMAL;
|
|
|
- unsigned int dix = scsi_prot_sg_count(scmd);
|
|
|
-
|
|
|
- if (scmd->sc_data_direction == DMA_FROM_DEVICE) {
|
|
|
- if (dif && dix)
|
|
|
- prot_op = SCSI_PROT_READ_PASS;
|
|
|
- else if (dif && !dix)
|
|
|
- prot_op = SCSI_PROT_READ_STRIP;
|
|
|
- else if (!dif && dix)
|
|
|
- prot_op = SCSI_PROT_READ_INSERT;
|
|
|
- } else {
|
|
|
- if (dif && dix)
|
|
|
- prot_op = SCSI_PROT_WRITE_PASS;
|
|
|
- else if (dif && !dix)
|
|
|
- prot_op = SCSI_PROT_WRITE_INSERT;
|
|
|
- else if (!dif && dix)
|
|
|
- prot_op = SCSI_PROT_WRITE_STRIP;
|
|
|
+
|
|
|
+
|
|
|
+static unsigned char sd_setup_protect_cmnd(struct scsi_cmnd *scmd,
|
|
|
+ unsigned int dix, unsigned int dif)
|
|
|
+{
|
|
|
+ struct bio *bio = scmd->request->bio;
|
|
|
+ unsigned int prot_op = sd_prot_op(rq_data_dir(scmd->request), dix, dif);
|
|
|
+ unsigned int protect = 0;
|
|
|
+
|
|
|
+ if (dix) { /* DIX Type 0, 1, 2, 3 */
|
|
|
+ if (bio_integrity_flagged(bio, BIP_IP_CHECKSUM))
|
|
|
+ scmd->prot_flags |= SCSI_PROT_IP_CHECKSUM;
|
|
|
+
|
|
|
+ if (bio_integrity_flagged(bio, BIP_CTRL_NOCHECK) == false)
|
|
|
+ scmd->prot_flags |= SCSI_PROT_GUARD_CHECK;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (dif != SD_DIF_TYPE3_PROTECTION) { /* DIX/DIF Type 0, 1, 2 */
|
|
|
+ scmd->prot_flags |= SCSI_PROT_REF_INCREMENT;
|
|
|
+
|
|
|
+ if (bio_integrity_flagged(bio, BIP_CTRL_NOCHECK) == false)
|
|
|
+ scmd->prot_flags |= SCSI_PROT_REF_CHECK;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (dif) { /* DIX/DIF Type 1, 2, 3 */
|
|
|
+ scmd->prot_flags |= SCSI_PROT_TRANSFER_PI;
|
|
|
+
|
|
|
+ if (bio_integrity_flagged(bio, BIP_DISK_NOCHECK))
|
|
|
+ protect = 3 << 5; /* Disable target PI checking */
|
|
|
+ else
|
|
|
+ protect = 1 << 5; /* Enable target PI checking */
|
|
|
}
|
|
|
|
|
|
scsi_set_prot_op(scmd, prot_op);
|
|
|
scsi_set_prot_type(scmd, dif);
|
|
|
+ scmd->prot_flags &= sd_prot_flag_mask(prot_op);
|
|
|
+
|
|
|
+ return protect;
|
|
|
}
|
|
|
|
|
|
static 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)
|
|
|
sector_t block = blk_rq_pos(rq);
|
|
|
sector_t threshold;
|
|
|
unsigned int this_count = blk_rq_sectors(rq);
|
|
|
- int ret, host_dif;
|
|
|
+ unsigned int dif, dix;
|
|
|
+ int ret;
|
|
|
unsigned char protect;
|
|
|
|
|
|
ret = scsi_init_io(SCpnt, GFP_ATOMIC);
|
|
@@ -995,7 +1011,7 @@ static int sd_setup_read_write_cmnd(struct scsi_cmnd *SCpnt)
|
|
|
SCpnt->cmnd[0] = WRITE_6;
|
|
|
|
|
|
if (blk_integrity_rq(rq))
|
|
|
- sd_dif_prepare(rq, block, sdp->sector_size);
|
|
|
+ sd_dif_prepare(SCpnt);
|
|
|
|
|
|
} else if (rq_data_dir(rq) == READ) {
|
|
|
SCpnt->cmnd[0] = READ_6;
|
|
@@ -1010,14 +1026,15 @@ static int sd_setup_read_write_cmnd(struct scsi_cmnd *SCpnt)
|
|
|
"writing" : "reading", this_count,
|
|
|
blk_rq_sectors(rq)));
|
|
|
|
|
|
- /* Set RDPROTECT/WRPROTECT if disk is formatted with DIF */
|
|
|
- host_dif = scsi_host_dif_capable(sdp->host, sdkp->protection_type);
|
|
|
- if (host_dif)
|
|
|
- protect = 1 << 5;
|
|
|
+ dix = scsi_prot_sg_count(SCpnt);
|
|
|
+ dif = scsi_host_dif_capable(SCpnt->device->host, sdkp->protection_type);
|
|
|
+
|
|
|
+ if (dif || dix)
|
|
|
+ protect = sd_setup_protect_cmnd(SCpnt, dix, dif);
|
|
|
else
|
|
|
protect = 0;
|
|
|
|
|
|
- if (host_dif == SD_DIF_TYPE2_PROTECTION) {
|
|
|
+ if (protect && sdkp->protection_type == SD_DIF_TYPE2_PROTECTION) {
|
|
|
SCpnt->cmnd = mempool_alloc(sd_cdb_pool, GFP_ATOMIC);
|
|
|
|
|
|
if (unlikely(SCpnt->cmnd == NULL)) {
|
|
@@ -1102,10 +1119,6 @@ static int sd_setup_read_write_cmnd(struct scsi_cmnd *SCpnt)
|
|
|
}
|
|
|
SCpnt->sdb.length = this_count * sdp->sector_size;
|
|
|
|
|
|
- /* If DIF or DIX is enabled, tell HBA how to handle request */
|
|
|
- if (host_dif || scsi_prot_sg_count(SCpnt))
|
|
|
- sd_prot_op(SCpnt, host_dif);
|
|
|
-
|
|
|
/*
|
|
|
* We shouldn't disconnect in the middle of a sector, so with a dumb
|
|
|
* host adapter, it's safe to assume that we can at least transfer
|