scsi_debug.c

来自「linux 内核源代码」· C语言 代码 · 共 2,078 行 · 第 1/5 页

C
2,078
字号
/* * 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://www.torque.net/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/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 "scsi.h"#include <scsi/scsi_host.h>#include <scsi/scsicam.h>#include <linux/stat.h>#include "scsi_logging.h"#include "scsi_debug.h"#define SCSI_DEBUG_VERSION "1.81"static const char * scsi_debug_version_date = "20070104";/* 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_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_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_D_SENSE   0#define DEF_NO_LUN_0   0#define DEF_VIRTUAL_GB   0#define DEF_FAKE_RW	0#define DEF_VPD_USE_HOSTNO 1/* 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/* 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 *//* 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 0xc101static int scsi_debug_add_host = DEF_NUM_HOST;static int scsi_debug_delay = DEF_DELAY;static int scsi_debug_dev_size_mb = DEF_DEV_SIZE_MB;static int scsi_debug_every_nth = DEF_EVERY_NTH;static int scsi_debug_max_luns = DEF_MAX_LUNS;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_opts = DEF_OPTS;static int scsi_debug_scsi_level = DEF_SCSI_LEVEL;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_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_cmnd_count = 0;#define DEV_READONLY(TGT)      (0)#define DEV_REMOVEABLE(TGT)    (0)static unsigned int sdebug_store_size;	/* in bytes */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 *//* 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 32struct 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 struct scsi_host_template sdebug_driver_template = {	.proc_info =		scsi_debug_proc_info,	.name =			"SCSI DEBUG",	.info =			scsi_debug_info,	.slave_alloc =		scsi_debug_slave_alloc,	.slave_configure =	scsi_debug_slave_configure,	.slave_destroy =	scsi_debug_slave_destroy,	.ioctl =		scsi_debug_ioctl,	.queuecommand =		scsi_debug_queuecommand,	.eh_abort_handler =	scsi_debug_abort,	.eh_bus_reset_handler = scsi_debug_bus_reset,	.eh_device_reset_handler = scsi_debug_device_reset,	.eh_host_reset_handler = scsi_debug_host_reset,	.bios_param =		scsi_debug_biosparam,	.can_queue =		SCSI_DEBUG_CANQUEUE,	.this_id =		7,	.sg_tablesize =		256,	.cmd_per_lun =		16,	.max_sectors =		0xffff,	.unchecked_isa_dma = 	0,	.use_clustering = 	ENABLE_CLUSTERING,	.module =		THIS_MODULE,};static unsigned char * fake_storep;	/* ramdisk storage */static int num_aborts = 0;static int num_dev_resets = 0;static int num_bus_resets = 0;static int num_host_resets = 0;static DEFINE_SPINLOCK(queued_arr_lock);static DEFINE_RWLOCK(atomic_rw);static char sdebug_proc_name[] = "scsi_debug";static int sdebug_driver_probe(struct device *);static int sdebug_driver_remove(struct device *);static struct bus_type pseudo_lld_bus;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 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};/* function declarations */static int resp_inquiry(struct scsi_cmnd * SCpnt, int target,			struct sdebug_dev_info * devip);static int resp_requests(struct scsi_cmnd * SCpnt,			 struct sdebug_dev_info * devip);static int resp_start_stop(struct scsi_cmnd * scp,			   struct sdebug_dev_info * devip);static int resp_report_tgtpgs(struct scsi_cmnd * scp,			      struct sdebug_dev_info * devip);static int resp_readcap(struct scsi_cmnd * SCpnt,			struct sdebug_dev_info * devip);static int resp_readcap16(struct scsi_cmnd * SCpnt,			  struct sdebug_dev_info * devip);static int resp_mode_sense(struct scsi_cmnd * scp, int target,			   struct sdebug_dev_info * devip);static int resp_mode_select(struct scsi_cmnd * scp, int mselect6,			    struct sdebug_dev_info * devip);static int resp_log_sense(struct scsi_cmnd * scp,			  struct sdebug_dev_info * devip);static int resp_read(struct scsi_cmnd * SCpnt, unsigned long long lba,		     unsigned int num, struct sdebug_dev_info * devip);static int resp_write(struct scsi_cmnd * SCpnt, unsigned long long lba,		      unsigned int num, struct sdebug_dev_info * devip);static int resp_report_luns(struct scsi_cmnd * SCpnt,			    struct sdebug_dev_info * devip);static int fill_from_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr,                                int arr_len);static int fetch_to_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr,                               int max_arr_len);static void timer_intr_handler(unsigned long);static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev);static void mk_sense_buffer(struct sdebug_dev_info * devip, int key,			    int asc, int asq);static int check_readiness(struct scsi_cmnd * SCpnt, int reset_only,			   struct sdebug_dev_info * devip);static int schedule_resp(struct scsi_cmnd * cmnd,			 struct sdebug_dev_info * devip,			 done_funct_t done, int scsi_result, int delta_jiff);static void __init sdebug_build_parts(unsigned char * ramp);static void __init init_all_queued(void);static void stop_all_queued(void);static int stop_queued_cmnd(struct scsi_cmnd * cmnd);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);static int inquiry_evpd_88(unsigned char * arr, int target_dev_id);static int do_create_driverfs_files(void);static void do_remove_driverfs_files(void);static int sdebug_add_adapter(void);static void sdebug_remove_adapter(void);static void sdebug_max_tgts_luns(void);static struct device pseudo_primary;static struct bus_type pseudo_lld_bus;staticint scsi_debug_queuecommand(struct scsi_cmnd * SCpnt, done_funct_t done){	unsigned char *cmd = (unsigned char *) SCpnt->cmnd;	int len, k, j;	unsigned int num;	unsigned long long lba;	int errsts = 0;	int target = SCpnt->device->id;	struct sdebug_dev_info * devip = NULL;	int inj_recovered = 0;	int inj_transport = 0;	int delay_override = 0;	if (done == NULL)		return 0;	/* assume mid level reprocessing command */	SCpnt->resid = 0;	if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmd) {		printk(KERN_INFO "scsi_debug: cmd ");		for (k = 0, len = SCpnt->cmd_len; k < len; ++k)			printk("%02x ", (int)cmd[k]);		printk("\n");	}        if(target == sdebug_driver_template.this_id) {		printk(KERN_INFO "scsi_debug: initiator's id used as "		       "target!\n");		return schedule_resp(SCpnt, NULL, done,				     DID_NO_CONNECT << 16, 0);        }	if ((SCpnt->device->lun >= scsi_debug_max_luns) &&	    (SCpnt->device->lun != SAM2_WLUN_REPORT_LUNS))		return schedule_resp(SCpnt, NULL, done,				     DID_NO_CONNECT << 16, 0);	devip = devInfoReg(SCpnt->device);	if (NULL == devip)		return schedule_resp(SCpnt, NULL, done,				     DID_NO_CONNECT << 16, 0);        if ((scsi_debug_every_nth != 0) &&            (++scsi_debug_cmnd_count >= abs(scsi_debug_every_nth))) {                scsi_debug_cmnd_count = 0;		if (scsi_debug_every_nth < -1)			scsi_debug_every_nth = -1;		if (SCSI_DEBUG_OPT_TIMEOUT & scsi_debug_opts)			return 0; /* ignore command causing timeout */		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)			inj_transport = 1; /* to reads and writes below */        }	if (devip->wlun) {		switch (*cmd) {		case INQUIRY:		case REQUEST_SENSE:		case TEST_UNIT_READY:		case REPORT_LUNS:			break;  /* only allowable wlun commands */		default:			if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)				printk(KERN_INFO "scsi_debug: Opcode: 0x%x "				       "not supported for wlun\n", *cmd);			mk_sense_buffer(devip, ILLEGAL_REQUEST,					INVALID_OPCODE, 0);			errsts = check_condition_result;			return schedule_resp(SCpnt, devip, done, errsts,					     0);		}	}	switch (*cmd) {	case INQUIRY:     /* mandatory, ignore unit attention */		delay_override = 1;		errsts = resp_inquiry(SCpnt, target, devip);		break;	case REQUEST_SENSE:	/* mandatory, ignore unit attention */		delay_override = 1;		errsts = resp_requests(SCpnt, devip);		break;	case REZERO_UNIT:	/* actually this is REWIND for SSC */	case START_STOP:		errsts = resp_start_stop(SCpnt, devip);		break;	case ALLOW_MEDIUM_REMOVAL:		if ((errsts = check_readiness(SCpnt, 1, devip)))			break;		if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)			printk(KERN_INFO "scsi_debug: Medium removal %s\n",			        cmd[4] ? "inhibited" : "enabled");		break;	case SEND_DIAGNOSTIC:     /* mandatory */		errsts = check_readiness(SCpnt, 1, devip);		break;	case TEST_UNIT_READY:     /* mandatory */		delay_override = 1;		errsts = check_readiness(SCpnt, 0, devip);		break;        case RESERVE:		errsts = check_readiness(SCpnt, 1, devip);                break;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?