diff options
Diffstat (limited to 'drivers/scsi/scsi_debug.c')
| -rw-r--r-- | drivers/scsi/scsi_debug.c | 1084 | 
1 files changed, 566 insertions, 518 deletions
diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index 2c36bae3bd4..1328a262107 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -64,6 +64,7 @@ static const char * scsi_debug_version_date = "20100324";  /* Additional Sense Code (ASC) */  #define NO_ADDITIONAL_SENSE 0x0  #define LOGICAL_UNIT_NOT_READY 0x4 +#define LOGICAL_UNIT_COMMUNICATION_FAILURE 0x8  #define UNRECOVERED_READ_ERR 0x11  #define PARAMETER_LIST_LENGTH_ERR 0x1a  #define INVALID_OPCODE 0x20 @@ -89,32 +90,36 @@ static const char * scsi_debug_version_date = "20100324";  /* With these defaults, this driver will make 1 host with 1 target   * (id 0) containing 1 logical unit (lun 0). That is 1 device.   */ +#define DEF_ATO 1  #define DEF_DELAY   1  #define DEF_DEV_SIZE_MB   8 -#define DEF_EVERY_NTH   0 -#define DEF_NUM_PARTS   0 -#define DEF_OPTS   0 -#define DEF_SCSI_LEVEL   5    /* INQUIRY, byte2 [5->SPC-3] */ -#define DEF_PTYPE   0 +#define DEF_DIF 0 +#define DEF_DIX 0  #define DEF_D_SENSE   0 -#define DEF_NO_LUN_0   0 -#define DEF_VIRTUAL_GB   0 +#define DEF_EVERY_NTH   0  #define DEF_FAKE_RW	0 -#define DEF_VPD_USE_HOSTNO 1 -#define DEF_SECTOR_SIZE 512 -#define DEF_DIX 0 -#define DEF_DIF 0  #define DEF_GUARD 0 -#define DEF_ATO 1 -#define DEF_PHYSBLK_EXP 0 +#define DEF_LBPU 0 +#define DEF_LBPWS 0 +#define DEF_LBPWS10 0 +#define DEF_LBPRZ 1  #define DEF_LOWEST_ALIGNED 0 +#define DEF_NO_LUN_0   0 +#define DEF_NUM_PARTS   0 +#define DEF_OPTS   0  #define DEF_OPT_BLKS 64 +#define DEF_PHYSBLK_EXP 0 +#define DEF_PTYPE   0 +#define DEF_REMOVABLE false +#define DEF_SCSI_LEVEL   5    /* INQUIRY, byte2 [5->SPC-3] */ +#define DEF_SECTOR_SIZE 512 +#define DEF_UNMAP_ALIGNMENT 0 +#define DEF_UNMAP_GRANULARITY 1  #define DEF_UNMAP_MAX_BLOCKS 0xFFFFFFFF  #define DEF_UNMAP_MAX_DESC 256 -#define DEF_UNMAP_GRANULARITY 1 -#define DEF_UNMAP_ALIGNMENT 0 -#define DEF_TPWS 0 -#define DEF_TPU 0 +#define DEF_VIRTUAL_GB   0 +#define DEF_VPD_USE_HOSTNO 1 +#define DEF_WRITESAME_LENGTH 0xFFFF  /* bit mask values for scsi_debug_opts */  #define SCSI_DEBUG_OPT_NOISE   1 @@ -124,6 +129,8 @@ static const char * scsi_debug_version_date = "20100324";  #define SCSI_DEBUG_OPT_TRANSPORT_ERR   16  #define SCSI_DEBUG_OPT_DIF_ERR   32  #define SCSI_DEBUG_OPT_DIX_ERR   64 +#define SCSI_DEBUG_OPT_MAC_TIMEOUT  128 +#define SCSI_DEBUG_OPT_SHORT_TRANSFER	256  /* When "every_nth" > 0 then modulo "every_nth" commands:   *   - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set   *   - a RECOVERED_ERROR is simulated on successful read and write @@ -144,6 +151,7 @@ static const char * scsi_debug_version_date = "20100324";  /* when 1==SCSI_DEBUG_OPT_MEDIUM_ERR, a medium error is simulated at this   * sector on read commands: */  #define OPT_MEDIUM_ERR_ADDR   0x1234 /* that's sector 4660 in decimal */ +#define OPT_MEDIUM_ERR_NUM    10     /* number of consecutive medium errs */  /* If REPORT LUNS has luns >= 256 it can choose "flat space" (value 1)   * or "peripheral device" addressing (value 0) */ @@ -155,41 +163,45 @@ static const char * scsi_debug_version_date = "20100324";  #define SCSI_DEBUG_CANQUEUE  255  static int scsi_debug_add_host = DEF_NUM_HOST; +static int scsi_debug_ato = DEF_ATO;  static int scsi_debug_delay = DEF_DELAY;  static int scsi_debug_dev_size_mb = DEF_DEV_SIZE_MB; +static int scsi_debug_dif = DEF_DIF; +static int scsi_debug_dix = DEF_DIX; +static int scsi_debug_dsense = DEF_D_SENSE;  static int scsi_debug_every_nth = DEF_EVERY_NTH; +static int scsi_debug_fake_rw = DEF_FAKE_RW; +static unsigned int scsi_debug_guard = DEF_GUARD; +static int scsi_debug_lowest_aligned = DEF_LOWEST_ALIGNED;  static int scsi_debug_max_luns = DEF_MAX_LUNS;  static int scsi_debug_max_queue = SCSI_DEBUG_CANQUEUE; -static int scsi_debug_num_parts = DEF_NUM_PARTS; +static int scsi_debug_no_lun_0 = DEF_NO_LUN_0;  static int scsi_debug_no_uld = 0; +static int scsi_debug_num_parts = DEF_NUM_PARTS;  static int scsi_debug_num_tgts = DEF_NUM_TGTS; /* targets per host */ +static int scsi_debug_opt_blks = DEF_OPT_BLKS;  static int scsi_debug_opts = DEF_OPTS; -static int scsi_debug_scsi_level = DEF_SCSI_LEVEL; +static int scsi_debug_physblk_exp = DEF_PHYSBLK_EXP;  static int scsi_debug_ptype = DEF_PTYPE; /* SCSI peripheral type (0==disk) */ -static int scsi_debug_dsense = DEF_D_SENSE; -static int scsi_debug_no_lun_0 = DEF_NO_LUN_0; +static int scsi_debug_scsi_level = DEF_SCSI_LEVEL; +static int scsi_debug_sector_size = DEF_SECTOR_SIZE;  static int scsi_debug_virtual_gb = DEF_VIRTUAL_GB; -static int scsi_debug_fake_rw = DEF_FAKE_RW;  static int scsi_debug_vpd_use_hostno = DEF_VPD_USE_HOSTNO; -static int scsi_debug_sector_size = DEF_SECTOR_SIZE; -static int scsi_debug_dix = DEF_DIX; -static int scsi_debug_dif = DEF_DIF; -static int scsi_debug_guard = DEF_GUARD; -static int scsi_debug_ato = DEF_ATO; -static int scsi_debug_physblk_exp = DEF_PHYSBLK_EXP; -static int scsi_debug_lowest_aligned = DEF_LOWEST_ALIGNED; -static int scsi_debug_opt_blks = DEF_OPT_BLKS; -static unsigned int scsi_debug_unmap_max_desc = DEF_UNMAP_MAX_DESC; -static unsigned int scsi_debug_unmap_max_blocks = DEF_UNMAP_MAX_BLOCKS; -static unsigned int scsi_debug_unmap_granularity = DEF_UNMAP_GRANULARITY; +static unsigned int scsi_debug_lbpu = DEF_LBPU; +static unsigned int scsi_debug_lbpws = DEF_LBPWS; +static unsigned int scsi_debug_lbpws10 = DEF_LBPWS10; +static unsigned int scsi_debug_lbprz = DEF_LBPRZ;  static unsigned int scsi_debug_unmap_alignment = DEF_UNMAP_ALIGNMENT; -static unsigned int scsi_debug_tpws = DEF_TPWS; -static unsigned int scsi_debug_tpu = DEF_TPU; +static unsigned int scsi_debug_unmap_granularity = DEF_UNMAP_GRANULARITY; +static unsigned int scsi_debug_unmap_max_blocks = DEF_UNMAP_MAX_BLOCKS; +static unsigned int scsi_debug_unmap_max_desc = DEF_UNMAP_MAX_DESC; +static unsigned int scsi_debug_write_same_length = DEF_WRITESAME_LENGTH; +static bool scsi_debug_removable = DEF_REMOVABLE; +static bool scsi_debug_clustering;  static int scsi_debug_cmnd_count = 0;  #define DEV_READONLY(TGT)      (0) -#define DEV_REMOVEABLE(TGT)    (0)  static unsigned int sdebug_store_sectors;  static sector_t sdebug_capacity;	/* in sectors */ @@ -206,6 +218,11 @@ static int sdebug_sectors_per;		/* sectors per cylinder */  #define SCSI_DEBUG_MAX_CMD_LEN 32 +static unsigned int scsi_debug_lbp(void) +{ +	return scsi_debug_lbpu | scsi_debug_lbpws | scsi_debug_lbpws10; +} +  struct sdebug_dev_info {  	struct list_head dev_list;  	unsigned char sense_buff[SDEBUG_SENSE_LEN];	/* weak nexus */ @@ -244,7 +261,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; @@ -263,11 +280,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, @@ -284,6 +296,20 @@ static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,  static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,  			           0, 0, 0x0, 0x0}; +static void *fake_store(unsigned long long lba) +{ +	lba = do_div(lba, sdebug_store_sectors); + +	return fake_storep + lba * scsi_debug_sector_size; +} + +static struct sd_dif_tuple *dif_store(sector_t sector) +{ +	sector = do_div(sector, sdebug_store_sectors); + +	return dif_storep + sector; +} +  static int sdebug_add_adapter(void);  static void sdebug_remove_adapter(void); @@ -425,10 +451,7 @@ static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,  	act_len = sg_copy_from_buffer(sdb->table.sgl, sdb->table.nents,  				      arr, arr_len); -	if (sdb->resid) -		sdb->resid -= act_len; -	else -		sdb->resid = scsi_bufflen(scp) - act_len; +	sdb->resid = scsi_bufflen(scp) - act_len;  	return 0;  } @@ -727,7 +750,7 @@ static int inquiry_evpd_b0(unsigned char * arr)  	/* Optimal Transfer Length */  	put_unaligned_be32(scsi_debug_opt_blks, &arr[8]); -	if (scsi_debug_tpu) { +	if (scsi_debug_lbpu) {  		/* Maximum Unmap LBA Count */  		put_unaligned_be32(scsi_debug_unmap_max_blocks, &arr[16]); @@ -744,7 +767,10 @@ static int inquiry_evpd_b0(unsigned char * arr)  	/* Optimal Unmap Granularity */  	put_unaligned_be32(scsi_debug_unmap_granularity, &arr[24]); -	return 0x3c; /* Mandatory page length for thin provisioning */ +	/* Maximum WRITE SAME Length */ +	put_unaligned_be64(scsi_debug_write_same_length, &arr[32]); + +	return 0x3c; /* Mandatory page length for Logical Block Provisioning */  	return sizeof(vpdb0_data);  } @@ -761,19 +787,25 @@ static int inquiry_evpd_b1(unsigned char *arr)  	return 0x3c;  } -/* Thin provisioning VPD page (SBC-3) */ +/* Logical block provisioning VPD page (SBC-3) */  static int inquiry_evpd_b2(unsigned char *arr)  { -	memset(arr, 0, 0x8); +	memset(arr, 0, 0x4);  	arr[0] = 0;			/* threshold exponent */ -	if (scsi_debug_tpu) +	if (scsi_debug_lbpu)  		arr[1] = 1 << 7; -	if (scsi_debug_tpws) +	if (scsi_debug_lbpws)  		arr[1] |= 1 << 6; -	return 0x8; +	if (scsi_debug_lbpws10) +		arr[1] |= 1 << 5; + +	if (scsi_debug_lbprz) +		arr[1] |= 1 << 2; + +	return 0x4;  }  #define SDEBUG_LONG_INQ_SZ 96 @@ -831,7 +863,8 @@ static int resp_inquiry(struct scsi_cmnd * scp, int target,  			arr[n++] = 0x89;  /* ATA information */  			arr[n++] = 0xb0;  /* Block limits (SBC) */  			arr[n++] = 0xb1;  /* Block characteristics (SBC) */ -			arr[n++] = 0xb2;  /* Thin provisioning (SBC) */ +			if (scsi_debug_lbp()) /* Logical Block Prov. (SBC) */ +				arr[n++] = 0xb2;  			arr[3] = n - 4;	  /* number of supported VPD pages */  		} else if (0x80 == cmd[2]) { /* unit serial number */  			arr[1] = cmd[2];	/*sanity */ @@ -879,7 +912,7 @@ static int resp_inquiry(struct scsi_cmnd * scp, int target,  		} else if (0xb1 == cmd[2]) { /* Block characteristics (SBC) */  			arr[1] = cmd[2];        /*sanity */  			arr[3] = inquiry_evpd_b1(&arr[4]); -		} else if (0xb2 == cmd[2]) { /* Thin provisioning (SBC) */ +		} else if (0xb2 == cmd[2]) { /* Logical Block Prov. (SBC) */  			arr[1] = cmd[2];        /*sanity */  			arr[3] = inquiry_evpd_b2(&arr[4]);  		} else { @@ -896,7 +929,7 @@ static int resp_inquiry(struct scsi_cmnd * scp, int target,  		return ret;  	}  	/* drops through here for a standard inquiry */ -	arr[1] = DEV_REMOVEABLE(target) ? 0x80 : 0;	/* Removable disk */ +	arr[1] = scsi_debug_removable ? 0x80 : 0;	/* Removable disk */  	arr[2] = scsi_debug_scsi_level;  	arr[3] = 2;    /* response_data_format==2 */  	arr[4] = SDEBUG_LONG_INQ_SZ - 5; @@ -1053,8 +1086,11 @@ static int resp_readcap16(struct scsi_cmnd * scp,  	arr[13] = scsi_debug_physblk_exp & 0xf;  	arr[14] = (scsi_debug_lowest_aligned >> 8) & 0x3f; -	if (scsi_debug_tpu || scsi_debug_tpws) -		arr[14] |= 0x80; /* TPE */ +	if (scsi_debug_lbp()) { +		arr[14] |= 0x80; /* LBPME */ +		if (scsi_debug_lbprz) +			arr[14] |= 0x40; /* LBPRZ */ +	}  	arr[15] = scsi_debug_lowest_aligned & 0xff; @@ -1185,7 +1221,7 @@ static int resp_format_pg(unsigned char * p, int pcontrol, int target)  	p[11] = sdebug_sectors_per & 0xff;  	p[12] = (scsi_debug_sector_size >> 8) & 0xff;  	p[13] = scsi_debug_sector_size & 0xff; -	if (DEV_REMOVEABLE(target)) +	if (scsi_debug_removable)  		p[20] |= 0x20; /* should agree with INQUIRY */  	if (1 == pcontrol)  		memset(p + 2, 0, sizeof(format_pg) - 2); @@ -1666,114 +1702,159 @@ static int check_device_access_params(struct sdebug_dev_info *devi,  	return 0;  } +/* Returns number of bytes copied or -1 if error. */  static int do_device_access(struct scsi_cmnd *scmd,  			    struct sdebug_dev_info *devi,  			    unsigned long long lba, unsigned int num, int write)  {  	int ret; -	unsigned int block, rest = 0; -	int (*func)(struct scsi_cmnd *, unsigned char *, int); +	unsigned long long block, rest = 0; +	struct scsi_data_buffer *sdb; +	enum dma_data_direction dir; +	size_t (*func)(struct scatterlist *, unsigned int, void *, size_t, +		       off_t); + +	if (write) { +		sdb = scsi_out(scmd); +		dir = DMA_TO_DEVICE; +		func = sg_pcopy_to_buffer; +	} else { +		sdb = scsi_in(scmd); +		dir = DMA_FROM_DEVICE; +		func = sg_pcopy_from_buffer; +	} -	func = write ? fetch_to_dev_buffer : fill_from_dev_buffer; +	if (!sdb->length) +		return 0; +	if (!(scsi_bidi_cmnd(scmd) || scmd->sc_data_direction == dir)) +		return -1;  	block = do_div(lba, sdebug_store_sectors);  	if (block + num > sdebug_store_sectors)  		rest = block + num - sdebug_store_sectors; -	ret = func(scmd, fake_storep + (block * scsi_debug_sector_size), -		   (num - rest) * scsi_debug_sector_size); -	if (!ret && rest) -		ret = func(scmd, fake_storep, rest * scsi_debug_sector_size); +	ret = func(sdb->table.sgl, sdb->table.nents, +		   fake_storep + (block * scsi_debug_sector_size), +		   (num - rest) * scsi_debug_sector_size, 0); +	if (ret != (num - rest) * scsi_debug_sector_size) +		return ret; + +	if (rest) { +		ret += func(sdb->table.sgl, sdb->table.nents, +			    fake_storep, rest * scsi_debug_sector_size, +			    (num - rest) * scsi_debug_sector_size); +	}  	return ret;  } -static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec, -			    unsigned int sectors, u32 ei_lba) +static __be16 dif_compute_csum(const void *buf, int len)  { -	unsigned int i, resid; -	struct scatterlist *psgl; -	struct sd_dif_tuple *sdt; -	sector_t sector; -	sector_t tmp_sec = start_sec; -	void *paddr; +	__be16 csum; -	start_sec = do_div(tmp_sec, sdebug_store_sectors); +	if (scsi_debug_guard) +		csum = (__force __be16)ip_compute_csum(buf, len); +	else +		csum = cpu_to_be16(crc_t10dif(buf, len)); -	sdt = (struct sd_dif_tuple *)(dif_storep + dif_offset(start_sec)); +	return csum; +} -	for (i = 0 ; i < sectors ; i++) { -		u16 csum; +static int dif_verify(struct sd_dif_tuple *sdt, const void *data, +		      sector_t sector, u32 ei_lba) +{ +	__be16 csum = dif_compute_csum(data, scsi_debug_sector_size); -		if (sdt[i].app_tag == 0xffff) -			continue; +	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); +		return 0x03; +	} +	return 0; +} -		sector = start_sec + i; +static void dif_copy_prot(struct scsi_cmnd *SCpnt, sector_t sector, +			  unsigned int sectors, bool read) +{ +	size_t resid; +	void *paddr; +	const void *dif_store_end = dif_storep + sdebug_store_sectors; +	struct sg_mapping_iter miter; -		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(); -		} +	/* Bytes of protection data to copy into sgl */ +	resid = sectors * sizeof(*dif_storep); -		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; -		} +	sg_miter_start(&miter, scsi_prot_sglist(SCpnt), +			scsi_prot_sg_count(SCpnt), SG_MITER_ATOMIC | +			(read ? SG_MITER_TO_SG : SG_MITER_FROM_SG)); -		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); -			dif_errors++; -			return 0x03; -		} +	while (sg_miter_next(&miter) && resid > 0) { +		size_t len = min(miter.length, resid); +		void *start = dif_store(sector); +		size_t rest = 0; -		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; +		if (dif_store_end < start + len) +			rest = start + len - dif_store_end; + +		paddr = miter.addr; + +		if (read) +			memcpy(paddr, start, len - rest); +		else +			memcpy(start, paddr, len - rest); + +		if (rest) { +			if (read) +				memcpy(paddr + len - rest, dif_storep, rest); +			else +				memcpy(dif_storep, paddr + len - rest, rest);  		} -		ei_lba++; +		sector += len / sizeof(*dif_storep); +		resid -= len;  	} +	sg_miter_stop(&miter); +} -	resid = sectors * 8; /* Bytes of protection data to copy into sgl */ -	sector = start_sec; +static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec, +			    unsigned int sectors, u32 ei_lba) +{ +	unsigned int i; +	struct sd_dif_tuple *sdt; +	sector_t sector; -	scsi_for_each_prot_sg(SCpnt, psgl, scsi_prot_sg_count(SCpnt), i) { -		int len = min(psgl->length, resid); +	for (i = 0; i < sectors; i++, ei_lba++) { +		int ret; -		paddr = kmap_atomic(sg_page(psgl), KM_IRQ0) + psgl->offset; -		memcpy(paddr, dif_storep + dif_offset(sector), len); +		sector = start_sec + i; +		sdt = dif_store(sector); + +		if (sdt->app_tag == cpu_to_be16(0xffff)) +			continue; -		sector += len >> 3; -		if (sector >= sdebug_store_sectors) { -			/* Force wrap */ -			tmp_sec = sector; -			sector = do_div(tmp_sec, sdebug_store_sectors); +		ret = dif_verify(sdt, fake_store(sector), sector, ei_lba); +		if (ret) { +			dif_errors++; +			return ret;  		} -		resid -= len; -		kunmap_atomic(paddr, KM_IRQ0);  	} +	dif_copy_prot(SCpnt, start_sec, sectors, true);  	dix_reads++;  	return 0; @@ -1791,37 +1872,45 @@ static int resp_read(struct scsi_cmnd *SCpnt, unsigned long long lba,  		return ret;  	if ((SCSI_DEBUG_OPT_MEDIUM_ERR & scsi_debug_opts) && -	    (lba <= OPT_MEDIUM_ERR_ADDR) && +	    (lba <= (OPT_MEDIUM_ERR_ADDR + OPT_MEDIUM_ERR_NUM - 1)) &&  	    ((lba + num) > OPT_MEDIUM_ERR_ADDR)) {  		/* claim unrecoverable read error */ -		mk_sense_buffer(devip, MEDIUM_ERROR, UNRECOVERED_READ_ERR, -				0); +		mk_sense_buffer(devip, MEDIUM_ERROR, UNRECOVERED_READ_ERR, 0);  		/* set info field and valid bit for fixed descriptor */  		if (0x70 == (devip->sense_buff[0] & 0x7f)) {  			devip->sense_buff[0] |= 0x80;	/* Valid bit */ -			ret = OPT_MEDIUM_ERR_ADDR; +			ret = (lba < OPT_MEDIUM_ERR_ADDR) +			      ? OPT_MEDIUM_ERR_ADDR : (int)lba;  			devip->sense_buff[3] = (ret >> 24) & 0xff;  			devip->sense_buff[4] = (ret >> 16) & 0xff;  			devip->sense_buff[5] = (ret >> 8) & 0xff;  			devip->sense_buff[6] = ret & 0xff;  		} +	        scsi_set_resid(SCpnt, scsi_bufflen(SCpnt));  		return check_condition_result;  	} +	read_lock_irqsave(&atomic_rw, iflags); +  	/* DIX + T10 DIF */  	if (scsi_debug_dix && scsi_prot_sg_count(SCpnt)) {  		int prot_ret = prot_verify_read(SCpnt, lba, num, ei_lba);  		if (prot_ret) { +			read_unlock_irqrestore(&atomic_rw, iflags);  			mk_sense_buffer(devip, ABORTED_COMMAND, 0x10, prot_ret);  			return illegal_condition_result;  		}  	} -	read_lock_irqsave(&atomic_rw, iflags);  	ret = do_device_access(SCpnt, devip, lba, num, 0);  	read_unlock_irqrestore(&atomic_rw, iflags); -	return ret; +	if (ret == -1) +		return DID_ERROR << 16; + +	scsi_in(SCpnt)->resid = scsi_bufflen(SCpnt) - ret; + +	return 0;  }  void dump_sector(unsigned char *buf, int len) @@ -1848,145 +1937,114 @@ void dump_sector(unsigned char *buf, int len)  static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,  			     unsigned int sectors, u32 ei_lba)  { -	int i, j, ret; +	int ret;  	struct sd_dif_tuple *sdt; -	struct scatterlist *dsgl = scsi_sglist(SCpnt); -	struct scatterlist *psgl = scsi_prot_sglist(SCpnt); -	void *daddr, *paddr; -	sector_t tmp_sec = start_sec; -	sector_t sector; +	void *daddr; +	sector_t sector = start_sec;  	int ppage_offset; -	unsigned short csum; - -	sector = do_div(tmp_sec, sdebug_store_sectors); +	int dpage_offset; +	struct sg_mapping_iter diter; +	struct sg_mapping_iter piter;  	BUG_ON(scsi_sg_count(SCpnt) == 0);  	BUG_ON(scsi_prot_sg_count(SCpnt) == 0); -	paddr = kmap_atomic(sg_page(psgl), KM_IRQ1) + 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), KM_IRQ0) + dsgl->offset; - -		/* For each sector-sized chunk in data page */ -		for (j = 0 ; j < dsgl->length ; j += scsi_debug_sector_size) { +	sg_miter_start(&piter, scsi_prot_sglist(SCpnt), +			scsi_prot_sg_count(SCpnt), +			SG_MITER_ATOMIC | SG_MITER_FROM_SG); +	sg_miter_start(&diter, scsi_sglist(SCpnt), scsi_sg_count(SCpnt), +			SG_MITER_ATOMIC | SG_MITER_FROM_SG); + +	/* For each protection page */ +	while (sg_miter_next(&piter)) { +		dpage_offset = 0; +		if (WARN_ON(!sg_miter_next(&diter))) { +			ret = 0x01; +			goto out; +		} +		for (ppage_offset = 0; ppage_offset < piter.length; +		     ppage_offset += sizeof(struct sd_dif_tuple)) {  			/* If we're at the end of the current -			 * protection page advance to the next one +			 * data page advance to the next one  			 */ -			if (ppage_offset >= psgl->length) { -				kunmap_atomic(paddr, KM_IRQ1); -				psgl = sg_next(psgl); -				BUG_ON(psgl == NULL); -				paddr = kmap_atomic(sg_page(psgl), KM_IRQ1) -					+ psgl->offset; -				ppage_offset = 0; +			if (dpage_offset >= diter.length) { +				if (WARN_ON(!sg_miter_next(&diter))) { +					ret = 0x01; +					goto out; +				} +				dpage_offset = 0;  			} -			sdt = paddr + ppage_offset; +			sdt = piter.addr + ppage_offset; +			daddr = diter.addr + dpage_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; +			ret = dif_verify(sdt, daddr, sector, ei_lba); +			if (ret) {  				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); -				goto out; -			} - -			/* Would be great to copy this in bigger -			 * chunks.  However, for the sake of -			 * correctness we need to verify each sector -			 * before writing it to "stable" storage -			 */ -			memcpy(dif_storep + dif_offset(sector), sdt, 8); -  			sector++; - -			if (sector == sdebug_store_sectors) -				sector = 0;	/* Force wrap */ - -			start_sec++;  			ei_lba++; -			daddr += scsi_debug_sector_size; -			ppage_offset += sizeof(struct sd_dif_tuple); +			dpage_offset += scsi_debug_sector_size;  		} - -		kunmap_atomic(daddr, KM_IRQ0); +		diter.consumed = dpage_offset; +		sg_miter_stop(&diter);  	} +	sg_miter_stop(&piter); -	kunmap_atomic(paddr, KM_IRQ1); - +	dif_copy_prot(SCpnt, start_sec, sectors, false);  	dix_writes++;  	return 0;  out:  	dif_errors++; -	kunmap_atomic(daddr, KM_IRQ0); -	kunmap_atomic(paddr, KM_IRQ1); +	sg_miter_stop(&diter); +	sg_miter_stop(&piter);  	return ret;  } -static unsigned int map_state(sector_t lba, unsigned int *num) +static unsigned long lba_to_map_index(sector_t lba)  { -	unsigned int granularity, alignment, mapped; -	sector_t block, next, end; +	if (scsi_debug_unmap_alignment) { +		lba += scsi_debug_unmap_granularity - +			scsi_debug_unmap_alignment; +	} +	do_div(lba, scsi_debug_unmap_granularity); + +	return lba; +} + +static sector_t map_index_to_lba(unsigned long index) +{ +	sector_t lba = index * scsi_debug_unmap_granularity; + +	if (scsi_debug_unmap_alignment) { +		lba -= scsi_debug_unmap_granularity - +			scsi_debug_unmap_alignment; +	} -	granularity = scsi_debug_unmap_granularity; -	alignment = granularity - scsi_debug_unmap_alignment; -	block = lba + alignment; -	do_div(block, granularity); +	return lba; +} -	mapped = test_bit(block, map_storep); +static unsigned int map_state(sector_t lba, unsigned int *num) +{ +	sector_t end; +	unsigned int mapped; +	unsigned long index; +	unsigned long next; + +	index = lba_to_map_index(lba); +	mapped = test_bit(index, map_storep);  	if (mapped) -		next = find_next_zero_bit(map_storep, map_size, block); +		next = find_next_zero_bit(map_storep, map_size, index);  	else -		next = find_next_bit(map_storep, map_size, block); +		next = find_next_bit(map_storep, map_size, index); -	end = next * granularity - scsi_debug_unmap_alignment; +	end = min_t(sector_t, sdebug_store_sectors,  map_index_to_lba(next));  	*num = end - lba;  	return mapped; @@ -1994,44 +2052,42 @@ static unsigned int map_state(sector_t lba, unsigned int *num)  static void map_region(sector_t lba, unsigned int len)  { -	unsigned int granularity, alignment;  	sector_t end = lba + len; -	granularity = scsi_debug_unmap_granularity; -	alignment = granularity - scsi_debug_unmap_alignment; -  	while (lba < end) { -		sector_t block, rem; +		unsigned long index = lba_to_map_index(lba); -		block = lba + alignment; -		rem = do_div(block, granularity); +		if (index < map_size) +			set_bit(index, map_storep); -		if (block < map_size) -			set_bit(block, map_storep); - -		lba += granularity - rem; +		lba = map_index_to_lba(index + 1);  	}  }  static void unmap_region(sector_t lba, unsigned int len)  { -	unsigned int granularity, alignment;  	sector_t end = lba + len; -	granularity = scsi_debug_unmap_granularity; -	alignment = granularity - scsi_debug_unmap_alignment; -  	while (lba < end) { -		sector_t block, rem; - -		block = lba + alignment; -		rem = do_div(block, granularity); - -		if (rem == 0 && lba + granularity <= end && -		    block < map_size) -			clear_bit(block, map_storep); - -		lba += granularity - rem; +		unsigned long index = lba_to_map_index(lba); + +		if (lba == map_index_to_lba(index) && +		    lba + scsi_debug_unmap_granularity <= end && +		    index < map_size) { +			clear_bit(index, map_storep); +			if (scsi_debug_lbprz) { +				memset(fake_storep + +				       lba * scsi_debug_sector_size, 0, +				       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);  	}  } @@ -2046,19 +2102,21 @@ static int resp_write(struct scsi_cmnd *SCpnt, unsigned long long lba,  	if (ret)  		return ret; +	write_lock_irqsave(&atomic_rw, iflags); +  	/* DIX + T10 DIF */  	if (scsi_debug_dix && scsi_prot_sg_count(SCpnt)) {  		int prot_ret = prot_verify_write(SCpnt, lba, num, ei_lba);  		if (prot_ret) { +			write_unlock_irqrestore(&atomic_rw, iflags);  			mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x10, prot_ret);  			return illegal_condition_result;  		}  	} -	write_lock_irqsave(&atomic_rw, iflags);  	ret = do_device_access(SCpnt, devip, lba, num, 1); -	if (scsi_debug_unmap_granularity) +	if (scsi_debug_lbp())  		map_region(lba, num);  	write_unlock_irqrestore(&atomic_rw, iflags);  	if (-1 == ret) @@ -2083,9 +2141,15 @@ static int resp_write_same(struct scsi_cmnd *scmd, unsigned long long lba,  	if (ret)  		return ret; +	if (num > scsi_debug_write_same_length) { +		mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, +				0); +		return check_condition_result; +	} +  	write_lock_irqsave(&atomic_rw, iflags); -	if (unmap && scsi_debug_unmap_granularity) { +	if (unmap && scsi_debug_lbp()) {  		unmap_region(lba, num);  		goto out;  	} @@ -2109,7 +2173,7 @@ static int resp_write_same(struct scsi_cmnd *scmd, unsigned long long lba,  		       fake_storep + (lba * scsi_debug_sector_size),  		       scsi_debug_sector_size); -	if (scsi_debug_unmap_granularity) +	if (scsi_debug_lbp())  		map_region(lba, num);  out:  	write_unlock_irqrestore(&atomic_rw, iflags); @@ -2129,6 +2193,7 @@ static int resp_unmap(struct scsi_cmnd * scmd, struct sdebug_dev_info * devip)  	struct unmap_block_desc *desc;  	unsigned int i, payload_len, descriptors;  	int ret; +	unsigned long iflags;  	ret = check_readiness(scmd, 1, devip);  	if (ret) @@ -2150,6 +2215,8 @@ static int resp_unmap(struct scsi_cmnd * scmd, struct sdebug_dev_info * devip)  	desc = (void *)&buf[8]; +	write_lock_irqsave(&atomic_rw, iflags); +  	for (i = 0 ; i < descriptors ; i++) {  		unsigned long long lba = get_unaligned_be64(&desc[i].lba);  		unsigned int num = get_unaligned_be32(&desc[i].blocks); @@ -2164,6 +2231,7 @@ static int resp_unmap(struct scsi_cmnd * scmd, struct sdebug_dev_info * devip)  	ret = 0;  out: +	write_unlock_irqrestore(&atomic_rw, iflags);  	kfree(buf);  	return ret; @@ -2196,7 +2264,7 @@ static int resp_get_lba_status(struct scsi_cmnd * scmd,  	mapped = map_state(lba, &num);  	memset(arr, 0, SDEBUG_GET_LBA_STATUS_LEN); -	put_unaligned_be32(16, &arr[0]);	/* Parameter Data Length */ +	put_unaligned_be32(20, &arr[0]);	/* Parameter Data Length */  	put_unaligned_be64(lba, &arr[8]);	/* LBA */  	put_unaligned_be32(num, &arr[16]);	/* Number of blocks */  	arr[20] = !mapped;			/* mapped = 0, unmapped = 1 */ @@ -2264,36 +2332,37 @@ static int resp_report_luns(struct scsi_cmnd * scp,  static int resp_xdwriteread(struct scsi_cmnd *scp, unsigned long long lba,  			    unsigned int num, struct sdebug_dev_info *devip)  { -	int i, j, ret = -1; +	int j;  	unsigned char *kaddr, *buf;  	unsigned int offset; -	struct scatterlist *sg;  	struct scsi_data_buffer *sdb = scsi_in(scp); +	struct sg_mapping_iter miter;  	/* better not to use temporary buffer. */  	buf = kmalloc(scsi_bufflen(scp), GFP_ATOMIC); -	if (!buf) -		return ret; +	if (!buf) { +		mk_sense_buffer(devip, NOT_READY, +				LOGICAL_UNIT_COMMUNICATION_FAILURE, 0); +		return check_condition_result; +	}  	scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));  	offset = 0; -	for_each_sg(sdb->table.sgl, sg, sdb->table.nents, i) { -		kaddr = (unsigned char *)kmap_atomic(sg_page(sg), KM_USER0); -		if (!kaddr) -			goto out; +	sg_miter_start(&miter, sdb->table.sgl, sdb->table.nents, +			SG_MITER_ATOMIC | SG_MITER_TO_SG); -		for (j = 0; j < sg->length; j++) -			*(kaddr + sg->offset + j) ^= *(buf + offset + j); +	while (sg_miter_next(&miter)) { +		kaddr = miter.addr; +		for (j = 0; j < miter.length; j++) +			*(kaddr + j) ^= *(buf + offset + j); -		offset += sg->length; -		kunmap_atomic(kaddr, KM_USER0); +		offset += miter.length;  	} -	ret = 0; -out: +	sg_miter_stop(&miter);  	kfree(buf); -	return ret; +	return 0;  }  /* When timer goes off this function is called. */ @@ -2430,7 +2499,7 @@ static void scsi_debug_slave_destroy(struct scsi_device *sdp)  		printk(KERN_INFO "scsi_debug: slave_destroy <%u %u %u %u>\n",  		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);  	if (devip) { -		/* make this slot avaliable for re-use */ +		/* make this slot available for re-use */  		devip->used = 0;  		sdp->hostdata = NULL;  	} @@ -2625,8 +2694,8 @@ static void __init sdebug_build_parts(unsigned char *ramp,  			       / sdebug_sectors_per;  		pp->end_sector = (end_sec % sdebug_sectors_per) + 1; -		pp->start_sect = start_sec; -		pp->nr_sects = end_sec - start_sec + 1; +		pp->start_sect = cpu_to_le32(start_sec); +		pp->nr_sects = cpu_to_le32(end_sec - start_sec + 1);  		pp->sys_ind = 0x83;	/* plain Linux partition */  	}  } @@ -2694,37 +2763,43 @@ static int schedule_resp(struct scsi_cmnd * cmnd,     /sys/bus/pseudo/drivers/scsi_debug directory is changed.   */  module_param_named(add_host, scsi_debug_add_host, int, S_IRUGO | S_IWUSR); +module_param_named(ato, scsi_debug_ato, int, S_IRUGO); +module_param_named(clustering, scsi_debug_clustering, bool, S_IRUGO | S_IWUSR);  module_param_named(delay, scsi_debug_delay, int, S_IRUGO | S_IWUSR);  module_param_named(dev_size_mb, scsi_debug_dev_size_mb, int, S_IRUGO); +module_param_named(dif, scsi_debug_dif, int, S_IRUGO); +module_param_named(dix, scsi_debug_dix, int, S_IRUGO);  module_param_named(dsense, scsi_debug_dsense, int, S_IRUGO | S_IWUSR);  module_param_named(every_nth, scsi_debug_every_nth, int, S_IRUGO | S_IWUSR);  module_param_named(fake_rw, scsi_debug_fake_rw, int, S_IRUGO | S_IWUSR); +module_param_named(guard, scsi_debug_guard, uint, S_IRUGO); +module_param_named(lbpu, scsi_debug_lbpu, int, S_IRUGO); +module_param_named(lbpws, scsi_debug_lbpws, int, S_IRUGO); +module_param_named(lbpws10, scsi_debug_lbpws10, int, S_IRUGO); +module_param_named(lbprz, scsi_debug_lbprz, int, S_IRUGO); +module_param_named(lowest_aligned, scsi_debug_lowest_aligned, int, S_IRUGO);  module_param_named(max_luns, scsi_debug_max_luns, int, S_IRUGO | S_IWUSR);  module_param_named(max_queue, scsi_debug_max_queue, int, S_IRUGO | S_IWUSR);  module_param_named(no_lun_0, scsi_debug_no_lun_0, int, S_IRUGO | S_IWUSR);  module_param_named(no_uld, scsi_debug_no_uld, int, S_IRUGO);  module_param_named(num_parts, scsi_debug_num_parts, int, S_IRUGO);  module_param_named(num_tgts, scsi_debug_num_tgts, int, S_IRUGO | S_IWUSR); +module_param_named(opt_blks, scsi_debug_opt_blks, int, S_IRUGO);  module_param_named(opts, scsi_debug_opts, int, S_IRUGO | S_IWUSR); +module_param_named(physblk_exp, scsi_debug_physblk_exp, int, S_IRUGO);  module_param_named(ptype, scsi_debug_ptype, int, S_IRUGO | S_IWUSR); +module_param_named(removable, scsi_debug_removable, bool, S_IRUGO | S_IWUSR);  module_param_named(scsi_level, scsi_debug_scsi_level, int, S_IRUGO); -module_param_named(virtual_gb, scsi_debug_virtual_gb, int, S_IRUGO | S_IWUSR); -module_param_named(vpd_use_hostno, scsi_debug_vpd_use_hostno, int, -		   S_IRUGO | S_IWUSR);  module_param_named(sector_size, scsi_debug_sector_size, int, S_IRUGO); -module_param_named(dix, scsi_debug_dix, int, S_IRUGO); -module_param_named(dif, scsi_debug_dif, int, S_IRUGO); -module_param_named(guard, scsi_debug_guard, int, S_IRUGO); -module_param_named(ato, scsi_debug_ato, int, S_IRUGO); -module_param_named(physblk_exp, scsi_debug_physblk_exp, int, S_IRUGO); -module_param_named(opt_blks, scsi_debug_opt_blks, int, S_IRUGO); -module_param_named(lowest_aligned, scsi_debug_lowest_aligned, int, S_IRUGO); +module_param_named(unmap_alignment, scsi_debug_unmap_alignment, int, S_IRUGO); +module_param_named(unmap_granularity, scsi_debug_unmap_granularity, int, S_IRUGO);  module_param_named(unmap_max_blocks, scsi_debug_unmap_max_blocks, int, S_IRUGO);  module_param_named(unmap_max_desc, scsi_debug_unmap_max_desc, int, S_IRUGO); -module_param_named(unmap_granularity, scsi_debug_unmap_granularity, int, S_IRUGO); -module_param_named(unmap_alignment, scsi_debug_unmap_alignment, int, S_IRUGO); -module_param_named(tpu, scsi_debug_tpu, int, S_IRUGO); -module_param_named(tpws, scsi_debug_tpws, int, S_IRUGO); +module_param_named(virtual_gb, scsi_debug_virtual_gb, int, S_IRUGO | S_IWUSR); +module_param_named(vpd_use_hostno, scsi_debug_vpd_use_hostno, int, +		   S_IRUGO | S_IWUSR); +module_param_named(write_same_length, scsi_debug_write_same_length, int, +		   S_IRUGO | S_IWUSR);  MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");  MODULE_DESCRIPTION("SCSI debug adapter driver"); @@ -2732,36 +2807,41 @@ MODULE_LICENSE("GPL");  MODULE_VERSION(SCSI_DEBUG_VERSION);  MODULE_PARM_DESC(add_host, "0..127 hosts allowed(def=1)"); +MODULE_PARM_DESC(ato, "application tag ownership: 0=disk 1=host (def=1)"); +MODULE_PARM_DESC(clustering, "when set enables larger transfers (def=0)");  MODULE_PARM_DESC(delay, "# of jiffies to delay response(def=1)");  MODULE_PARM_DESC(dev_size_mb, "size in MB of ram shared by devs(def=8)"); +MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)"); +MODULE_PARM_DESC(dix, "data integrity extensions mask (def=0)");  MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)");  MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)");  MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)"); +MODULE_PARM_DESC(guard, "protection checksum: 0=crc, 1=ip (def=0)"); +MODULE_PARM_DESC(lbpu, "enable LBP, support UNMAP command (def=0)"); +MODULE_PARM_DESC(lbpws, "enable LBP, support WRITE SAME(16) with UNMAP bit (def=0)"); +MODULE_PARM_DESC(lbpws10, "enable LBP, support WRITE SAME(10) with UNMAP bit (def=0)"); +MODULE_PARM_DESC(lbprz, "unmapped blocks return 0 on read (def=1)"); +MODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)");  MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");  MODULE_PARM_DESC(max_queue, "max number of queued commands (1 to 255(def))");  MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");  MODULE_PARM_DESC(no_uld, "stop ULD (e.g. sd driver) attaching (def=0))");  MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");  MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)"); +MODULE_PARM_DESC(opt_blks, "optimal transfer length in block (def=64)");  MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)"); +MODULE_PARM_DESC(physblk_exp, "physical block exponent (def=0)");  MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])"); +MODULE_PARM_DESC(removable, "claim to have removable media (def=0)");  MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=5[SPC-3])"); -MODULE_PARM_DESC(virtual_gb, "virtual gigabyte size (def=0 -> use dev_size_mb)"); -MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");  MODULE_PARM_DESC(sector_size, "logical block size in bytes (def=512)"); -MODULE_PARM_DESC(physblk_exp, "physical block exponent (def=0)"); -MODULE_PARM_DESC(opt_blks, "optimal transfer length in block (def=64)"); -MODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)"); -MODULE_PARM_DESC(dix, "data integrity extensions mask (def=0)"); -MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)"); -MODULE_PARM_DESC(guard, "protection checksum: 0=crc, 1=ip (def=0)"); -MODULE_PARM_DESC(ato, "application tag ownership: 0=disk 1=host (def=1)"); +MODULE_PARM_DESC(unmap_alignment, "lowest aligned thin provisioning lba (def=0)"); +MODULE_PARM_DESC(unmap_granularity, "thin provisioning granularity in blocks (def=1)");  MODULE_PARM_DESC(unmap_max_blocks, "max # of blocks can be unmapped in one cmd (def=0xffffffff)");  MODULE_PARM_DESC(unmap_max_desc, "max # of ranges that can be unmapped in one cmd (def=256)"); -MODULE_PARM_DESC(unmap_granularity, "thin provisioning granularity in blocks (def=1)"); -MODULE_PARM_DESC(unmap_alignment, "lowest aligned thin provisioning lba (def=0)"); -MODULE_PARM_DESC(tpu, "enable TP, support UNMAP command (def=0)"); -MODULE_PARM_DESC(tpws, "enable TP, support WRITE SAME(16) with UNMAP bit (def=0)"); +MODULE_PARM_DESC(virtual_gb, "virtual gigabyte size (def=0 -> use dev_size_mb)"); +MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)"); +MODULE_PARM_DESC(write_same_length, "Maximum blocks per WRITE SAME cmd (def=0xffff)");  static char sdebug_info[256]; @@ -2777,31 +2857,27 @@ static const char * scsi_debug_info(struct Scsi_Host * shp)  /* scsi_debug_proc_info   * Used if the driver currently has no own support for /proc/scsi   */ -static int scsi_debug_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset, -				int length, int inout) +static int scsi_debug_write_info(struct Scsi_Host *host, char *buffer, int length)  { -	int len, pos, begin; -	int orig_length; +	char arr[16]; +	int opts; +	int minLen = length > 15 ? 15 : length; -	orig_length = length; - -	if (inout == 1) { -		char arr[16]; -		int minLen = length > 15 ? 15 : length; +	if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) +		return -EACCES; +	memcpy(arr, buffer, minLen); +	arr[minLen] = '\0'; +	if (1 != sscanf(arr, "%d", &opts)) +		return -EINVAL; +	scsi_debug_opts = opts; +	if (scsi_debug_every_nth != 0) +		scsi_debug_cmnd_count = 0; +	return length; +} -		if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) -			return -EACCES; -		memcpy(arr, buffer, minLen); -		arr[minLen] = '\0'; -		if (1 != sscanf(arr, "%d", &pos)) -			return -EINVAL; -		scsi_debug_opts = pos; -		if (scsi_debug_every_nth != 0) -                        scsi_debug_cmnd_count = 0; -		return length; -	} -	begin = 0; -	pos = len = sprintf(buffer, "scsi_debug adapter driver, version " +static int scsi_debug_show_info(struct seq_file *m, struct Scsi_Host *host) +{ +	seq_printf(m, "scsi_debug adapter driver, version "  	    "%s [%s]\n"  	    "num_tgts=%d, shared (ram) size=%d MB, opts=0x%x, "  	    "every_nth=%d(curr:%d)\n" @@ -2816,24 +2892,16 @@ static int scsi_debug_proc_info(struct Scsi_Host *host, char *buffer, char **sta  	    scsi_debug_sector_size, sdebug_cylinders_per, sdebug_heads,  	    sdebug_sectors_per, num_aborts, num_dev_resets, num_bus_resets,  	    num_host_resets, dix_reads, dix_writes, dif_errors); -	if (pos < offset) { -		len = 0; -		begin = pos; -	} -	*start = buffer + (offset - begin);	/* Start of wanted data */ -	len -= (offset - begin); -	if (len > length) -		len = length; -	return len; +	return 0;  } -static ssize_t sdebug_delay_show(struct device_driver * ddp, char * buf) +static ssize_t delay_show(struct device_driver *ddp, char *buf)  {          return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_delay);  } -static ssize_t sdebug_delay_store(struct device_driver * ddp, -				  const char * buf, size_t count) +static ssize_t delay_store(struct device_driver *ddp, const char *buf, +			   size_t count)  {          int delay;  	char work[20]; @@ -2846,16 +2914,15 @@ static ssize_t sdebug_delay_store(struct device_driver * ddp,  	}  	return -EINVAL;  } -DRIVER_ATTR(delay, S_IRUGO | S_IWUSR, sdebug_delay_show, -	    sdebug_delay_store); +static DRIVER_ATTR_RW(delay); -static ssize_t sdebug_opts_show(struct device_driver * ddp, char * buf) +static ssize_t opts_show(struct device_driver *ddp, char *buf)  {          return scnprintf(buf, PAGE_SIZE, "0x%x\n", scsi_debug_opts);  } -static ssize_t sdebug_opts_store(struct device_driver * ddp, -				 const char * buf, size_t count) +static ssize_t opts_store(struct device_driver *ddp, const char *buf, +			  size_t count)  {          int opts;  	char work[20]; @@ -2875,15 +2942,14 @@ opts_done:  	scsi_debug_cmnd_count = 0;  	return count;  } -DRIVER_ATTR(opts, S_IRUGO | S_IWUSR, sdebug_opts_show, -	    sdebug_opts_store); +static DRIVER_ATTR_RW(opts); -static ssize_t sdebug_ptype_show(struct device_driver * ddp, char * buf) +static ssize_t ptype_show(struct device_driver *ddp, char *buf)  {          return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_ptype);  } -static ssize_t sdebug_ptype_store(struct device_driver * ddp, -				  const char * buf, size_t count) +static ssize_t ptype_store(struct device_driver *ddp, const char *buf, +			   size_t count)  {          int n; @@ -2893,14 +2959,14 @@ static ssize_t sdebug_ptype_store(struct device_driver * ddp,  	}  	return -EINVAL;  } -DRIVER_ATTR(ptype, S_IRUGO | S_IWUSR, sdebug_ptype_show, sdebug_ptype_store); +static DRIVER_ATTR_RW(ptype); -static ssize_t sdebug_dsense_show(struct device_driver * ddp, char * buf) +static ssize_t dsense_show(struct device_driver *ddp, char *buf)  {          return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dsense);  } -static ssize_t sdebug_dsense_store(struct device_driver * ddp, -				  const char * buf, size_t count) +static ssize_t dsense_store(struct device_driver *ddp, const char *buf, +			    size_t count)  {          int n; @@ -2910,15 +2976,14 @@ static ssize_t sdebug_dsense_store(struct device_driver * ddp,  	}  	return -EINVAL;  } -DRIVER_ATTR(dsense, S_IRUGO | S_IWUSR, sdebug_dsense_show, -	    sdebug_dsense_store); +static DRIVER_ATTR_RW(dsense); -static ssize_t sdebug_fake_rw_show(struct device_driver * ddp, char * buf) +static ssize_t fake_rw_show(struct device_driver *ddp, char *buf)  {          return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_fake_rw);  } -static ssize_t sdebug_fake_rw_store(struct device_driver * ddp, -				    const char * buf, size_t count) +static ssize_t fake_rw_store(struct device_driver *ddp, const char *buf, +			     size_t count)  {          int n; @@ -2928,15 +2993,14 @@ static ssize_t sdebug_fake_rw_store(struct device_driver * ddp,  	}  	return -EINVAL;  } -DRIVER_ATTR(fake_rw, S_IRUGO | S_IWUSR, sdebug_fake_rw_show, -	    sdebug_fake_rw_store); +static DRIVER_ATTR_RW(fake_rw); -static ssize_t sdebug_no_lun_0_show(struct device_driver * ddp, char * buf) +static ssize_t no_lun_0_show(struct device_driver *ddp, char *buf)  {          return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_no_lun_0);  } -static ssize_t sdebug_no_lun_0_store(struct device_driver * ddp, -				     const char * buf, size_t count) +static ssize_t no_lun_0_store(struct device_driver *ddp, const char *buf, +			      size_t count)  {          int n; @@ -2946,15 +3010,14 @@ static ssize_t sdebug_no_lun_0_store(struct device_driver * ddp,  	}  	return -EINVAL;  } -DRIVER_ATTR(no_lun_0, S_IRUGO | S_IWUSR, sdebug_no_lun_0_show, -	    sdebug_no_lun_0_store); +static DRIVER_ATTR_RW(no_lun_0); -static ssize_t sdebug_num_tgts_show(struct device_driver * ddp, char * buf) +static ssize_t num_tgts_show(struct device_driver *ddp, char *buf)  {          return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_tgts);  } -static ssize_t sdebug_num_tgts_store(struct device_driver * ddp, -				     const char * buf, size_t count) +static ssize_t num_tgts_store(struct device_driver *ddp, const char *buf, +			      size_t count)  {          int n; @@ -2965,27 +3028,26 @@ static ssize_t sdebug_num_tgts_store(struct device_driver * ddp,  	}  	return -EINVAL;  } -DRIVER_ATTR(num_tgts, S_IRUGO | S_IWUSR, sdebug_num_tgts_show, -	    sdebug_num_tgts_store); +static DRIVER_ATTR_RW(num_tgts); -static ssize_t sdebug_dev_size_mb_show(struct device_driver * ddp, char * buf) +static ssize_t dev_size_mb_show(struct device_driver *ddp, char *buf)  {          return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dev_size_mb);  } -DRIVER_ATTR(dev_size_mb, S_IRUGO, sdebug_dev_size_mb_show, NULL); +static DRIVER_ATTR_RO(dev_size_mb); -static ssize_t sdebug_num_parts_show(struct device_driver * ddp, char * buf) +static ssize_t num_parts_show(struct device_driver *ddp, char *buf)  {          return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_parts);  } -DRIVER_ATTR(num_parts, S_IRUGO, sdebug_num_parts_show, NULL); +static DRIVER_ATTR_RO(num_parts); -static ssize_t sdebug_every_nth_show(struct device_driver * ddp, char * buf) +static ssize_t every_nth_show(struct device_driver *ddp, char *buf)  {          return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_every_nth);  } -static ssize_t sdebug_every_nth_store(struct device_driver * ddp, -				      const char * buf, size_t count) +static ssize_t every_nth_store(struct device_driver *ddp, const char *buf, +			       size_t count)  {          int nth; @@ -2996,15 +3058,14 @@ static ssize_t sdebug_every_nth_store(struct device_driver * ddp,  	}  	return -EINVAL;  } -DRIVER_ATTR(every_nth, S_IRUGO | S_IWUSR, sdebug_every_nth_show, -	    sdebug_every_nth_store); +static DRIVER_ATTR_RW(every_nth); -static ssize_t sdebug_max_luns_show(struct device_driver * ddp, char * buf) +static ssize_t max_luns_show(struct device_driver *ddp, char *buf)  {          return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_max_luns);  } -static ssize_t sdebug_max_luns_store(struct device_driver * ddp, -				     const char * buf, size_t count) +static ssize_t max_luns_store(struct device_driver *ddp, const char *buf, +			      size_t count)  {          int n; @@ -3015,15 +3076,14 @@ static ssize_t sdebug_max_luns_store(struct device_driver * ddp,  	}  	return -EINVAL;  } -DRIVER_ATTR(max_luns, S_IRUGO | S_IWUSR, sdebug_max_luns_show, -	    sdebug_max_luns_store); +static DRIVER_ATTR_RW(max_luns); -static ssize_t sdebug_max_queue_show(struct device_driver * ddp, char * buf) +static ssize_t max_queue_show(struct device_driver *ddp, char *buf)  {          return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_max_queue);  } -static ssize_t sdebug_max_queue_store(struct device_driver * ddp, -				      const char * buf, size_t count) +static ssize_t max_queue_store(struct device_driver *ddp, const char *buf, +			       size_t count)  {          int n; @@ -3034,27 +3094,26 @@ static ssize_t sdebug_max_queue_store(struct device_driver * ddp,  	}  	return -EINVAL;  } -DRIVER_ATTR(max_queue, S_IRUGO | S_IWUSR, sdebug_max_queue_show, -	    sdebug_max_queue_store); +static DRIVER_ATTR_RW(max_queue); -static ssize_t sdebug_no_uld_show(struct device_driver * ddp, char * buf) +static ssize_t no_uld_show(struct device_driver *ddp, char *buf)  {          return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_no_uld);  } -DRIVER_ATTR(no_uld, S_IRUGO, sdebug_no_uld_show, NULL); +static DRIVER_ATTR_RO(no_uld); -static ssize_t sdebug_scsi_level_show(struct device_driver * ddp, char * buf) +static ssize_t scsi_level_show(struct device_driver *ddp, char *buf)  {          return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_scsi_level);  } -DRIVER_ATTR(scsi_level, S_IRUGO, sdebug_scsi_level_show, NULL); +static DRIVER_ATTR_RO(scsi_level); -static ssize_t sdebug_virtual_gb_show(struct device_driver * ddp, char * buf) +static ssize_t virtual_gb_show(struct device_driver *ddp, char *buf)  {          return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_virtual_gb);  } -static ssize_t sdebug_virtual_gb_store(struct device_driver * ddp, -				       const char * buf, size_t count) +static ssize_t virtual_gb_store(struct device_driver *ddp, const char *buf, +				size_t count)  {          int n; @@ -3067,16 +3126,15 @@ static ssize_t sdebug_virtual_gb_store(struct device_driver * ddp,  	}  	return -EINVAL;  } -DRIVER_ATTR(virtual_gb, S_IRUGO | S_IWUSR, sdebug_virtual_gb_show, -	    sdebug_virtual_gb_store); +static DRIVER_ATTR_RW(virtual_gb); -static ssize_t sdebug_add_host_show(struct device_driver * ddp, char * buf) +static ssize_t add_host_show(struct device_driver *ddp, char *buf)  {          return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_add_host);  } -static ssize_t sdebug_add_host_store(struct device_driver * ddp, -				     const char * buf, size_t count) +static ssize_t add_host_store(struct device_driver *ddp, const char *buf, +			      size_t count)  {  	int delta_hosts; @@ -3093,16 +3151,14 @@ static ssize_t sdebug_add_host_store(struct device_driver * ddp,  	}  	return count;  } -DRIVER_ATTR(add_host, S_IRUGO | S_IWUSR, sdebug_add_host_show, -	    sdebug_add_host_store); +static DRIVER_ATTR_RW(add_host); -static ssize_t sdebug_vpd_use_hostno_show(struct device_driver * ddp, -					  char * buf) +static ssize_t vpd_use_hostno_show(struct device_driver *ddp, char *buf)  {  	return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_vpd_use_hostno);  } -static ssize_t sdebug_vpd_use_hostno_store(struct device_driver * ddp, -					   const char * buf, size_t count) +static ssize_t vpd_use_hostno_store(struct device_driver *ddp, const char *buf, +				    size_t count)  {  	int n; @@ -3112,44 +3168,43 @@ static ssize_t sdebug_vpd_use_hostno_store(struct device_driver * ddp,  	}  	return -EINVAL;  } -DRIVER_ATTR(vpd_use_hostno, S_IRUGO | S_IWUSR, sdebug_vpd_use_hostno_show, -	    sdebug_vpd_use_hostno_store); +static DRIVER_ATTR_RW(vpd_use_hostno); -static ssize_t sdebug_sector_size_show(struct device_driver * ddp, char * buf) +static ssize_t sector_size_show(struct device_driver *ddp, char *buf)  {  	return scnprintf(buf, PAGE_SIZE, "%u\n", scsi_debug_sector_size);  } -DRIVER_ATTR(sector_size, S_IRUGO, sdebug_sector_size_show, NULL); +static DRIVER_ATTR_RO(sector_size); -static ssize_t sdebug_dix_show(struct device_driver *ddp, char *buf) +static ssize_t dix_show(struct device_driver *ddp, char *buf)  {  	return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dix);  } -DRIVER_ATTR(dix, S_IRUGO, sdebug_dix_show, NULL); +static DRIVER_ATTR_RO(dix); -static ssize_t sdebug_dif_show(struct device_driver *ddp, char *buf) +static ssize_t dif_show(struct device_driver *ddp, char *buf)  {  	return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dif);  } -DRIVER_ATTR(dif, S_IRUGO, sdebug_dif_show, NULL); +static DRIVER_ATTR_RO(dif); -static ssize_t sdebug_guard_show(struct device_driver *ddp, char *buf) +static ssize_t guard_show(struct device_driver *ddp, char *buf)  { -	return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_guard); +	return scnprintf(buf, PAGE_SIZE, "%u\n", scsi_debug_guard);  } -DRIVER_ATTR(guard, S_IRUGO, sdebug_guard_show, NULL); +static DRIVER_ATTR_RO(guard); -static ssize_t sdebug_ato_show(struct device_driver *ddp, char *buf) +static ssize_t ato_show(struct device_driver *ddp, char *buf)  {  	return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_ato);  } -DRIVER_ATTR(ato, S_IRUGO, sdebug_ato_show, NULL); +static DRIVER_ATTR_RO(ato); -static ssize_t sdebug_map_show(struct device_driver *ddp, char *buf) +static ssize_t map_show(struct device_driver *ddp, char *buf)  {  	ssize_t count; -	if (scsi_debug_tpu == 0 && scsi_debug_tpws == 0) +	if (!scsi_debug_lbp())  		return scnprintf(buf, PAGE_SIZE, "0-%u\n",  				 sdebug_store_sectors); @@ -3160,73 +3215,62 @@ static ssize_t sdebug_map_show(struct device_driver *ddp, char *buf)  	return count;  } -DRIVER_ATTR(map, S_IRUGO, sdebug_map_show, NULL); +static DRIVER_ATTR_RO(map); +static ssize_t removable_show(struct device_driver *ddp, char *buf) +{ +	return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_removable ? 1 : 0); +} +static ssize_t removable_store(struct device_driver *ddp, const char *buf, +			       size_t count) +{ +	int n; + +	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { +		scsi_debug_removable = (n > 0); +		return count; +	} +	return -EINVAL; +} +static DRIVER_ATTR_RW(removable); -/* Note: The following function creates attribute files in the +/* Note: The following array creates attribute files in the     /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these     files (over those found in the /sys/module/scsi_debug/parameters     directory) is that auxiliary actions can be triggered when an attribute     is changed. For example see: sdebug_add_host_store() above.   */ -static int do_create_driverfs_files(void) -{ -	int ret; -	ret = driver_create_file(&sdebug_driverfs_driver, &driver_attr_add_host); -	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_delay); -	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb); -	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dsense); -	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_every_nth); -	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_fake_rw); -	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_max_luns); -	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_max_queue); -	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_no_lun_0); -	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_no_uld); -	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_parts); -	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_tgts); -	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_ptype); -	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_opts); -	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_scsi_level); -	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb); -	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno); -	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_sector_size); -	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dix); -	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dif); -	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_guard); -	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_ato); -	ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_map); -	return ret; -} +static struct attribute *sdebug_drv_attrs[] = { +	&driver_attr_delay.attr, +	&driver_attr_opts.attr, +	&driver_attr_ptype.attr, +	&driver_attr_dsense.attr, +	&driver_attr_fake_rw.attr, +	&driver_attr_no_lun_0.attr, +	&driver_attr_num_tgts.attr, +	&driver_attr_dev_size_mb.attr, +	&driver_attr_num_parts.attr, +	&driver_attr_every_nth.attr, +	&driver_attr_max_luns.attr, +	&driver_attr_max_queue.attr, +	&driver_attr_no_uld.attr, +	&driver_attr_scsi_level.attr, +	&driver_attr_virtual_gb.attr, +	&driver_attr_add_host.attr, +	&driver_attr_vpd_use_hostno.attr, +	&driver_attr_sector_size.attr, +	&driver_attr_dix.attr, +	&driver_attr_dif.attr, +	&driver_attr_guard.attr, +	&driver_attr_ato.attr, +	&driver_attr_map.attr, +	&driver_attr_removable.attr, +	NULL, +}; +ATTRIBUTE_GROUPS(sdebug_drv); -static void do_remove_driverfs_files(void) -{ -	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_map); -	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_ato); -	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_guard); -	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dif); -	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dix); -	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_sector_size); -	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno); -	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb); -	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_scsi_level); -	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_opts); -	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_ptype); -	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_tgts); -	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_parts); -	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_no_uld); -	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_no_lun_0); -	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_max_queue); -	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_max_luns); -	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_fake_rw); -	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_every_nth); -	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dsense); -	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb); -	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_delay); -	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_add_host); -} - -struct device *pseudo_primary; +static struct device *pseudo_primary;  static int __init scsi_debug_init(void)  { @@ -3314,7 +3358,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); @@ -3332,10 +3376,8 @@ static int __init scsi_debug_init(void)  		memset(dif_storep, 0xff, dif_size);  	} -	/* Thin Provisioning */ -	if (scsi_debug_tpu || scsi_debug_tpws) { -		unsigned int map_bytes; - +	/* Logical Block Provisioning */ +	if (scsi_debug_lbp()) {  		scsi_debug_unmap_max_blocks =  			clamp(scsi_debug_unmap_max_blocks, 0U, 0xffffffffU); @@ -3346,16 +3388,16 @@ static int __init scsi_debug_init(void)  			clamp(scsi_debug_unmap_granularity, 1U, 0xffffffffU);  		if (scsi_debug_unmap_alignment && -		    scsi_debug_unmap_granularity < scsi_debug_unmap_alignment) { +		    scsi_debug_unmap_granularity <= +		    scsi_debug_unmap_alignment) {  			printk(KERN_ERR -			       "%s: ERR: unmap_granularity < unmap_alignment\n", +			       "%s: ERR: unmap_granularity <= unmap_alignment\n",  			       __func__);  			return -EINVAL;  		} -		map_size = (sdebug_store_sectors / scsi_debug_unmap_granularity); -		map_bytes = map_size >> 3; -		map_storep = vmalloc(map_bytes); +		map_size = lba_to_map_index(sdebug_store_sectors - 1) + 1; +		map_storep = vmalloc(BITS_TO_LONGS(map_size) * sizeof(long));  		printk(KERN_INFO "scsi_debug_init: %lu provisioning blocks\n",  		       map_size); @@ -3366,7 +3408,7 @@ static int __init scsi_debug_init(void)  			goto free_vm;  		} -		memset(map_storep, 0x0, map_bytes); +		bitmap_zero(map_storep, map_size);  		/* Map first 1KB for partition table */  		if (scsi_debug_num_parts) @@ -3391,12 +3433,6 @@ static int __init scsi_debug_init(void)  			ret);  		goto bus_unreg;  	} -	ret = do_create_driverfs_files(); -	if (ret < 0) { -		printk(KERN_WARNING "scsi_debug: driver_create_file error: %d\n", -			ret); -		goto del_files; -	}  	init_all_queued(); @@ -3417,9 +3453,6 @@ static int __init scsi_debug_init(void)  	}  	return 0; -del_files: -	do_remove_driverfs_files(); -	driver_unregister(&sdebug_driverfs_driver);  bus_unreg:  	bus_unregister(&pseudo_lld_bus);  dev_unreg: @@ -3441,7 +3474,6 @@ static void __exit scsi_debug_exit(void)  	stop_all_queued();  	for (; k; k--)  		sdebug_remove_adapter(); -	do_remove_driverfs_files();  	driver_unregister(&sdebug_driverfs_driver);  	bus_unregister(&pseudo_lld_bus);  	root_device_unregister(pseudo_primary); @@ -3538,7 +3570,7 @@ static void sdebug_remove_adapter(void)  }  static -int scsi_debug_queuecommand(struct scsi_cmnd *SCpnt, done_funct_t done) +int scsi_debug_queuecommand_lck(struct scsi_cmnd *SCpnt, done_funct_t done)  {  	unsigned char *cmd = (unsigned char *) SCpnt->cmnd;  	int len, k; @@ -3552,6 +3584,7 @@ int scsi_debug_queuecommand(struct scsi_cmnd *SCpnt, done_funct_t done)  	int inj_transport = 0;  	int inj_dif = 0;  	int inj_dix = 0; +	int inj_short = 0;  	int delay_override = 0;  	int unmap = 0; @@ -3586,6 +3619,9 @@ int scsi_debug_queuecommand(struct scsi_cmnd *SCpnt, done_funct_t done)  			scsi_debug_every_nth = -1;  		if (SCSI_DEBUG_OPT_TIMEOUT & scsi_debug_opts)  			return 0; /* ignore command causing timeout */ +		else if (SCSI_DEBUG_OPT_MAC_TIMEOUT & scsi_debug_opts && +			 scsi_medium_access_command(SCpnt)) +			return 0; /* time out reads and writes */  		else if (SCSI_DEBUG_OPT_RECOVERED_ERR & scsi_debug_opts)  			inj_recovered = 1; /* to reads and writes below */  		else if (SCSI_DEBUG_OPT_TRANSPORT_ERR & scsi_debug_opts) @@ -3594,6 +3630,8 @@ int scsi_debug_queuecommand(struct scsi_cmnd *SCpnt, done_funct_t done)  			inj_dif = 1; /* to reads and writes below */  		else if (SCSI_DEBUG_OPT_DIX_ERR & scsi_debug_opts)  			inj_dix = 1; /* to reads and writes below */ +		else if (SCSI_DEBUG_OPT_SHORT_TRANSFER & scsi_debug_opts) +			inj_short = 1;  	}  	if (devip->wlun) { @@ -3663,7 +3701,7 @@ int scsi_debug_queuecommand(struct scsi_cmnd *SCpnt, done_funct_t done)  			errsts = resp_readcap16(SCpnt, devip);  		else if (cmd[1] == SAI_GET_LBA_STATUS) { -			if (scsi_debug_tpu == 0 && scsi_debug_tpws == 0) { +			if (scsi_debug_lbp() == 0) {  				mk_sense_buffer(devip, ILLEGAL_REQUEST,  						INVALID_COMMAND_OPCODE, 0);  				errsts = check_condition_result; @@ -3710,6 +3748,10 @@ read:  		if (scsi_debug_fake_rw)  			break;  		get_data_transfer_info(cmd, &lba, &num, &ei_lba); + +		if (inj_short) +			num /= 2; +  		errsts = resp_read(SCpnt, lba, num, devip, ei_lba);  		if (inj_recovered && (0 == errsts)) {  			mk_sense_buffer(devip, RECOVERED_ERROR, @@ -3774,8 +3816,10 @@ write:  		}  		break;  	case WRITE_SAME_16: +	case WRITE_SAME:  		if (cmd[1] & 0x8) { -			if (scsi_debug_tpws == 0) { +			if ((*cmd == WRITE_SAME_16 && scsi_debug_lbpws == 0) || +			    (*cmd == WRITE_SAME && scsi_debug_lbpws10 == 0)) {  				mk_sense_buffer(devip, ILLEGAL_REQUEST,  						INVALID_FIELD_IN_CDB, 0);  				errsts = check_condition_result; @@ -3784,8 +3828,6 @@ write:  		}  		if (errsts)  			break; -		/* fall through */ -	case WRITE_SAME:  		errsts = check_readiness(SCpnt, 0, devip);  		if (errsts)  			break; @@ -3797,7 +3839,7 @@ write:  		if (errsts)  			break; -		if (scsi_debug_unmap_max_desc == 0 || scsi_debug_tpu == 0) { +		if (scsi_debug_unmap_max_desc == 0 || scsi_debug_lbpu == 0) {  			mk_sense_buffer(devip, ILLEGAL_REQUEST,  					INVALID_COMMAND_OPCODE, 0);  			errsts = check_condition_result; @@ -3884,8 +3926,11 @@ write:  			     (delay_override ? 0 : scsi_debug_delay));  } +static DEF_SCSI_QCMD(scsi_debug_queuecommand) +  static struct scsi_host_template sdebug_driver_template = { -	.proc_info =		scsi_debug_proc_info, +	.show_info =		scsi_debug_show_info, +	.write_info =		scsi_debug_write_info,  	.proc_name =		sdebug_proc_name,  	.name =			"SCSI DEBUG",  	.info =			scsi_debug_info, @@ -3918,6 +3963,8 @@ static int sdebug_driver_probe(struct device * dev)  	sdbg_host = to_sdebug_host(dev);  	sdebug_driver_template.can_queue = scsi_debug_max_queue; +	if (scsi_debug_clustering) +		sdebug_driver_template.use_clustering = ENABLE_CLUSTERING;  	hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host));  	if (NULL == hpnt) {  		printk(KERN_ERR "%s: scsi_register failed\n", __func__); @@ -4025,4 +4072,5 @@ static struct bus_type pseudo_lld_bus = {  	.match = pseudo_lld_bus_match,  	.probe = sdebug_driver_probe,  	.remove = sdebug_driver_remove, +	.drv_groups = sdebug_drv_groups,  };  | 
