sd_dif.c 10.2 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
/*
 * sd_dif.c - SCSI Data Integrity Field
 *
 * Copyright (C) 2007, 2008 Oracle Corporation
 * Written by: Martin K. Petersen <martin.petersen@oracle.com>
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License version
 * 2 as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; see the file COPYING.  If not, write to
 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139,
 * USA.
 *
 */

#include <linux/blkdev.h>
#include <linux/crc-t10dif.h>

#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_dbg.h>
#include <scsi/scsi_device.h>
#include <scsi/scsi_driver.h>
#include <scsi/scsi_eh.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_ioctl.h>
#include <scsi/scsicam.h>

#include <net/checksum.h>

#include "sd.h"

typedef __u16 (csum_fn) (void *, unsigned int);

static __u16 sd_dif_crc_fn(void *data, unsigned int len)
{
	return cpu_to_be16(crc_t10dif(data, len));
}

static __u16 sd_dif_ip_fn(void *data, unsigned int len)
{
	return ip_compute_csum(data, len);
}

/*
 * Type 1 and Type 2 protection use the same format: 16 bit guard tag,
 * 16 bit app tag, 32 bit reference tag.
 */
56
static void sd_dif_type1_generate(struct blk_integrity_iter *iter, csum_fn *fn)
57
{
58 59 60
	void *buf = iter->data_buf;
	struct sd_dif_tuple *sdt = iter->prot_buf;
	sector_t seed = iter->seed;
61 62
	unsigned int i;

63 64
	for (i = 0 ; i < iter->data_size ; i += iter->interval, sdt++) {
		sdt->guard_tag = fn(buf, iter->interval);
65
		sdt->ref_tag = cpu_to_be32(seed & 0xffffffff);
66 67
		sdt->app_tag = 0;

68
		buf += iter->interval;
69
		seed++;
70 71 72
	}
}

73
static int sd_dif_type1_generate_crc(struct blk_integrity_iter *iter)
74
{
75 76
	sd_dif_type1_generate(iter, sd_dif_crc_fn);
	return 0;
77 78
}

79
static int sd_dif_type1_generate_ip(struct blk_integrity_iter *iter)
80
{
81 82
	sd_dif_type1_generate(iter, sd_dif_ip_fn);
	return 0;
83 84
}

85
static int sd_dif_type1_verify(struct blk_integrity_iter *iter, csum_fn *fn)
86
{
87 88 89
	void *buf = iter->data_buf;
	struct sd_dif_tuple *sdt = iter->prot_buf;
	sector_t seed = iter->seed;
90 91 92
	unsigned int i;
	__u16 csum;

93
	for (i = 0 ; i < iter->data_size ; i += iter->interval, sdt++) {
94 95 96 97
		/* Unwritten sectors */
		if (sdt->app_tag == 0xffff)
			return 0;

98
		if (be32_to_cpu(sdt->ref_tag) != (seed & 0xffffffff)) {
99 100
			printk(KERN_ERR
			       "%s: ref tag error on sector %lu (rcvd %u)\n",
101
			       iter->disk_name, (unsigned long)seed,
102 103 104 105
			       be32_to_cpu(sdt->ref_tag));
			return -EIO;
		}

106
		csum = fn(buf, iter->interval);
107 108 109

		if (sdt->guard_tag != csum) {
			printk(KERN_ERR "%s: guard tag error on sector %lu " \
110
			       "(rcvd %04x, data %04x)\n", iter->disk_name,
111
			       (unsigned long)seed,
112 113 114 115
			       be16_to_cpu(sdt->guard_tag), be16_to_cpu(csum));
			return -EIO;
		}

116
		buf += iter->interval;
117
		seed++;
118 119 120 121 122
	}

	return 0;
}

123
static int sd_dif_type1_verify_crc(struct blk_integrity_iter *iter)
124
{
125
	return sd_dif_type1_verify(iter, sd_dif_crc_fn);
126 127
}

128
static int sd_dif_type1_verify_ip(struct blk_integrity_iter *iter)
129
{
130
	return sd_dif_type1_verify(iter, sd_dif_ip_fn);
131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
}

static struct blk_integrity dif_type1_integrity_crc = {
	.name			= "T10-DIF-TYPE1-CRC",
	.generate_fn		= sd_dif_type1_generate_crc,
	.verify_fn		= sd_dif_type1_verify_crc,
	.tuple_size		= sizeof(struct sd_dif_tuple),
	.tag_size		= 0,
};

static struct blk_integrity dif_type1_integrity_ip = {
	.name			= "T10-DIF-TYPE1-IP",
	.generate_fn		= sd_dif_type1_generate_ip,
	.verify_fn		= sd_dif_type1_verify_ip,
	.tuple_size		= sizeof(struct sd_dif_tuple),
	.tag_size		= 0,
};


/*
 * Type 3 protection has a 16-bit guard tag and 16 + 32 bits of opaque
 * tag space.
 */
