diff options
Diffstat (limited to 'drivers/scsi/scsi_debug.c')
| -rw-r--r-- | drivers/scsi/scsi_debug.c | 108 | 
1 files changed, 70 insertions, 38 deletions
diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index f6600bfb5bd..01d11a01ffb 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -94,6 +94,7 @@ static const char * scsi_debug_version_date = "20070104";  #define DEF_VIRTUAL_GB   0  #define DEF_FAKE_RW	0  #define DEF_VPD_USE_HOSTNO 1 +#define DEF_SECTOR_SIZE 512  /* bit mask values for scsi_debug_opts */  #define SCSI_DEBUG_OPT_NOISE   1 @@ -142,6 +143,7 @@ static int scsi_debug_no_lun_0 = DEF_NO_LUN_0;  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_cmnd_count = 0; @@ -157,11 +159,6 @@ static int sdebug_heads;		/* heads per disk */  static int sdebug_cylinders_per;	/* cylinders per surface */  static int sdebug_sectors_per;		/* sectors per cylinder */ -/* default sector size is 512 bytes, 2**9 bytes */ -#define POW2_SECT_SIZE 9 -#define SECT_SIZE (1 << POW2_SECT_SIZE) -#define SECT_SIZE_PER(TGT) SECT_SIZE -  #define SDEBUG_MAX_PARTS 4  #define SDEBUG_SENSE_LEN 32 @@ -646,6 +643,14 @@ static int inquiry_evpd_b0(unsigned char * arr)  	return sizeof(vpdb0_data);  } +static int inquiry_evpd_b1(unsigned char *arr) +{ +	memset(arr, 0, 0x3c); +	arr[0] = 0; +	arr[1] = 1; + +	return 0x3c; +}  #define SDEBUG_LONG_INQ_SZ 96  #define SDEBUG_MAX_INQ_ARR_SZ 584 @@ -701,6 +706,7 @@ static int resp_inquiry(struct scsi_cmnd * scp, int target,  			arr[n++] = 0x88;  /* SCSI ports */  			arr[n++] = 0x89;  /* ATA information */  			arr[n++] = 0xb0;  /* Block limits (SBC) */ +			arr[n++] = 0xb1;  /* Block characteristics (SBC) */  			arr[3] = n - 4;	  /* number of supported VPD pages */  		} else if (0x80 == cmd[2]) { /* unit serial number */  			arr[1] = cmd[2];	/*sanity */ @@ -740,6 +746,9 @@ static int resp_inquiry(struct scsi_cmnd * scp, int target,  		} else if (0xb0 == cmd[2]) { /* Block limits (SBC) */  			arr[1] = cmd[2];        /*sanity */  			arr[3] = inquiry_evpd_b0(&arr[4]); +		} else if (0xb1 == cmd[2]) { /* Block characteristics (SBC) */ +			arr[1] = cmd[2];        /*sanity */ +			arr[3] = inquiry_evpd_b1(&arr[4]);  		} else {  			/* Illegal request, invalid field in cdb */  			mk_sense_buffer(devip, ILLEGAL_REQUEST, @@ -878,8 +887,8 @@ static int resp_readcap(struct scsi_cmnd * scp,  		arr[2] = 0xff;  		arr[3] = 0xff;  	} -	arr[6] = (SECT_SIZE_PER(target) >> 8) & 0xff; -	arr[7] = SECT_SIZE_PER(target) & 0xff; +	arr[6] = (scsi_debug_sector_size >> 8) & 0xff; +	arr[7] = scsi_debug_sector_size & 0xff;  	return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ);  } @@ -902,10 +911,10 @@ static int resp_readcap16(struct scsi_cmnd * scp,  	capac = sdebug_capacity - 1;  	for (k = 0; k < 8; ++k, capac >>= 8)  		arr[7 - k] = capac & 0xff; -	arr[8] = (SECT_SIZE_PER(target) >> 24) & 0xff; -	arr[9] = (SECT_SIZE_PER(target) >> 16) & 0xff; -	arr[10] = (SECT_SIZE_PER(target) >> 8) & 0xff; -	arr[11] = SECT_SIZE_PER(target) & 0xff; +	arr[8] = (scsi_debug_sector_size >> 24) & 0xff; +	arr[9] = (scsi_debug_sector_size >> 16) & 0xff; +	arr[10] = (scsi_debug_sector_size >> 8) & 0xff; +	arr[11] = scsi_debug_sector_size & 0xff;  	return fill_from_dev_buffer(scp, arr,  				    min(alloc_len, SDEBUG_READCAP16_ARR_SZ));  } @@ -1019,20 +1028,20 @@ static int resp_disconnect_pg(unsigned char * p, int pcontrol, int target)  static int resp_format_pg(unsigned char * p, int pcontrol, int target)  {       /* Format device page for mode_sense */ -        unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0, -                                     0, 0, 0, 0, 0, 0, 0, 0, -                                     0, 0, 0, 0, 0x40, 0, 0, 0}; +	unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0, +				     0, 0, 0, 0, 0, 0, 0, 0, +				     0, 0, 0, 0, 0x40, 0, 0, 0}; -        memcpy(p, format_pg, sizeof(format_pg)); -        p[10] = (sdebug_sectors_per >> 8) & 0xff; -        p[11] = sdebug_sectors_per & 0xff; -        p[12] = (SECT_SIZE >> 8) & 0xff; -        p[13] = SECT_SIZE & 0xff; -        if (DEV_REMOVEABLE(target)) -                p[20] |= 0x20; /* should agree with INQUIRY */ -        if (1 == pcontrol) -                memset(p + 2, 0, sizeof(format_pg) - 2); -        return sizeof(format_pg); +	memcpy(p, format_pg, sizeof(format_pg)); +	p[10] = (sdebug_sectors_per >> 8) & 0xff; +	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)) +		p[20] |= 0x20; /* should agree with INQUIRY */ +	if (1 == pcontrol) +		memset(p + 2, 0, sizeof(format_pg) - 2); +	return sizeof(format_pg);  }  static int resp_caching_pg(unsigned char * p, int pcontrol, int target) @@ -1206,8 +1215,8 @@ static int resp_mode_sense(struct scsi_cmnd * scp, int target,  			ap[2] = (sdebug_capacity >> 8) & 0xff;  			ap[3] = sdebug_capacity & 0xff;  		} -        	ap[6] = (SECT_SIZE_PER(target) >> 8) & 0xff; -        	ap[7] = SECT_SIZE_PER(target) & 0xff; +		ap[6] = (scsi_debug_sector_size >> 8) & 0xff; +		ap[7] = scsi_debug_sector_size & 0xff;  		offset += bd_len;  		ap = arr + offset;  	} else if (16 == bd_len) { @@ -1215,10 +1224,10 @@ static int resp_mode_sense(struct scsi_cmnd * scp, int target,          	for (k = 0; k < 8; ++k, capac >>= 8)                  	ap[7 - k] = capac & 0xff; -        	ap[12] = (SECT_SIZE_PER(target) >> 24) & 0xff; -        	ap[13] = (SECT_SIZE_PER(target) >> 16) & 0xff; -        	ap[14] = (SECT_SIZE_PER(target) >> 8) & 0xff; -        	ap[15] = SECT_SIZE_PER(target) & 0xff; +		ap[12] = (scsi_debug_sector_size >> 24) & 0xff; +		ap[13] = (scsi_debug_sector_size >> 16) & 0xff; +		ap[14] = (scsi_debug_sector_size >> 8) & 0xff; +		ap[15] = scsi_debug_sector_size & 0xff;  		offset += bd_len;  		ap = arr + offset;  	} @@ -1519,10 +1528,10 @@ static int do_device_access(struct scsi_cmnd *scmd,  	if (block + num > sdebug_store_sectors)  		rest = block + num - sdebug_store_sectors; -	ret = func(scmd, fake_storep + (block * SECT_SIZE), -		   (num - rest) * SECT_SIZE); +	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 * SECT_SIZE); +		ret = func(scmd, fake_storep, rest * scsi_debug_sector_size);  	return ret;  } @@ -1575,10 +1584,10 @@ static int resp_write(struct scsi_cmnd *SCpnt, unsigned long long lba,  	write_unlock_irqrestore(&atomic_rw, iflags);  	if (-1 == ret)  		return (DID_ERROR << 16); -	else if ((ret < (num * SECT_SIZE)) && +	else if ((ret < (num * scsi_debug_sector_size)) &&  		 (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))  		printk(KERN_INFO "scsi_debug: write: cdb indicated=%u, " -		       " IO sent=%d bytes\n", num * SECT_SIZE, ret); +		       " IO sent=%d bytes\n", num * scsi_debug_sector_size, ret);  	return 0;  } @@ -2085,6 +2094,7 @@ 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_AUTHOR("Eric Youngdale + Douglas Gilbert");  MODULE_DESCRIPTION("SCSI debug adapter driver"); @@ -2106,6 +2116,7 @@ MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");  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, "hardware sector size in bytes (def=512)");  static char sdebug_info[256]; @@ -2158,8 +2169,9 @@ static int scsi_debug_proc_info(struct Scsi_Host *host, char *buffer, char **sta  	    scsi_debug_dev_size_mb, scsi_debug_opts, scsi_debug_every_nth,  	    scsi_debug_cmnd_count, scsi_debug_delay,  	    scsi_debug_max_luns, scsi_debug_scsi_level, -	    SECT_SIZE, sdebug_cylinders_per, sdebug_heads, sdebug_sectors_per, -	    num_aborts, num_dev_resets, num_bus_resets, num_host_resets); +	    scsi_debug_sector_size, sdebug_cylinders_per, sdebug_heads, +	    sdebug_sectors_per, num_aborts, num_dev_resets, num_bus_resets, +	    num_host_resets);  	if (pos < offset) {  		len = 0;  		begin = pos; @@ -2434,6 +2446,12 @@ static ssize_t sdebug_vpd_use_hostno_store(struct device_driver * ddp,  DRIVER_ATTR(vpd_use_hostno, S_IRUGO | S_IWUSR, sdebug_vpd_use_hostno_show,  	    sdebug_vpd_use_hostno_store); +static ssize_t sdebug_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); +  /* Note: The following function 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 @@ -2459,11 +2477,13 @@ static int do_create_driverfs_files(void)  	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);  	return ret;  }  static void do_remove_driverfs_files(void)  { +	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); @@ -2499,10 +2519,22 @@ static int __init scsi_debug_init(void)  	int k;  	int ret; +	switch (scsi_debug_sector_size) { +	case  512: +	case 1024: +	case 2048: +	case 4096: +		break; +	default: +		printk(KERN_ERR "scsi_debug_init: invalid sector_size %u\n", +		       scsi_debug_sector_size); +		return -EINVAL; +	} +  	if (scsi_debug_dev_size_mb < 1)  		scsi_debug_dev_size_mb = 1;  /* force minimum 1 MB ramdisk */  	sz = (unsigned long)scsi_debug_dev_size_mb * 1048576; -	sdebug_store_sectors = sz / SECT_SIZE; +	sdebug_store_sectors = sz / scsi_debug_sector_size;  	sdebug_capacity = get_sdebug_capacity();  	/* play around with geometry, don't waste too much on track 0 */  |