162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * sd_dif.c - SCSI Data Integrity Field 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2007, 2008 Oracle Corporation 662306a36Sopenharmony_ci * Written by: Martin K. Petersen <martin.petersen@oracle.com> 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/blk-integrity.h> 1062306a36Sopenharmony_ci#include <linux/t10-pi.h> 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include <scsi/scsi.h> 1362306a36Sopenharmony_ci#include <scsi/scsi_cmnd.h> 1462306a36Sopenharmony_ci#include <scsi/scsi_dbg.h> 1562306a36Sopenharmony_ci#include <scsi/scsi_device.h> 1662306a36Sopenharmony_ci#include <scsi/scsi_driver.h> 1762306a36Sopenharmony_ci#include <scsi/scsi_eh.h> 1862306a36Sopenharmony_ci#include <scsi/scsi_host.h> 1962306a36Sopenharmony_ci#include <scsi/scsi_ioctl.h> 2062306a36Sopenharmony_ci#include <scsi/scsicam.h> 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci#include "sd.h" 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci/* 2562306a36Sopenharmony_ci * Configure exchange of protection information between OS and HBA. 2662306a36Sopenharmony_ci */ 2762306a36Sopenharmony_civoid sd_dif_config_host(struct scsi_disk *sdkp) 2862306a36Sopenharmony_ci{ 2962306a36Sopenharmony_ci struct scsi_device *sdp = sdkp->device; 3062306a36Sopenharmony_ci struct gendisk *disk = sdkp->disk; 3162306a36Sopenharmony_ci u8 type = sdkp->protection_type; 3262306a36Sopenharmony_ci struct blk_integrity bi; 3362306a36Sopenharmony_ci int dif, dix; 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci dif = scsi_host_dif_capable(sdp->host, type); 3662306a36Sopenharmony_ci dix = scsi_host_dix_capable(sdp->host, type); 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci if (!dix && scsi_host_dix_capable(sdp->host, 0)) { 3962306a36Sopenharmony_ci dif = 0; dix = 1; 4062306a36Sopenharmony_ci } 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci if (!dix) { 4362306a36Sopenharmony_ci blk_integrity_unregister(disk); 4462306a36Sopenharmony_ci return; 4562306a36Sopenharmony_ci } 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci memset(&bi, 0, sizeof(bi)); 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci /* Enable DMA of protection information */ 5062306a36Sopenharmony_ci if (scsi_host_get_guard(sdkp->device->host) & SHOST_DIX_GUARD_IP) { 5162306a36Sopenharmony_ci if (type == T10_PI_TYPE3_PROTECTION) 5262306a36Sopenharmony_ci bi.profile = &t10_pi_type3_ip; 5362306a36Sopenharmony_ci else 5462306a36Sopenharmony_ci bi.profile = &t10_pi_type1_ip; 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci bi.flags |= BLK_INTEGRITY_IP_CHECKSUM; 5762306a36Sopenharmony_ci } else 5862306a36Sopenharmony_ci if (type == T10_PI_TYPE3_PROTECTION) 5962306a36Sopenharmony_ci bi.profile = &t10_pi_type3_crc; 6062306a36Sopenharmony_ci else 6162306a36Sopenharmony_ci bi.profile = &t10_pi_type1_crc; 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci bi.tuple_size = sizeof(struct t10_pi_tuple); 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci if (dif && type) { 6662306a36Sopenharmony_ci bi.flags |= BLK_INTEGRITY_DEVICE_CAPABLE; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci if (!sdkp->ATO) 6962306a36Sopenharmony_ci goto out; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci if (type == T10_PI_TYPE3_PROTECTION) 7262306a36Sopenharmony_ci bi.tag_size = sizeof(u16) + sizeof(u32); 7362306a36Sopenharmony_ci else 7462306a36Sopenharmony_ci bi.tag_size = sizeof(u16); 7562306a36Sopenharmony_ci } 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci sd_first_printk(KERN_NOTICE, sdkp, 7862306a36Sopenharmony_ci "Enabling DIX %s, application tag size %u bytes\n", 7962306a36Sopenharmony_ci bi.profile->name, bi.tag_size); 8062306a36Sopenharmony_ciout: 8162306a36Sopenharmony_ci blk_integrity_register(disk, &bi); 8262306a36Sopenharmony_ci} 8362306a36Sopenharmony_ci 84