diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-07-13 17:41:21 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-07-13 17:41:21 -0700 |
commit | 03ce3ca4b02bfc1e6567a7851ae231ad3cc9418e (patch) | |
tree | bf953469c6cac6b0a5b7d3671a27473eace144e3 /drivers/scsi/scsi_debug.c | |
parent | f8acc450e10dbe7996220bac5459ee9c14a82a6a (diff) | |
parent | 622f9a8e7b8043a5ea2c7d047d65ecad01fe0f97 (diff) |
Merge tag 'scsi-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi
Pull final round of SCSI updates from James Bottomley:
"This is the remaining set of SCSI patches for the merge window. It's
mostly driver updates (scsi_debug, qla2xxx, storvsc, mp3sas). There
are also several bug fixes in fcoe, libfc, and megaraid_sas. We also
have a couple of core changes to try to make device destruction more
deterministic"
* tag 'scsi-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi: (46 commits)
[SCSI] scsi constants: command, sense key + additional sense strings
fcoe: Reduce number of sparse warnings
fcoe: Stop fc_rport_priv structure leak
libfcoe: Fix meaningless log statement
libfc: Differentiate echange timer cancellation debug statements
libfc: Remove extra space in fc_exch_timer_cancel definition
fcoe: fix the link error status block sparse warnings
fcoe: Fix smatch warning in fcoe_fdmi_info function
libfc: Reject PLOGI from nodes with incompatible role
[SCSI] enable destruction of blocked devices which fail LUN scanning
[SCSI] Fix race between starved list and device removal
[SCSI] megaraid_sas: fix a bug for 64 bit arches
[SCSI] scsi_debug: reduce duplication between prot_verify_read and prot_verify_write
[SCSI] scsi_debug: simplify offset calculation for dif_storep
[SCSI] scsi_debug: invalidate protection info for unmapped region
[SCSI] scsi_debug: fix NULL pointer dereference with parameters dif=0 dix=1
[SCSI] scsi_debug: fix incorrectly nested kmap_atomic()
[SCSI] scsi_debug: fix invalid address passed to kunmap_atomic()
[SCSI] mpt3sas: Bump driver version to v02.100.00.00
[SCSI] mpt3sas: when async scanning is enabled then while scanning, devices are removed but their transport layer entries are not removed
...
Diffstat (limited to 'drivers/scsi/scsi_debug.c')
-rw-r--r-- | drivers/scsi/scsi_debug.c | 174 |
1 files changed, 70 insertions, 104 deletions
diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index d055450c2a4a..cb4fefa1bfba 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -258,7 +258,7 @@ struct sdebug_queued_cmd { static struct sdebug_queued_cmd queued_arr[SCSI_DEBUG_CANQUEUE]; static unsigned char * fake_storep; /* ramdisk storage */ -static unsigned char *dif_storep; /* protection info */ +static struct sd_dif_tuple *dif_storep; /* protection info */ static void *map_storep; /* provisioning map */ static unsigned long map_size; @@ -277,11 +277,6 @@ static char sdebug_proc_name[] = "scsi_debug"; static struct bus_type pseudo_lld_bus; -static inline sector_t dif_offset(sector_t sector) -{ - return sector << 3; -} - static struct device_driver sdebug_driverfs_driver = { .name = sdebug_proc_name, .bus = &pseudo_lld_bus, @@ -1736,6 +1731,50 @@ static int do_device_access(struct scsi_cmnd *scmd, return ret; } +static u16 dif_compute_csum(const void *buf, int len) +{ + u16 csum; + + switch (scsi_debug_guard) { + case 1: + csum = ip_compute_csum(buf, len); + break; + case 0: + csum = cpu_to_be16(crc_t10dif(buf, len)); + break; + } + return csum; +} + +static int dif_verify(struct sd_dif_tuple *sdt, const void *data, + sector_t sector, u32 ei_lba) +{ + u16 csum = dif_compute_csum(data, scsi_debug_sector_size); + + if (sdt->guard_tag != csum) { + pr_err("%s: GUARD check failed on sector %lu rcvd 0x%04x, data 0x%04x\n", + __func__, + (unsigned long)sector, + be16_to_cpu(sdt->guard_tag), + be16_to_cpu(csum)); + return 0x01; + } + if (scsi_debug_dif == SD_DIF_TYPE1_PROTECTION && + be32_to_cpu(sdt->ref_tag) != (sector & 0xffffffff)) { + pr_err("%s: REF check failed on sector %lu\n", + __func__, (unsigned long)sector); + return 0x03; + } + if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION && + be32_to_cpu(sdt->ref_tag) != ei_lba) { + pr_err("%s: REF check failed on sector %lu\n", + __func__, (unsigned long)sector); + dif_errors++; + return 0x03; + } + return 0; +} + static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec, unsigned int sectors, u32 ei_lba) { @@ -1748,71 +1787,38 @@ static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec, start_sec = do_div(tmp_sec, sdebug_store_sectors); - sdt = (struct sd_dif_tuple *)(dif_storep + dif_offset(start_sec)); + sdt = dif_storep + start_sec; for (i = 0 ; i < sectors ; i++) { - u16 csum; + int ret; if (sdt[i].app_tag == 0xffff) continue; sector = start_sec + i; - switch (scsi_debug_guard) { - case 1: - csum = ip_compute_csum(fake_storep + - sector * scsi_debug_sector_size, - scsi_debug_sector_size); - break; - case 0: - csum = crc_t10dif(fake_storep + - sector * scsi_debug_sector_size, - scsi_debug_sector_size); - csum = cpu_to_be16(csum); - break; - default: - BUG(); - } - - if (sdt[i].guard_tag != csum) { - printk(KERN_ERR "%s: GUARD check failed on sector %lu" \ - " rcvd 0x%04x, data 0x%04x\n", __func__, - (unsigned long)sector, - be16_to_cpu(sdt[i].guard_tag), - be16_to_cpu(csum)); - dif_errors++; - return 0x01; - } - - if (scsi_debug_dif == SD_DIF_TYPE1_PROTECTION && - be32_to_cpu(sdt[i].ref_tag) != (sector & 0xffffffff)) { - printk(KERN_ERR "%s: REF check failed on sector %lu\n", - __func__, (unsigned long)sector); + ret = dif_verify(&sdt[i], + fake_storep + sector * scsi_debug_sector_size, + sector, ei_lba); + if (ret) { dif_errors++; - return 0x03; - } - - if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION && - be32_to_cpu(sdt[i].ref_tag) != ei_lba) { - printk(KERN_ERR "%s: REF check failed on sector %lu\n", - __func__, (unsigned long)sector); - dif_errors++; - return 0x03; + return ret; } ei_lba++; } - resid = sectors * 8; /* Bytes of protection data to copy into sgl */ + /* Bytes of protection data to copy into sgl */ + resid = sectors * sizeof(*dif_storep); sector = start_sec; scsi_for_each_prot_sg(SCpnt, psgl, scsi_prot_sg_count(SCpnt), i) { int len = min(psgl->length, resid); paddr = kmap_atomic(sg_page(psgl)) + psgl->offset; - memcpy(paddr, dif_storep + dif_offset(sector), len); + memcpy(paddr, dif_storep + sector, len); - sector += len >> 3; + sector += len / sizeof(*dif_storep); if (sector >= sdebug_store_sectors) { /* Force wrap */ tmp_sec = sector; @@ -1910,22 +1916,21 @@ static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec, sector_t tmp_sec = start_sec; sector_t sector; int ppage_offset; - unsigned short csum; sector = do_div(tmp_sec, sdebug_store_sectors); BUG_ON(scsi_sg_count(SCpnt) == 0); BUG_ON(scsi_prot_sg_count(SCpnt) == 0); - paddr = kmap_atomic(sg_page(psgl)) + psgl->offset; ppage_offset = 0; /* For each data page */ scsi_for_each_sg(SCpnt, dsgl, scsi_sg_count(SCpnt), i) { daddr = kmap_atomic(sg_page(dsgl)) + dsgl->offset; + paddr = kmap_atomic(sg_page(psgl)) + psgl->offset; /* For each sector-sized chunk in data page */ - for (j = 0 ; j < dsgl->length ; j += scsi_debug_sector_size) { + for (j = 0; j < dsgl->length; j += scsi_debug_sector_size) { /* If we're at the end of the current * protection page advance to the next one @@ -1941,51 +1946,9 @@ static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec, sdt = paddr + ppage_offset; - switch (scsi_debug_guard) { - case 1: - csum = ip_compute_csum(daddr, - scsi_debug_sector_size); - break; - case 0: - csum = cpu_to_be16(crc_t10dif(daddr, - scsi_debug_sector_size)); - break; - default: - BUG(); - ret = 0; - goto out; - } - - if (sdt->guard_tag != csum) { - printk(KERN_ERR - "%s: GUARD check failed on sector %lu " \ - "rcvd 0x%04x, calculated 0x%04x\n", - __func__, (unsigned long)sector, - be16_to_cpu(sdt->guard_tag), - be16_to_cpu(csum)); - ret = 0x01; - dump_sector(daddr, scsi_debug_sector_size); - goto out; - } - - if (scsi_debug_dif == SD_DIF_TYPE1_PROTECTION && - be32_to_cpu(sdt->ref_tag) - != (start_sec & 0xffffffff)) { - printk(KERN_ERR - "%s: REF check failed on sector %lu\n", - __func__, (unsigned long)sector); - ret = 0x03; - dump_sector(daddr, scsi_debug_sector_size); - goto out; - } - - if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION && - be32_to_cpu(sdt->ref_tag) != ei_lba) { - printk(KERN_ERR - "%s: REF check failed on sector %lu\n", - __func__, (unsigned long)sector); - ret = 0x03; - dump_sector(daddr, scsi_debug_sector_size); + ret = dif_verify(sdt, daddr + j, start_sec, ei_lba); + if (ret) { + dump_sector(daddr + j, scsi_debug_sector_size); goto out; } @@ -1994,7 +1957,7 @@ static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec, * correctness we need to verify each sector * before writing it to "stable" storage */ - memcpy(dif_storep + dif_offset(sector), sdt, 8); + memcpy(dif_storep + sector, sdt, sizeof(*sdt)); sector++; @@ -2003,23 +1966,21 @@ static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec, start_sec++; ei_lba++; - daddr += scsi_debug_sector_size; ppage_offset += sizeof(struct sd_dif_tuple); } + kunmap_atomic(paddr); kunmap_atomic(daddr); } - kunmap_atomic(paddr); - dix_writes++; return 0; out: dif_errors++; - kunmap_atomic(daddr); kunmap_atomic(paddr); + kunmap_atomic(daddr); return ret; } @@ -2092,6 +2053,11 @@ static void unmap_region(sector_t lba, unsigned int len) scsi_debug_sector_size * scsi_debug_unmap_granularity); } + if (dif_storep) { + memset(dif_storep + lba, 0xff, + sizeof(*dif_storep) * + scsi_debug_unmap_granularity); + } } lba = map_index_to_lba(index + 1); } @@ -3400,7 +3366,7 @@ static int __init scsi_debug_init(void) if (scsi_debug_num_parts > 0) sdebug_build_parts(fake_storep, sz); - if (scsi_debug_dif) { + if (scsi_debug_dix) { int dif_size; dif_size = sdebug_store_sectors * sizeof(struct sd_dif_tuple); |