18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * sd_dif.c - SCSI Data Integrity Field 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2007, 2008 Oracle Corporation 68c2ecf20Sopenharmony_ci * Written by: Martin K. Petersen <martin.petersen@oracle.com> 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <linux/blkdev.h> 108c2ecf20Sopenharmony_ci#include <linux/t10-pi.h> 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include <scsi/scsi.h> 138c2ecf20Sopenharmony_ci#include <scsi/scsi_cmnd.h> 148c2ecf20Sopenharmony_ci#include <scsi/scsi_dbg.h> 158c2ecf20Sopenharmony_ci#include <scsi/scsi_device.h> 168c2ecf20Sopenharmony_ci#include <scsi/scsi_driver.h> 178c2ecf20Sopenharmony_ci#include <scsi/scsi_eh.h> 188c2ecf20Sopenharmony_ci#include <scsi/scsi_host.h> 198c2ecf20Sopenharmony_ci#include <scsi/scsi_ioctl.h> 208c2ecf20Sopenharmony_ci#include <scsi/scsicam.h> 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#include "sd.h" 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci/* 258c2ecf20Sopenharmony_ci * Configure exchange of protection information between OS and HBA. 268c2ecf20Sopenharmony_ci */ 278c2ecf20Sopenharmony_civoid sd_dif_config_host(struct scsi_disk *sdkp) 288c2ecf20Sopenharmony_ci{ 298c2ecf20Sopenharmony_ci struct scsi_device *sdp = sdkp->device; 308c2ecf20Sopenharmony_ci struct gendisk *disk = sdkp->disk; 318c2ecf20Sopenharmony_ci u8 type = sdkp->protection_type; 328c2ecf20Sopenharmony_ci struct blk_integrity bi; 338c2ecf20Sopenharmony_ci int dif, dix; 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci dif = scsi_host_dif_capable(sdp->host, type); 368c2ecf20Sopenharmony_ci dix = scsi_host_dix_capable(sdp->host, type); 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci if (!dix && scsi_host_dix_capable(sdp->host, 0)) { 398c2ecf20Sopenharmony_ci dif = 0; dix = 1; 408c2ecf20Sopenharmony_ci } 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci if (!dix) 438c2ecf20Sopenharmony_ci return; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci memset(&bi, 0, sizeof(bi)); 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci /* Enable DMA of protection information */ 488c2ecf20Sopenharmony_ci if (scsi_host_get_guard(sdkp->device->host) & SHOST_DIX_GUARD_IP) { 498c2ecf20Sopenharmony_ci if (type == T10_PI_TYPE3_PROTECTION) 508c2ecf20Sopenharmony_ci bi.profile = &t10_pi_type3_ip; 518c2ecf20Sopenharmony_ci else 528c2ecf20Sopenharmony_ci bi.profile = &t10_pi_type1_ip; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci bi.flags |= BLK_INTEGRITY_IP_CHECKSUM; 558c2ecf20Sopenharmony_ci } else 568c2ecf20Sopenharmony_ci if (type == T10_PI_TYPE3_PROTECTION) 578c2ecf20Sopenharmony_ci bi.profile = &t10_pi_type3_crc; 588c2ecf20Sopenharmony_ci else 598c2ecf20Sopenharmony_ci bi.profile = &t10_pi_type1_crc; 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci bi.tuple_size = sizeof(struct t10_pi_tuple); 628c2ecf20Sopenharmony_ci sd_printk(KERN_NOTICE, sdkp, 638c2ecf20Sopenharmony_ci "Enabling DIX %s protection\n", bi.profile->name); 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci if (dif && type) { 668c2ecf20Sopenharmony_ci bi.flags |= BLK_INTEGRITY_DEVICE_CAPABLE; 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci if (!sdkp->ATO) 698c2ecf20Sopenharmony_ci goto out; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci if (type == T10_PI_TYPE3_PROTECTION) 728c2ecf20Sopenharmony_ci bi.tag_size = sizeof(u16) + sizeof(u32); 738c2ecf20Sopenharmony_ci else 748c2ecf20Sopenharmony_ci bi.tag_size = sizeof(u16); 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci sd_printk(KERN_NOTICE, sdkp, "DIF application tag size %u\n", 778c2ecf20Sopenharmony_ci bi.tag_size); 788c2ecf20Sopenharmony_ci } 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ciout: 818c2ecf20Sopenharmony_ci blk_integrity_register(disk, &bi); 828c2ecf20Sopenharmony_ci} 838c2ecf20Sopenharmony_ci 84