154
static void sd_dif_type3_generate(struct blk_integrity_iter *iter, csum_fn *fn)
155
{
156 157
	void *buf = iter->data_buf;
	struct sd_dif_tuple *sdt = iter->prot_buf;
158 159
	unsigned int i;

160 161
	for (i = 0 ; i < iter->data_size ; i += iter->interval, sdt++) {
		sdt->guard_tag = fn(buf, iter->interval);
162 163 164
		sdt->ref_tag = 0;
		sdt->app_tag = 0;

165
		buf += iter->interval;
166 167 168
	}
}

169
static int sd_dif_type3_generate_crc(struct blk_integrity_iter *iter)
170
{
171 172
	sd_dif_type3_generate(iter, sd_dif_crc_fn);
	return 0;
173 174
}

175
static int sd_dif_type3_generate_ip(struct blk_integrity_iter *iter)
176
{
177 178
	sd_dif_type3_generate(iter, sd_dif_ip_fn);
	return 0;
179 180
}

181
static int sd_dif_type3_verify(struct blk_integrity_iter *iter, csum_fn *fn)
182
{
183 184 185
	void *buf = iter->data_buf;
	struct sd_dif_tuple *sdt = iter->prot_buf;
	sector_t seed = iter->seed;
186 187 188
	unsigned int i;
	__u16 csum;

189
	for (i = 0 ; i < iter->data_size ; i += iter->interval, sdt++) {
190 191 192 193
		/* Unwritten sectors */
		if (sdt->app_tag == 0xffff && sdt->ref_tag == 0xffffffff)
			return 0;

194
		csum = fn(buf, iter->interval);
195 196 197

		if (sdt->guard_tag != csum) {
			printk(KERN_ERR "%s: guard tag error on sector %lu " \
198
			       "(rcvd %04x, data %04x)\n", iter->disk_name,
199
			       (unsigned long)seed,
200 201 202 203
			       be16_to_cpu(sdt->guard_tag), be16_to_cpu(csum));
			return -EIO;
		}

204
		buf += iter->interval;
205
		seed++;
206 207 208 209 210
	}

	return 0;
}

211
static int sd_dif_type3_verify_crc(struct blk_integrity_iter *iter)
212
{
213
	return sd_dif_type3_verify(iter, sd_dif_crc_fn);
214 215
}

216
static int sd_dif_type3_verify_ip(struct blk_integrity_iter *iter)
217
{
218
	return sd_dif_type3_verify(iter, sd_dif_ip_fn);
219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244
}

static struct blk_integrity dif_type3_integrity_crc = {
	.name			= "T10-DIF-TYPE3-CRC",
	.generate_fn		= sd_dif_type3_generate_crc,
	.verify_fn		= sd_dif_type3_verify_crc,
	.tuple_size		= sizeof(struct sd_dif_tuple),
	.tag_size		= 0,
};

static struct blk_integrity dif_type3_integrity_ip = {
	.name			= "T10-DIF-TYPE3-IP",
	.generate_fn		= sd_dif_type3_generate_ip,
	.verify_fn		= sd_dif_type3_verify_ip,
	.tuple_size		= sizeof(struct sd_dif_tuple),
	.tag_size		= 0,
};

/*
 * Configure exchange of protection information between OS and HBA.
 */
void sd_dif_config_host(struct scsi_disk *sdkp)
{
	struct scsi_device *sdp = sdkp->device;
	struct gendisk *disk = sdkp->disk;
	u8 type = sdkp->protection_type;
245
	int dif, dix;
246

247 248
	dif = scsi_host_dif_capable(sdp->host, type);
	dix = scsi_host_dix_capable(sdp->host, type);
249

250 251 252
	if (!dix && scsi_host_dix_capable(sdp->host, 0)) {
		dif = 0; dix = 1;
	}
253

254
	if (!dix)
255 256 257
		return;

	/* Enable DMA of protection information */
258
	if (scsi_host_get_guard(sdkp->device->host) & SHOST_DIX_GUARD_IP) {
259 260 261 262
		if (type == SD_DIF_TYPE3_PROTECTION)
			blk_integrity_register(disk, &dif_type3_integrity_ip);
		else
			blk_integrity_register(disk, &dif_type1_integrity_ip);
263 264 265

		disk->integrity->flags |= BLK_INTEGRITY_IP_CHECKSUM;
	} else
266 267 268 269 270
		if (type == SD_DIF_TYPE3_PROTECTION)
			blk_integrity_register(disk, &dif_type3_integrity_crc);
		else
			blk_integrity_register(disk, &dif_type1_integrity_crc);

271
	sd_printk(KERN_NOTICE, sdkp,
272
		  "Enabling DIX %s protection\n", disk->integrity->name);
273 274

	/* Signal to block layer that we support sector tagging */
275 276 277 278 279 280 281
	if (dif && type) {

		disk->integrity->flags |= BLK_INTEGRITY_DEVICE_CAPABLE;

		if (!sdkp)
			return;

282 283 284 285 286
		if (type == SD_DIF_TYPE3_PROTECTION)
			disk->integrity->tag_size = sizeof(u16) + sizeof(u32);
		else
			disk->integrity->tag_size = sizeof(u16);

287
		sd_printk(KERN_NOTICE, sdkp, "DIF application tag size %u\n",
288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307
			  disk->integrity->tag_size);
	}
}

