1*af55ff67SMartin K. Petersen /* 2*af55ff67SMartin K. Petersen * sd_dif.c - SCSI Data Integrity Field 3*af55ff67SMartin K. Petersen * 4*af55ff67SMartin K. Petersen * Copyright (C) 2007, 2008 Oracle Corporation 5*af55ff67SMartin K. Petersen * Written by: Martin K. Petersen <martin.petersen@oracle.com> 6*af55ff67SMartin K. Petersen * 7*af55ff67SMartin K. Petersen * This program is free software; you can redistribute it and/or 8*af55ff67SMartin K. Petersen * modify it under the terms of the GNU General Public License version 9*af55ff67SMartin K. Petersen * 2 as published by the Free Software Foundation. 10*af55ff67SMartin K. Petersen * 11*af55ff67SMartin K. Petersen * This program is distributed in the hope that it will be useful, but 12*af55ff67SMartin K. Petersen * WITHOUT ANY WARRANTY; without even the implied warranty of 13*af55ff67SMartin K. Petersen * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14*af55ff67SMartin K. Petersen * General Public License for more details. 15*af55ff67SMartin K. Petersen * 16*af55ff67SMartin K. Petersen * You should have received a copy of the GNU General Public License 17*af55ff67SMartin K. Petersen * along with this program; see the file COPYING. If not, write to 18*af55ff67SMartin K. Petersen * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, 19*af55ff67SMartin K. Petersen * USA. 20*af55ff67SMartin K. Petersen * 21*af55ff67SMartin K. Petersen */ 22*af55ff67SMartin K. Petersen 23*af55ff67SMartin K. Petersen #include <linux/blkdev.h> 24*af55ff67SMartin K. Petersen #include <linux/crc-t10dif.h> 25*af55ff67SMartin K. Petersen 26*af55ff67SMartin K. Petersen #include <scsi/scsi.h> 27*af55ff67SMartin K. Petersen #include <scsi/scsi_cmnd.h> 28*af55ff67SMartin K. Petersen #include <scsi/scsi_dbg.h> 29*af55ff67SMartin K. Petersen #include <scsi/scsi_device.h> 30*af55ff67SMartin K. Petersen #include <scsi/scsi_driver.h> 31*af55ff67SMartin K. Petersen #include <scsi/scsi_eh.h> 32*af55ff67SMartin K. Petersen #include <scsi/scsi_host.h> 33*af55ff67SMartin K. Petersen #include <scsi/scsi_ioctl.h> 34*af55ff67SMartin K. Petersen #include <scsi/scsicam.h> 35*af55ff67SMartin K. Petersen 36*af55ff67SMartin K. Petersen #include <net/checksum.h> 37*af55ff67SMartin K. Petersen 38*af55ff67SMartin K. Petersen #include "sd.h" 39*af55ff67SMartin K. Petersen 40*af55ff67SMartin K. Petersen typedef __u16 (csum_fn) (void *, unsigned int); 41*af55ff67SMartin K. Petersen 42*af55ff67SMartin K. Petersen static __u16 sd_dif_crc_fn(void *data, unsigned int len) 43*af55ff67SMartin K. Petersen { 44*af55ff67SMartin K. Petersen return cpu_to_be16(crc_t10dif(data, len)); 45*af55ff67SMartin K. Petersen } 46*af55ff67SMartin K. Petersen 47*af55ff67SMartin K. Petersen static __u16 sd_dif_ip_fn(void *data, unsigned int len) 48*af55ff67SMartin K. Petersen { 49*af55ff67SMartin K. Petersen return ip_compute_csum(data, len); 50*af55ff67SMartin K. Petersen } 51*af55ff67SMartin K. Petersen 52*af55ff67SMartin K. Petersen /* 53*af55ff67SMartin K. Petersen * Type 1 and Type 2 protection use the same format: 16 bit guard tag, 54*af55ff67SMartin K. Petersen * 16 bit app tag, 32 bit reference tag. 55*af55ff67SMartin K. Petersen */ 56*af55ff67SMartin K. Petersen static void sd_dif_type1_generate(struct blk_integrity_exchg *bix, csum_fn *fn) 57*af55ff67SMartin K. Petersen { 58*af55ff67SMartin K. Petersen void *buf = bix->data_buf; 59*af55ff67SMartin K. Petersen struct sd_dif_tuple *sdt = bix->prot_buf; 60*af55ff67SMartin K. Petersen sector_t sector = bix->sector; 61*af55ff67SMartin K. Petersen unsigned int i; 62*af55ff67SMartin K. Petersen 63*af55ff67SMartin K. Petersen for (i = 0 ; i < bix->data_size ; i += bix->sector_size, sdt++) { 64*af55ff67SMartin K. Petersen sdt->guard_tag = fn(buf, bix->sector_size); 65*af55ff67SMartin K. Petersen sdt->ref_tag = cpu_to_be32(sector & 0xffffffff); 66*af55ff67SMartin K. Petersen sdt->app_tag = 0; 67*af55ff67SMartin K. Petersen 68*af55ff67SMartin K. Petersen buf += bix->sector_size; 69*af55ff67SMartin K. Petersen sector++; 70*af55ff67SMartin K. Petersen } 71*af55ff67SMartin K. Petersen } 72*af55ff67SMartin K. Petersen 73*af55ff67SMartin K. Petersen static void sd_dif_type1_generate_crc(struct blk_integrity_exchg *bix) 74*af55ff67SMartin K. Petersen { 75*af55ff67SMartin K. Petersen sd_dif_type1_generate(bix, sd_dif_crc_fn); 76*af55ff67SMartin K. Petersen } 77*af55ff67SMartin K. Petersen 78*af55ff67SMartin K. Petersen static void sd_dif_type1_generate_ip(struct blk_integrity_exchg *bix) 79*af55ff67SMartin K. Petersen { 80*af55ff67SMartin K. Petersen sd_dif_type1_generate(bix, sd_dif_ip_fn); 81*af55ff67SMartin K. Petersen } 82*af55ff67SMartin K. Petersen 83*af55ff67SMartin K. Petersen static int sd_dif_type1_verify(struct blk_integrity_exchg *bix, csum_fn *fn) 84*af55ff67SMartin K. Petersen { 85*af55ff67SMartin K. Petersen void *buf = bix->data_buf; 86*af55ff67SMartin K. Petersen struct sd_dif_tuple *sdt = bix->prot_buf; 87*af55ff67SMartin K. Petersen sector_t sector = bix->sector; 88*af55ff67SMartin K. Petersen unsigned int i; 89*af55ff67SMartin K. Petersen __u16 csum; 90*af55ff67SMartin K. Petersen 91*af55ff67SMartin K. Petersen for (i = 0 ; i < bix->data_size ; i += bix->sector_size, sdt++) { 92*af55ff67SMartin K. Petersen /* Unwritten sectors */ 93*af55ff67SMartin K. Petersen if (sdt->app_tag == 0xffff) 94*af55ff67SMartin K. Petersen return 0; 95*af55ff67SMartin K. Petersen 96*af55ff67SMartin K. Petersen /* Bad ref tag received from disk */ 97*af55ff67SMartin K. Petersen if (sdt->ref_tag == 0xffffffff) { 98*af55ff67SMartin K. Petersen printk(KERN_ERR 99*af55ff67SMartin K. Petersen "%s: bad phys ref tag on sector %lu\n", 100*af55ff67SMartin K. Petersen bix->disk_name, (unsigned long)sector); 101*af55ff67SMartin K. Petersen return -EIO; 102*af55ff67SMartin K. Petersen } 103*af55ff67SMartin K. Petersen 104*af55ff67SMartin K. Petersen if (be32_to_cpu(sdt->ref_tag) != (sector & 0xffffffff)) { 105*af55ff67SMartin K. Petersen printk(KERN_ERR 106*af55ff67SMartin K. Petersen "%s: ref tag error on sector %lu (rcvd %u)\n", 107*af55ff67SMartin K. Petersen bix->disk_name, (unsigned long)sector, 108*af55ff67SMartin K. Petersen be32_to_cpu(sdt->ref_tag)); 109*af55ff67SMartin K. Petersen return -EIO; 110*af55ff67SMartin K. Petersen } 111*af55ff67SMartin K. Petersen 112*af55ff67SMartin K. Petersen csum = fn(buf, bix->sector_size); 113*af55ff67SMartin K. Petersen 114*af55ff67SMartin K. Petersen if (sdt->guard_tag != csum) { 115*af55ff67SMartin K. Petersen printk(KERN_ERR "%s: guard tag error on sector %lu " \ 116*af55ff67SMartin K. Petersen "(rcvd %04x, data %04x)\n", bix->disk_name, 117*af55ff67SMartin K. Petersen (unsigned long)sector, 118*af55ff67SMartin K. Petersen be16_to_cpu(sdt->guard_tag), be16_to_cpu(csum)); 119*af55ff67SMartin K. Petersen return -EIO; 120*af55ff67SMartin K. Petersen } 121*af55ff67SMartin K. Petersen 122*af55ff67SMartin K. Petersen buf += bix->sector_size; 123*af55ff67SMartin K. Petersen sector++; 124*af55ff67SMartin K. Petersen } 125*af55ff67SMartin K. Petersen 126*af55ff67SMartin K. Petersen return 0; 127*af55ff67SMartin K. Petersen } 128*af55ff67SMartin K. Petersen 129*af55ff67SMartin K. Petersen static int sd_dif_type1_verify_crc(struct blk_integrity_exchg *bix) 130*af55ff67SMartin K. Petersen { 131*af55ff67SMartin K. Petersen return sd_dif_type1_verify(bix, sd_dif_crc_fn); 132*af55ff67SMartin K. Petersen } 133*af55ff67SMartin K. Petersen 134*af55ff67SMartin K. Petersen static int sd_dif_type1_verify_ip(struct blk_integrity_exchg *bix) 135*af55ff67SMartin K. Petersen { 136*af55ff67SMartin K. Petersen return sd_dif_type1_verify(bix, sd_dif_ip_fn); 137*af55ff67SMartin K. Petersen } 138*af55ff67SMartin K. Petersen 139*af55ff67SMartin K. Petersen /* 140*af55ff67SMartin K. Petersen * Functions for interleaving and deinterleaving application tags 141*af55ff67SMartin K. Petersen */ 142*af55ff67SMartin K. Petersen static void sd_dif_type1_set_tag(void *prot, void *tag_buf, unsigned int sectors) 143*af55ff67SMartin K. Petersen { 144*af55ff67SMartin K. Petersen struct sd_dif_tuple *sdt = prot; 145*af55ff67SMartin K. Petersen char *tag = tag_buf; 146*af55ff67SMartin K. Petersen unsigned int i, j; 147*af55ff67SMartin K. Petersen 148*af55ff67SMartin K. Petersen for (i = 0, j = 0 ; i < sectors ; i++, j += 2, sdt++) { 149*af55ff67SMartin K. Petersen sdt->app_tag = tag[j] << 8 | tag[j+1]; 150*af55ff67SMartin K. Petersen BUG_ON(sdt->app_tag == 0xffff); 151*af55ff67SMartin K. Petersen } 152*af55ff67SMartin K. Petersen } 153*af55ff67SMartin K. Petersen 154*af55ff67SMartin K. Petersen static void sd_dif_type1_get_tag(void *prot, void *tag_buf, unsigned int sectors) 155*af55ff67SMartin K. Petersen { 156*af55ff67SMartin K. Petersen struct sd_dif_tuple *sdt = prot; 157*af55ff67SMartin K. Petersen char *tag = tag_buf; 158*af55ff67SMartin K. Petersen unsigned int i, j; 159*af55ff67SMartin K. Petersen 160*af55ff67SMartin K. Petersen for (i = 0, j = 0 ; i < sectors ; i++, j += 2, sdt++) { 161*af55ff67SMartin K. Petersen tag[j] = (sdt->app_tag & 0xff00) >> 8; 162*af55ff67SMartin K. Petersen tag[j+1] = sdt->app_tag & 0xff; 163*af55ff67SMartin K. Petersen } 164*af55ff67SMartin K. Petersen } 165*af55ff67SMartin K. Petersen 166*af55ff67SMartin K. Petersen static struct blk_integrity dif_type1_integrity_crc = { 167*af55ff67SMartin K. Petersen .name = "T10-DIF-TYPE1-CRC", 168*af55ff67SMartin K. Petersen .generate_fn = sd_dif_type1_generate_crc, 169*af55ff67SMartin K. Petersen .verify_fn = sd_dif_type1_verify_crc, 170*af55ff67SMartin K. Petersen .get_tag_fn = sd_dif_type1_get_tag, 171*af55ff67SMartin K. Petersen .set_tag_fn = sd_dif_type1_set_tag, 172*af55ff67SMartin K. Petersen .tuple_size = sizeof(struct sd_dif_tuple), 173*af55ff67SMartin K. Petersen .tag_size = 0, 174*af55ff67SMartin K. Petersen }; 175*af55ff67SMartin K. Petersen 176*af55ff67SMartin K. Petersen static struct blk_integrity dif_type1_integrity_ip = { 177*af55ff67SMartin K. Petersen .name = "T10-DIF-TYPE1-IP", 178*af55ff67SMartin K. Petersen .generate_fn = sd_dif_type1_generate_ip, 179*af55ff67SMartin K. Petersen .verify_fn = sd_dif_type1_verify_ip, 180*af55ff67SMartin K. Petersen .get_tag_fn = sd_dif_type1_get_tag, 181*af55ff67SMartin K. Petersen .set_tag_fn = sd_dif_type1_set_tag, 182*af55ff67SMartin K. Petersen .tuple_size = sizeof(struct sd_dif_tuple), 183*af55ff67SMartin K. Petersen .tag_size = 0, 184*af55ff67SMartin K. Petersen }; 185*af55ff67SMartin K. Petersen 186*af55ff67SMartin K. Petersen 187*af55ff67SMartin K. Petersen /* 188*af55ff67SMartin K. Petersen * Type 3 protection has a 16-bit guard tag and 16 + 32 bits of opaque 189*af55ff67SMartin K. Petersen * tag space. 190*af55ff67SMartin K. Petersen */ 191*af55ff67SMartin K. Petersen static void sd_dif_type3_generate(struct blk_integrity_exchg *bix, csum_fn *fn) 192*af55ff67SMartin K. Petersen { 193*af55ff67SMartin K. Petersen void *buf = bix->data_buf; 194*af55ff67SMartin K. Petersen struct sd_dif_tuple *sdt = bix->prot_buf; 195*af55ff67SMartin K. Petersen unsigned int i; 196*af55ff67SMartin K. Petersen 197*af55ff67SMartin K. Petersen for (i = 0 ; i < bix->data_size ; i += bix->sector_size, sdt++) { 198*af55ff67SMartin K. Petersen sdt->guard_tag = fn(buf, bix->sector_size); 199*af55ff67SMartin K. Petersen sdt->ref_tag = 0; 200*af55ff67SMartin K. Petersen sdt->app_tag = 0; 201*af55ff67SMartin K. Petersen 202*af55ff67SMartin K. Petersen buf += bix->sector_size; 203*af55ff67SMartin K. Petersen } 204*af55ff67SMartin K. Petersen } 205*af55ff67SMartin K. Petersen 206*af55ff67SMartin K. Petersen static void sd_dif_type3_generate_crc(struct blk_integrity_exchg *bix) 207*af55ff67SMartin K. Petersen { 208*af55ff67SMartin K. Petersen sd_dif_type3_generate(bix, sd_dif_crc_fn); 209*af55ff67SMartin K. Petersen } 210*af55ff67SMartin K. Petersen 211*af55ff67SMartin K. Petersen static void sd_dif_type3_generate_ip(struct blk_integrity_exchg *bix) 212*af55ff67SMartin K. Petersen { 213*af55ff67SMartin K. Petersen sd_dif_type3_generate(bix, sd_dif_ip_fn); 214*af55ff67SMartin K. Petersen } 215*af55ff67SMartin K. Petersen 216*af55ff67SMartin K. Petersen static int sd_dif_type3_verify(struct blk_integrity_exchg *bix, csum_fn *fn) 217*af55ff67SMartin K. Petersen { 218*af55ff67SMartin K. Petersen void *buf = bix->data_buf; 219*af55ff67SMartin K. Petersen struct sd_dif_tuple *sdt = bix->prot_buf; 220*af55ff67SMartin K. Petersen sector_t sector = bix->sector; 221*af55ff67SMartin K. Petersen unsigned int i; 222*af55ff67SMartin K. Petersen __u16 csum; 223*af55ff67SMartin K. Petersen 224*af55ff67SMartin K. Petersen for (i = 0 ; i < bix->data_size ; i += bix->sector_size, sdt++) { 225*af55ff67SMartin K. Petersen /* Unwritten sectors */ 226*af55ff67SMartin K. Petersen if (sdt->app_tag == 0xffff && sdt->ref_tag == 0xffffffff) 227*af55ff67SMartin K. Petersen return 0; 228*af55ff67SMartin K. Petersen 229*af55ff67SMartin K. Petersen csum = fn(buf, bix->sector_size); 230*af55ff67SMartin K. Petersen 231*af55ff67SMartin K. Petersen if (sdt->guard_tag != csum) { 232*af55ff67SMartin K. Petersen printk(KERN_ERR "%s: guard tag error on sector %lu " \ 233*af55ff67SMartin K. Petersen "(rcvd %04x, data %04x)\n", bix->disk_name, 234*af55ff67SMartin K. Petersen (unsigned long)sector, 235*af55ff67SMartin K. Petersen be16_to_cpu(sdt->guard_tag), be16_to_cpu(csum)); 236*af55ff67SMartin K. Petersen return -EIO; 237*af55ff67SMartin K. Petersen } 238*af55ff67SMartin K. Petersen 239*af55ff67SMartin K. Petersen buf += bix->sector_size; 240*af55ff67SMartin K. Petersen sector++; 241*af55ff67SMartin K. Petersen } 242*af55ff67SMartin K. Petersen 243*af55ff67SMartin K. Petersen return 0; 244*af55ff67SMartin K. Petersen } 245*af55ff67SMartin K. Petersen 246*af55ff67SMartin K. Petersen static int sd_dif_type3_verify_crc(struct blk_integrity_exchg *bix) 247*af55ff67SMartin K. Petersen { 248*af55ff67SMartin K. Petersen return sd_dif_type3_verify(bix, sd_dif_crc_fn); 249*af55ff67SMartin K. Petersen } 250*af55ff67SMartin K. Petersen 251*af55ff67SMartin K. Petersen static int sd_dif_type3_verify_ip(struct blk_integrity_exchg *bix) 252*af55ff67SMartin K. Petersen { 253*af55ff67SMartin K. Petersen return sd_dif_type3_verify(bix, sd_dif_ip_fn); 254*af55ff67SMartin K. Petersen } 255*af55ff67SMartin K. Petersen 256*af55ff67SMartin K. Petersen static void sd_dif_type3_set_tag(void *prot, void *tag_buf, unsigned int sectors) 257*af55ff67SMartin K. Petersen { 258*af55ff67SMartin K. Petersen struct sd_dif_tuple *sdt = prot; 259*af55ff67SMartin K. Petersen char *tag = tag_buf; 260*af55ff67SMartin K. Petersen unsigned int i, j; 261*af55ff67SMartin K. Petersen 262*af55ff67SMartin K. Petersen for (i = 0, j = 0 ; i < sectors ; i++, j += 6, sdt++) { 263*af55ff67SMartin K. Petersen sdt->app_tag = tag[j] << 8 | tag[j+1]; 264*af55ff67SMartin K. Petersen sdt->ref_tag = tag[j+2] << 24 | tag[j+3] << 16 | 265*af55ff67SMartin K. Petersen tag[j+4] << 8 | tag[j+5]; 266*af55ff67SMartin K. Petersen } 267*af55ff67SMartin K. Petersen } 268*af55ff67SMartin K. Petersen 269*af55ff67SMartin K. Petersen static void sd_dif_type3_get_tag(void *prot, void *tag_buf, unsigned int sectors) 270*af55ff67SMartin K. Petersen { 271*af55ff67SMartin K. Petersen struct sd_dif_tuple *sdt = prot; 272*af55ff67SMartin K. Petersen char *tag = tag_buf; 273*af55ff67SMartin K. Petersen unsigned int i, j; 274*af55ff67SMartin K. Petersen 275*af55ff67SMartin K. Petersen for (i = 0, j = 0 ; i < sectors ; i++, j += 2, sdt++) { 276*af55ff67SMartin K. Petersen tag[j] = (sdt->app_tag & 0xff00) >> 8; 277*af55ff67SMartin K. Petersen tag[j+1] = sdt->app_tag & 0xff; 278*af55ff67SMartin K. Petersen tag[j+2] = (sdt->ref_tag & 0xff000000) >> 24; 279*af55ff67SMartin K. Petersen tag[j+3] = (sdt->ref_tag & 0xff0000) >> 16; 280*af55ff67SMartin K. Petersen tag[j+4] = (sdt->ref_tag & 0xff00) >> 8; 281*af55ff67SMartin K. Petersen tag[j+5] = sdt->ref_tag & 0xff; 282*af55ff67SMartin K. Petersen BUG_ON(sdt->app_tag == 0xffff || sdt->ref_tag == 0xffffffff); 283*af55ff67SMartin K. Petersen } 284*af55ff67SMartin K. Petersen } 285*af55ff67SMartin K. Petersen 286*af55ff67SMartin K. Petersen static struct blk_integrity dif_type3_integrity_crc = { 287*af55ff67SMartin K. Petersen .name = "T10-DIF-TYPE3-CRC", 288*af55ff67SMartin K. Petersen .generate_fn = sd_dif_type3_generate_crc, 289*af55ff67SMartin K. Petersen .verify_fn = sd_dif_type3_verify_crc, 290*af55ff67SMartin K. Petersen .get_tag_fn = sd_dif_type3_get_tag, 291*af55ff67SMartin K. Petersen .set_tag_fn = sd_dif_type3_set_tag, 292*af55ff67SMartin K. Petersen .tuple_size = sizeof(struct sd_dif_tuple), 293*af55ff67SMartin K. Petersen .tag_size = 0, 294*af55ff67SMartin K. Petersen }; 295*af55ff67SMartin K. Petersen 296*af55ff67SMartin K. Petersen static struct blk_integrity dif_type3_integrity_ip = { 297*af55ff67SMartin K. Petersen .name = "T10-DIF-TYPE3-IP", 298*af55ff67SMartin K. Petersen .generate_fn = sd_dif_type3_generate_ip, 299*af55ff67SMartin K. Petersen .verify_fn = sd_dif_type3_verify_ip, 300*af55ff67SMartin K. Petersen .get_tag_fn = sd_dif_type3_get_tag, 301*af55ff67SMartin K. Petersen .set_tag_fn = sd_dif_type3_set_tag, 302*af55ff67SMartin K. Petersen .tuple_size = sizeof(struct sd_dif_tuple), 303*af55ff67SMartin K. Petersen .tag_size = 0, 304*af55ff67SMartin K. Petersen }; 305*af55ff67SMartin K. Petersen 306*af55ff67SMartin K. Petersen /* 307*af55ff67SMartin K. Petersen * Configure exchange of protection information between OS and HBA. 308*af55ff67SMartin K. Petersen */ 309*af55ff67SMartin K. Petersen void sd_dif_config_host(struct scsi_disk *sdkp) 310*af55ff67SMartin K. Petersen { 311*af55ff67SMartin K. Petersen struct scsi_device *sdp = sdkp->device; 312*af55ff67SMartin K. Petersen struct gendisk *disk = sdkp->disk; 313*af55ff67SMartin K. Petersen u8 type = sdkp->protection_type; 314*af55ff67SMartin K. Petersen 315*af55ff67SMartin K. Petersen /* If this HBA doesn't support DIX, resort to normal I/O or DIF */ 316*af55ff67SMartin K. Petersen if (scsi_host_dix_capable(sdp->host, type) == 0) { 317*af55ff67SMartin K. Petersen 318*af55ff67SMartin K. Petersen if (type == SD_DIF_TYPE0_PROTECTION) 319*af55ff67SMartin K. Petersen return; 320*af55ff67SMartin K. Petersen 321*af55ff67SMartin K. Petersen if (scsi_host_dif_capable(sdp->host, type) == 0) { 322*af55ff67SMartin K. Petersen sd_printk(KERN_INFO, sdkp, "Type %d protection " \ 323*af55ff67SMartin K. Petersen "unsupported by HBA. Disabling DIF.\n", type); 324*af55ff67SMartin K. Petersen sdkp->protection_type = 0; 325*af55ff67SMartin K. Petersen return; 326*af55ff67SMartin K. Petersen } 327*af55ff67SMartin K. Petersen 328*af55ff67SMartin K. Petersen sd_printk(KERN_INFO, sdkp, "Enabling DIF Type %d protection\n", 329*af55ff67SMartin K. Petersen type); 330*af55ff67SMartin K. Petersen 331*af55ff67SMartin K. Petersen return; 332*af55ff67SMartin K. Petersen } 333*af55ff67SMartin K. Petersen 334*af55ff67SMartin K. Petersen /* Enable DMA of protection information */ 335*af55ff67SMartin K. Petersen if (scsi_host_get_guard(sdkp->device->host) & SHOST_DIX_GUARD_IP) 336*af55ff67SMartin K. Petersen if (type == SD_DIF_TYPE3_PROTECTION) 337*af55ff67SMartin K. Petersen blk_integrity_register(disk, &dif_type3_integrity_ip); 338*af55ff67SMartin K. Petersen else 339*af55ff67SMartin K. Petersen blk_integrity_register(disk, &dif_type1_integrity_ip); 340*af55ff67SMartin K. Petersen else 341*af55ff67SMartin K. Petersen if (type == SD_DIF_TYPE3_PROTECTION) 342*af55ff67SMartin K. Petersen blk_integrity_register(disk, &dif_type3_integrity_crc); 343*af55ff67SMartin K. Petersen else 344*af55ff67SMartin K. Petersen blk_integrity_register(disk, &dif_type1_integrity_crc); 345*af55ff67SMartin K. Petersen 346*af55ff67SMartin K. Petersen sd_printk(KERN_INFO, sdkp, 347*af55ff67SMartin K. Petersen "Enabling %s integrity protection\n", disk->integrity->name); 348*af55ff67SMartin K. Petersen 349*af55ff67SMartin K. Petersen /* Signal to block layer that we support sector tagging */ 350*af55ff67SMartin K. Petersen if (type && sdkp->ATO) { 351*af55ff67SMartin K. Petersen if (type == SD_DIF_TYPE3_PROTECTION) 352*af55ff67SMartin K. Petersen disk->integrity->tag_size = sizeof(u16) + sizeof(u32); 353*af55ff67SMartin K. Petersen else 354*af55ff67SMartin K. Petersen disk->integrity->tag_size = sizeof(u16); 355*af55ff67SMartin K. Petersen 356*af55ff67SMartin K. Petersen sd_printk(KERN_INFO, sdkp, "DIF application tag size %u\n", 357*af55ff67SMartin K. Petersen disk->integrity->tag_size); 358*af55ff67SMartin K. Petersen } 359*af55ff67SMartin K. Petersen } 360*af55ff67SMartin K. Petersen 361*af55ff67SMartin K. Petersen /* 362*af55ff67SMartin K. Petersen * DIF DMA operation magic decoder ring. 363*af55ff67SMartin K. Petersen */ 364*af55ff67SMartin K. Petersen void sd_dif_op(struct scsi_cmnd *scmd, unsigned int dif, unsigned int dix) 365*af55ff67SMartin K. Petersen { 366*af55ff67SMartin K. Petersen int csum_convert, prot_op; 367*af55ff67SMartin K. Petersen 368*af55ff67SMartin K. Petersen prot_op = 0; 369*af55ff67SMartin K. Petersen 370*af55ff67SMartin K. Petersen /* Convert checksum? */ 371*af55ff67SMartin K. Petersen if (scsi_host_get_guard(scmd->device->host) != SHOST_DIX_GUARD_CRC) 372*af55ff67SMartin K. Petersen csum_convert = 1; 373*af55ff67SMartin K. Petersen else 374*af55ff67SMartin K. Petersen csum_convert = 0; 375*af55ff67SMartin K. Petersen 376*af55ff67SMartin K. Petersen switch (scmd->cmnd[0]) { 377*af55ff67SMartin K. Petersen case READ_10: 378*af55ff67SMartin K. Petersen case READ_12: 379*af55ff67SMartin K. Petersen case READ_16: 380*af55ff67SMartin K. Petersen if (dif && dix) 381*af55ff67SMartin K. Petersen if (csum_convert) 382*af55ff67SMartin K. Petersen prot_op = SCSI_PROT_READ_CONVERT; 383*af55ff67SMartin K. Petersen else 384*af55ff67SMartin K. Petersen prot_op = SCSI_PROT_READ_PASS; 385*af55ff67SMartin K. Petersen else if (dif && !dix) 386*af55ff67SMartin K. Petersen prot_op = SCSI_PROT_READ_STRIP; 387*af55ff67SMartin K. Petersen else if (!dif && dix) 388*af55ff67SMartin K. Petersen prot_op = SCSI_PROT_READ_INSERT; 389*af55ff67SMartin K. Petersen 390*af55ff67SMartin K. Petersen break; 391*af55ff67SMartin K. Petersen 392*af55ff67SMartin K. Petersen case WRITE_10: 393*af55ff67SMartin K. Petersen case WRITE_12: 394*af55ff67SMartin K. Petersen case WRITE_16: 395*af55ff67SMartin K. Petersen if (dif && dix) 396*af55ff67SMartin K. Petersen if (csum_convert) 397*af55ff67SMartin K. Petersen prot_op = SCSI_PROT_WRITE_CONVERT; 398*af55ff67SMartin K. Petersen else 399*af55ff67SMartin K. Petersen prot_op = SCSI_PROT_WRITE_PASS; 400*af55ff67SMartin K. Petersen else if (dif && !dix) 401*af55ff67SMartin K. Petersen prot_op = SCSI_PROT_WRITE_INSERT; 402*af55ff67SMartin K. Petersen else if (!dif && dix) 403*af55ff67SMartin K. Petersen prot_op = SCSI_PROT_WRITE_STRIP; 404*af55ff67SMartin K. Petersen 405*af55ff67SMartin K. Petersen break; 406*af55ff67SMartin K. Petersen } 407*af55ff67SMartin K. Petersen 408*af55ff67SMartin K. Petersen scsi_set_prot_op(scmd, prot_op); 409*af55ff67SMartin K. Petersen scsi_set_prot_type(scmd, dif); 410*af55ff67SMartin K. Petersen } 411*af55ff67SMartin K. Petersen 412*af55ff67SMartin K. Petersen /* 413*af55ff67SMartin K. Petersen * The virtual start sector is the one that was originally submitted 414*af55ff67SMartin K. Petersen * by the block layer. Due to partitioning, MD/DM cloning, etc. the 415*af55ff67SMartin K. Petersen * actual physical start sector is likely to be different. Remap 416*af55ff67SMartin K. Petersen * protection information to match the physical LBA. 417*af55ff67SMartin K. Petersen * 418*af55ff67SMartin K. Petersen * From a protocol perspective there's a slight difference between 419*af55ff67SMartin K. Petersen * Type 1 and 2. The latter uses 32-byte CDBs exclusively, and the 420*af55ff67SMartin K. Petersen * reference tag is seeded in the CDB. This gives us the potential to 421*af55ff67SMartin K. Petersen * avoid virt->phys remapping during write. However, at read time we 422*af55ff67SMartin K. Petersen * don't know whether the virt sector is the same as when we wrote it 423*af55ff67SMartin K. Petersen * (we could be reading from real disk as opposed to MD/DM device. So 424*af55ff67SMartin K. Petersen * we always remap Type 2 making it identical to Type 1. 425*af55ff67SMartin K. Petersen * 426*af55ff67SMartin K. Petersen * Type 3 does not have a reference tag so no remapping is required. 427*af55ff67SMartin K. Petersen */ 428*af55ff67SMartin K. Petersen int sd_dif_prepare(struct request *rq, sector_t hw_sector, unsigned int sector_sz) 429*af55ff67SMartin K. Petersen { 430*af55ff67SMartin K. Petersen const int tuple_sz = sizeof(struct sd_dif_tuple); 431*af55ff67SMartin K. Petersen struct bio *bio; 432*af55ff67SMartin K. Petersen struct scsi_disk *sdkp; 433*af55ff67SMartin K. Petersen struct sd_dif_tuple *sdt; 434*af55ff67SMartin K. Petersen unsigned int i, j; 435*af55ff67SMartin K. Petersen u32 phys, virt; 436*af55ff67SMartin K. Petersen 437*af55ff67SMartin K. Petersen /* Already remapped? */ 438*af55ff67SMartin K. Petersen if (rq->cmd_flags & REQ_INTEGRITY) 439*af55ff67SMartin K. Petersen return 0; 440*af55ff67SMartin K. Petersen 441*af55ff67SMartin K. Petersen sdkp = rq->bio->bi_bdev->bd_disk->private_data; 442*af55ff67SMartin K. Petersen 443*af55ff67SMartin K. Petersen if (sdkp->protection_type == SD_DIF_TYPE3_PROTECTION) 444*af55ff67SMartin K. Petersen return 0; 445*af55ff67SMartin K. Petersen 446*af55ff67SMartin K. Petersen rq->cmd_flags |= REQ_INTEGRITY; 447*af55ff67SMartin K. Petersen phys = hw_sector & 0xffffffff; 448*af55ff67SMartin K. Petersen 449*af55ff67SMartin K. Petersen __rq_for_each_bio(bio, rq) { 450*af55ff67SMartin K. Petersen struct bio_vec *iv; 451*af55ff67SMartin K. Petersen 452*af55ff67SMartin K. Petersen virt = bio->bi_integrity->bip_sector & 0xffffffff; 453*af55ff67SMartin K. Petersen 454*af55ff67SMartin K. Petersen bip_for_each_vec(iv, bio->bi_integrity, i) { 455*af55ff67SMartin K. Petersen sdt = kmap_atomic(iv->bv_page, KM_USER0) 456*af55ff67SMartin K. Petersen + iv->bv_offset; 457*af55ff67SMartin K. Petersen 458*af55ff67SMartin K. Petersen for (j = 0 ; j < iv->bv_len ; j += tuple_sz, sdt++) { 459*af55ff67SMartin K. Petersen 460*af55ff67SMartin K. Petersen if (be32_to_cpu(sdt->ref_tag) != virt) 461*af55ff67SMartin K. Petersen goto error; 462*af55ff67SMartin K. Petersen 463*af55ff67SMartin K. Petersen sdt->ref_tag = cpu_to_be32(phys); 464*af55ff67SMartin K. Petersen virt++; 465*af55ff67SMartin K. Petersen phys++; 466*af55ff67SMartin K. Petersen } 467*af55ff67SMartin K. Petersen 468*af55ff67SMartin K. Petersen kunmap_atomic(sdt, KM_USER0); 469*af55ff67SMartin K. Petersen } 470*af55ff67SMartin K. Petersen } 471*af55ff67SMartin K. Petersen 472*af55ff67SMartin K. Petersen return 0; 473*af55ff67SMartin K. Petersen 474*af55ff67SMartin K. Petersen error: 475*af55ff67SMartin K. Petersen kunmap_atomic(sdt, KM_USER0); 476*af55ff67SMartin K. Petersen sd_printk(KERN_ERR, sdkp, "%s: virt %u, phys %u, ref %u\n", 477*af55ff67SMartin K. Petersen __func__, virt, phys, be32_to_cpu(sdt->ref_tag)); 478*af55ff67SMartin K. Petersen 479*af55ff67SMartin K. Petersen return -EIO; 480*af55ff67SMartin K. Petersen } 481*af55ff67SMartin K. Petersen 482*af55ff67SMartin K. Petersen /* 483*af55ff67SMartin K. Petersen * Remap physical sector values in the reference tag to the virtual 484*af55ff67SMartin K. Petersen * values expected by the block layer. 485*af55ff67SMartin K. Petersen */ 486*af55ff67SMartin K. Petersen void sd_dif_complete(struct scsi_cmnd *scmd, unsigned int good_bytes) 487*af55ff67SMartin K. Petersen { 488*af55ff67SMartin K. Petersen const int tuple_sz = sizeof(struct sd_dif_tuple); 489*af55ff67SMartin K. Petersen struct scsi_disk *sdkp; 490*af55ff67SMartin K. Petersen struct bio *bio; 491*af55ff67SMartin K. Petersen struct sd_dif_tuple *sdt; 492*af55ff67SMartin K. Petersen unsigned int i, j, sectors, sector_sz; 493*af55ff67SMartin K. Petersen u32 phys, virt; 494*af55ff67SMartin K. Petersen 495*af55ff67SMartin K. Petersen sdkp = scsi_disk(scmd->request->rq_disk); 496*af55ff67SMartin K. Petersen 497*af55ff67SMartin K. Petersen if (sdkp->protection_type == SD_DIF_TYPE3_PROTECTION || good_bytes == 0) 498*af55ff67SMartin K. Petersen return; 499*af55ff67SMartin K. Petersen 500*af55ff67SMartin K. Petersen sector_sz = scmd->device->sector_size; 501*af55ff67SMartin K. Petersen sectors = good_bytes / sector_sz; 502*af55ff67SMartin K. Petersen 503*af55ff67SMartin K. Petersen phys = scmd->request->sector & 0xffffffff; 504*af55ff67SMartin K. Petersen if (sector_sz == 4096) 505*af55ff67SMartin K. Petersen phys >>= 3; 506*af55ff67SMartin K. Petersen 507*af55ff67SMartin K. Petersen __rq_for_each_bio(bio, scmd->request) { 508*af55ff67SMartin K. Petersen struct bio_vec *iv; 509*af55ff67SMartin K. Petersen 510*af55ff67SMartin K. Petersen virt = bio->bi_integrity->bip_sector & 0xffffffff; 511*af55ff67SMartin K. Petersen 512*af55ff67SMartin K. Petersen bip_for_each_vec(iv, bio->bi_integrity, i) { 513*af55ff67SMartin K. Petersen sdt = kmap_atomic(iv->bv_page, KM_USER0) 514*af55ff67SMartin K. Petersen + iv->bv_offset; 515*af55ff67SMartin K. Petersen 516*af55ff67SMartin K. Petersen for (j = 0 ; j < iv->bv_len ; j += tuple_sz, sdt++) { 517*af55ff67SMartin K. Petersen 518*af55ff67SMartin K. Petersen if (sectors == 0) { 519*af55ff67SMartin K. Petersen kunmap_atomic(sdt, KM_USER0); 520*af55ff67SMartin K. Petersen return; 521*af55ff67SMartin K. Petersen } 522*af55ff67SMartin K. Petersen 523*af55ff67SMartin K. Petersen if (be32_to_cpu(sdt->ref_tag) != phys && 524*af55ff67SMartin K. Petersen sdt->app_tag != 0xffff) 525*af55ff67SMartin K. Petersen sdt->ref_tag = 0xffffffff; /* Bad ref */ 526*af55ff67SMartin K. Petersen else 527*af55ff67SMartin K. Petersen sdt->ref_tag = cpu_to_be32(virt); 528*af55ff67SMartin K. Petersen 529*af55ff67SMartin K. Petersen virt++; 530*af55ff67SMartin K. Petersen phys++; 531*af55ff67SMartin K. Petersen sectors--; 532*af55ff67SMartin K. Petersen } 533*af55ff67SMartin K. Petersen 534*af55ff67SMartin K. Petersen kunmap_atomic(sdt, KM_USER0); 535*af55ff67SMartin K. Petersen } 536*af55ff67SMartin K. Petersen } 537*af55ff67SMartin K. Petersen } 538*af55ff67SMartin K. Petersen 539