4076 lines · 119.0 KB · C
RawDownload
/* * vvvvvvvvvvvvvvvvvvvvvvv Original vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv *  Copyright (C) 1992  Eric Youngdale *  Simulate a host adapter with 2 disks attached.  Do a lot of checking *  to make sure that we are not getting blocks mixed up, and PANIC if *  anything out of the ordinary is seen. * ^^^^^^^^^^^^^^^^^^^^^^^ Original ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ * *  This version is more generic, simulating a variable number of disk *  (or disk like devices) sharing a common amount of RAM. To be more *  realistic, the simulated devices have the transport attributes of *  SAS disks. * * *  For documentation see http://sg.danny.cz/sg/sdebug26.html * *   D. Gilbert (dpg) work for Magneto-Optical device test [20010421] *   dpg: work for devfs large number of disks [20010809] *        forked for lk 2.5 series [20011216, 20020101] *        use vmalloc() more inquiry+mode_sense [20020302] *        add timers for delayed responses [20020721] *   Patrick Mansfield <patmans@us.ibm.com> max_luns+scsi_level [20021031] *   Mike Anderson <andmike@us.ibm.com> sysfs work [20021118] *   dpg: change style of boot options to "scsi_debug.num_tgts=2" and *        module options to "modprobe scsi_debug num_tgts=2" [20021221] */ #include <linux/module.h> #include <linux/kernel.h>#include <linux/errno.h>#include <linux/timer.h>#include <linux/slab.h>#include <linux/types.h>#include <linux/string.h>#include <linux/genhd.h>#include <linux/fs.h>#include <linux/init.h>#include <linux/proc_fs.h>#include <linux/vmalloc.h>#include <linux/moduleparam.h>#include <linux/scatterlist.h>#include <linux/blkdev.h>#include <linux/crc-t10dif.h> #include <net/checksum.h> #include <asm/unaligned.h> #include <scsi/scsi.h>#include <scsi/scsi_cmnd.h>#include <scsi/scsi_device.h>#include <scsi/scsi_host.h>#include <scsi/scsicam.h>#include <scsi/scsi_eh.h>#include <scsi/scsi_dbg.h> #include "sd.h"#include "scsi_logging.h" #define SCSI_DEBUG_VERSION "1.82"static const char * scsi_debug_version_date = "20100324"; /* Additional Sense Code (ASC) */#define NO_ADDITIONAL_SENSE 0x0#define LOGICAL_UNIT_NOT_READY 0x4#define UNRECOVERED_READ_ERR 0x11#define PARAMETER_LIST_LENGTH_ERR 0x1a#define INVALID_OPCODE 0x20#define ADDR_OUT_OF_RANGE 0x21#define INVALID_COMMAND_OPCODE 0x20#define INVALID_FIELD_IN_CDB 0x24#define INVALID_FIELD_IN_PARAM_LIST 0x26#define POWERON_RESET 0x29#define SAVING_PARAMS_UNSUP 0x39#define TRANSPORT_PROBLEM 0x4b#define THRESHOLD_EXCEEDED 0x5d#define LOW_POWER_COND_ON 0x5e /* Additional Sense Code Qualifier (ASCQ) */#define ACK_NAK_TO 0x3 #define SDEBUG_TAGGED_QUEUING 0 /* 0 | MSG_SIMPLE_TAG | MSG_ORDERED_TAG */ /* Default values for driver parameters */#define DEF_NUM_HOST   1#define DEF_NUM_TGTS   1#define DEF_MAX_LUNS   1/* 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_DIF 0#define DEF_DIX 0#define DEF_D_SENSE   0#define DEF_EVERY_NTH   0#define DEF_FAKE_RW	0#define DEF_GUARD 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_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_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#define SCSI_DEBUG_OPT_MEDIUM_ERR   2#define SCSI_DEBUG_OPT_TIMEOUT   4#define SCSI_DEBUG_OPT_RECOVERED_ERR   8#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/* 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 *     commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set. *   - a TRANSPORT_ERROR is simulated on successful read and write *     commands if SCSI_DEBUG_OPT_TRANSPORT_ERR is set. * * When "every_nth" < 0 then after "- 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 *     commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set. *   - a TRANSPORT_ERROR is simulated on successful read and write *     commands if SCSI_DEBUG_OPT_TRANSPORT_ERR is set. * This will continue until some other action occurs (e.g. the user * writing a new value (other than -1 or 1) to every_nth via sysfs). */ /* 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) */#define SAM2_LUN_ADDRESS_METHOD 0#define SAM2_WLUN_REPORT_LUNS 0xc101 /* Can queue up to this number of commands. Typically commands that * that have a non-zero delay are queued. */#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 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_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_physblk_exp = DEF_PHYSBLK_EXP;static int scsi_debug_ptype = DEF_PTYPE; /* SCSI peripheral type (0==disk) */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_vpd_use_hostno = DEF_VPD_USE_HOSTNO;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_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 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 */ /* old BIOS stuff, kernel may get rid of them but some mode sense pages   may still need them */static int sdebug_heads;		/* heads per disk */static int sdebug_cylinders_per;	/* cylinders per surface */static int sdebug_sectors_per;		/* sectors per cylinder */ #define SDEBUG_MAX_PARTS 4 #define SDEBUG_SENSE_LEN 32 #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 */	unsigned int channel;	unsigned int target;	unsigned int lun;	struct sdebug_host_info *sdbg_host;	unsigned int wlun;	char reset;	char stopped;	char used;}; struct sdebug_host_info {	struct list_head host_list;	struct Scsi_Host *shost;	struct device dev;	struct list_head dev_info_list;}; #define to_sdebug_host(d)	\	container_of(d, struct sdebug_host_info, dev) static LIST_HEAD(sdebug_host_list);static DEFINE_SPINLOCK(sdebug_host_list_lock); typedef void (* done_funct_t) (struct scsi_cmnd *); struct sdebug_queued_cmd {	int in_use;	struct timer_list cmnd_timer;	done_funct_t done_funct;	struct scsi_cmnd * a_cmnd;	int scsi_result;};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 void *map_storep;		/* provisioning map */ static unsigned long map_size;static int num_aborts = 0;static int num_dev_resets = 0;static int num_bus_resets = 0;static int num_host_resets = 0;static int dix_writes;static int dix_reads;static int dif_errors; static DEFINE_SPINLOCK(queued_arr_lock);static DEFINE_RWLOCK(atomic_rw); 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,}; static const int check_condition_result =		(DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION; static const int illegal_condition_result =	(DRIVER_SENSE << 24) | (DID_ABORT << 16) | SAM_STAT_CHECK_CONDITION; static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,				    0, 0, 0x2, 0x4b};static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,			           0, 0, 0x0, 0x0}; static int sdebug_add_adapter(void);static void sdebug_remove_adapter(void); static void sdebug_max_tgts_luns(void){	struct sdebug_host_info *sdbg_host;	struct Scsi_Host *hpnt; 	spin_lock(&sdebug_host_list_lock);	list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {		hpnt = sdbg_host->shost;		if ((hpnt->this_id >= 0) &&		    (scsi_debug_num_tgts > hpnt->this_id))			hpnt->max_id = scsi_debug_num_tgts + 1;		else			hpnt->max_id = scsi_debug_num_tgts;		/* scsi_debug_max_luns; */		hpnt->max_lun = SAM2_WLUN_REPORT_LUNS;	}	spin_unlock(&sdebug_host_list_lock);} static void mk_sense_buffer(struct sdebug_dev_info *devip, int key,			    int asc, int asq){	unsigned char *sbuff; 	sbuff = devip->sense_buff;	memset(sbuff, 0, SDEBUG_SENSE_LEN); 	scsi_build_sense_buffer(scsi_debug_dsense, sbuff, key, asc, asq); 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)		printk(KERN_INFO "scsi_debug:    [sense_key,asc,ascq]: "		      "[0x%x,0x%x,0x%x]\n", key, asc, asq);} static void get_data_transfer_info(unsigned char *cmd,				   unsigned long long *lba, unsigned int *num,				   u32 *ei_lba){	*ei_lba = 0; 	switch (*cmd) {	case VARIABLE_LENGTH_CMD:		*lba = (u64)cmd[19] | (u64)cmd[18] << 8 |			(u64)cmd[17] << 16 | (u64)cmd[16] << 24 |			(u64)cmd[15] << 32 | (u64)cmd[14] << 40 |			(u64)cmd[13] << 48 | (u64)cmd[12] << 56; 		*ei_lba = (u32)cmd[23] | (u32)cmd[22] << 8 |			(u32)cmd[21] << 16 | (u32)cmd[20] << 24; 		*num = (u32)cmd[31] | (u32)cmd[30] << 8 | (u32)cmd[29] << 16 |			(u32)cmd[28] << 24;		break; 	case WRITE_SAME_16:	case WRITE_16:	case READ_16:		*lba = (u64)cmd[9] | (u64)cmd[8] << 8 |			(u64)cmd[7] << 16 | (u64)cmd[6] << 24 |			(u64)cmd[5] << 32 | (u64)cmd[4] << 40 |			(u64)cmd[3] << 48 | (u64)cmd[2] << 56; 		*num = (u32)cmd[13] | (u32)cmd[12] << 8 | (u32)cmd[11] << 16 |			(u32)cmd[10] << 24;		break;	case WRITE_12:	case READ_12:		*lba = (u32)cmd[5] | (u32)cmd[4] << 8 | (u32)cmd[3] << 16 |			(u32)cmd[2] << 24; 		*num = (u32)cmd[9] | (u32)cmd[8] << 8 | (u32)cmd[7] << 16 |			(u32)cmd[6] << 24;		break;	case WRITE_SAME:	case WRITE_10:	case READ_10:	case XDWRITEREAD_10:		*lba = (u32)cmd[5] | (u32)cmd[4] << 8 |	(u32)cmd[3] << 16 |			(u32)cmd[2] << 24; 		*num = (u32)cmd[8] | (u32)cmd[7] << 8;		break;	case WRITE_6:	case READ_6:		*lba = (u32)cmd[3] | (u32)cmd[2] << 8 |			(u32)(cmd[1] & 0x1f) << 16;		*num = (0 == cmd[4]) ? 256 : cmd[4];		break;	default:		break;	}} static int scsi_debug_ioctl(struct scsi_device *dev, int cmd, void __user *arg){	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) {		printk(KERN_INFO "scsi_debug: ioctl: cmd=0x%x\n", cmd);	}	return -EINVAL;	/* return -ENOTTY; // correct return but upsets fdisk */} static int check_readiness(struct scsi_cmnd * SCpnt, int reset_only,			   struct sdebug_dev_info * devip){	if (devip->reset) {		if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)			printk(KERN_INFO "scsi_debug: Reporting Unit "			       "attention: power on reset\n");		devip->reset = 0;		mk_sense_buffer(devip, UNIT_ATTENTION, POWERON_RESET, 0);		return check_condition_result;	}	if ((0 == reset_only) && devip->stopped) {		if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)			printk(KERN_INFO "scsi_debug: Reporting Not "			       "ready: initializing command required\n");		mk_sense_buffer(devip, NOT_READY, LOGICAL_UNIT_NOT_READY,				0x2);		return check_condition_result;	}	return 0;} /* Returns 0 if ok else (DID_ERROR << 16). Sets scp->resid . */static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,				int arr_len){	int act_len;	struct scsi_data_buffer *sdb = scsi_in(scp); 	if (!sdb->length)		return 0;	if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_FROM_DEVICE))		return (DID_ERROR << 16); 	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; 	return 0;} /* Returns number of bytes fetched into 'arr' or -1 if error. */static int fetch_to_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,			       int arr_len){	if (!scsi_bufflen(scp))		return 0;	if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_TO_DEVICE))		return -1; 	return scsi_sg_copy_to_buffer(scp, arr, arr_len);}  static const char * inq_vendor_id = "Linux   ";static const char * inq_product_id = "scsi_debug      ";static const char * inq_product_rev = "0004"; static int inquiry_evpd_83(unsigned char * arr, int port_group_id,			   int target_dev_id, int dev_id_num,			   const char * dev_id_str,			   int dev_id_str_len){	int num, port_a;	char b[32]; 	port_a = target_dev_id + 1;	/* T10 vendor identifier field format (faked) */	arr[0] = 0x2;	/* ASCII */	arr[1] = 0x1;	arr[2] = 0x0;	memcpy(&arr[4], inq_vendor_id, 8);	memcpy(&arr[12], inq_product_id, 16);	memcpy(&arr[28], dev_id_str, dev_id_str_len);	num = 8 + 16 + dev_id_str_len;	arr[3] = num;	num += 4;	if (dev_id_num >= 0) {		/* NAA-5, Logical unit identifier (binary) */		arr[num++] = 0x1;	/* binary (not necessarily sas) */		arr[num++] = 0x3;	/* PIV=0, lu, naa */		arr[num++] = 0x0;		arr[num++] = 0x8;		arr[num++] = 0x53;  /* naa-5 ieee company id=0x333333 (fake) */		arr[num++] = 0x33;		arr[num++] = 0x33;		arr[num++] = 0x30;		arr[num++] = (dev_id_num >> 24);		arr[num++] = (dev_id_num >> 16) & 0xff;		arr[num++] = (dev_id_num >> 8) & 0xff;		arr[num++] = dev_id_num & 0xff;		/* Target relative port number */		arr[num++] = 0x61;	/* proto=sas, binary */

Lines 1–500 of 4076.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t