/*
 * The virtual start sector is the one that was originally submitted
 * by the block layer.	Due to partitioning, MD/DM cloning, etc. the
 * actual physical start sector is likely to be different.  Remap
 * protection information to match the physical LBA.
 *
 * From a protocol perspective there's a slight difference between
 * Type 1 and 2.  The latter uses 32-byte CDBs exclusively, and the
 * reference tag is seeded in the CDB.  This gives us the potential to
 * avoid virt->phys remapping during write.  However, at read time we
 * don't know whether the virt sector is the same as when we wrote it
 * (we could be reading from real disk as opposed to MD/DM device.  So
 * we always remap Type 2 making it identical to Type 1.
 *
 * Type 3 does not have a reference tag so no remapping is required.
 */
308 309
void sd_dif_prepare(struct request *rq, sector_t hw_sector,
		    unsigned int sector_sz)
310 311 312 313 314 315 316 317 318 319
{
	const int tuple_sz = sizeof(struct sd_dif_tuple);
	struct bio *bio;
	struct scsi_disk *sdkp;
	struct sd_dif_tuple *sdt;
	u32 phys, virt;

	sdkp = rq->bio->bi_bdev->bd_disk->private_data;

	if (sdkp->protection_type == SD_DIF_TYPE3_PROTECTION)
320
		return;
321 322 323 324

	phys = hw_sector & 0xffffffff;

	__rq_for_each_bio(bio, rq) {
325
		struct bio_integrity_payload *bip = bio_integrity(bio);
326 327 328
		struct bio_vec iv;
		struct bvec_iter iter;
		unsigned int j;
329

330
		/* Already remapped? */
331
		if (bip->bip_flags & BIP_MAPPED_INTEGRITY)
332 333
			break;

334
		virt = bip_get_seed(bip) & 0xffffffff;
335

336
		bip_for_each_vec(iv, bip, iter) {
337 338
			sdt = kmap_atomic(iv.bv_page)
				+ iv.bv_offset;
339

340
			for (j = 0; j < iv.bv_len; j += tuple_sz, sdt++) {
341

342 343
				if (be32_to_cpu(sdt->ref_tag) == virt)
					sdt->ref_tag = cpu_to_be32(phys);
344 345 346 347 348

				virt++;
				phys++;
			}

349
			kunmap_atomic(sdt);
350
		}
351

352
		bip->bip_flags |= BIP_MAPPED_INTEGRITY;
353 354 355 356 357 358 359 360 361 362 363 364 365
	}
}

/*
 * Remap physical sector values in the reference tag to the virtual
 * values expected by the block layer.
 */
void sd_dif_complete(struct scsi_cmnd *scmd, unsigned int good_bytes)
{
	const int tuple_sz = sizeof(struct sd_dif_tuple);
	struct scsi_disk *sdkp;
	struct bio *bio;
	struct sd_dif_tuple *sdt;
366
	unsigned int j, sectors, sector_sz;
367 368 369 370 371 372 373 374 375 376
	u32 phys, virt;

	sdkp = scsi_disk(scmd->request->rq_disk);

	if (sdkp->protection_type == SD_DIF_TYPE3_PROTECTION || good_bytes == 0)
		return;

	sector_sz = scmd->device->sector_size;
	sectors = good_bytes / sector_sz;

377
	phys = blk_rq_pos(scmd->request) & 0xffffffff;
378 379 380 381
	if (sector_sz == 4096)
		phys >>= 3;

	__rq_for_each_bio(bio, scmd->request) {
382
		struct bio_integrity_payload *bip = bio_integrity(bio);
383 384
		struct bio_vec iv;
		struct bvec_iter iter;
385

386
		virt = bip_get_seed(bip) & 0xffffffff;
387

388
		bip_for_each_vec(iv, bip, iter) {
389 390
			sdt = kmap_atomic(iv.bv_page)
				+ iv.bv_offset;
391

392
			for (j = 0; j < iv.bv_len; j += tuple_sz, sdt++) {
393 394

				if (sectors == 0) {
395
					kunmap_atomic(sdt);
396 397 398
					return;
				}

399
				if (be32_to_cpu(sdt->ref_tag) == phys)
400 401 402 403 404 405 406
					sdt->ref_tag = cpu_to_be32(virt);

				virt++;
				phys++;
				sectors--;
			}

407
			kunmap_atomic(sdt);
408 409 410 411
		}
	}
}