scsi_debug.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,869 行 · 第 1/4 页

C
1,869
字号
static int scsi_debug_slave_configure(struct scsi_device * sdp){	struct sdebug_dev_info * devip;	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)		printk(KERN_INFO "scsi_debug: slave_configure <%u %u %u %u>\n",		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);	if (sdp->host->max_cmd_len != SCSI_DEBUG_MAX_CMD_LEN)		sdp->host->max_cmd_len = SCSI_DEBUG_MAX_CMD_LEN;	devip = devInfoReg(sdp);	sdp->hostdata = devip;	if (sdp->host->cmd_per_lun)		scsi_adjust_queue_depth(sdp, SDEBUG_TAGGED_QUEUING,					sdp->host->cmd_per_lun);	return 0;}static void scsi_debug_slave_destroy(struct scsi_device * sdp){	struct sdebug_dev_info * devip =				(struct sdebug_dev_info *)sdp->hostdata;	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)		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 */		devip->used = 0;		sdp->hostdata = NULL;	}}static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev){	struct sdebug_host_info * sdbg_host;	struct sdebug_dev_info * open_devip = NULL;	struct sdebug_dev_info * devip =			(struct sdebug_dev_info *)sdev->hostdata;	if (devip)		return devip;	sdbg_host = *(struct sdebug_host_info **) sdev->host->hostdata;        if(! sdbg_host) {                printk(KERN_ERR "Host info NULL\n");		return NULL;        }	list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) {		if ((devip->used) && (devip->channel == sdev->channel) &&                    (devip->target == sdev->id) &&                    (devip->lun == sdev->lun))                        return devip;		else {			if ((!devip->used) && (!open_devip))				open_devip = devip;		}	}	if (NULL == open_devip) { /* try and make a new one */		open_devip = kmalloc(sizeof(*open_devip),GFP_KERNEL);		if (NULL == open_devip) {			printk(KERN_ERR "%s: out of memory at line %d\n",				__FUNCTION__, __LINE__);			return NULL;		}		memset(open_devip, 0, sizeof(*open_devip));		open_devip->sdbg_host = sdbg_host;		list_add_tail(&open_devip->dev_list,		&sdbg_host->dev_info_list);	}        if (open_devip) {		open_devip->channel = sdev->channel;		open_devip->target = sdev->id;		open_devip->lun = sdev->lun;		open_devip->sdbg_host = sdbg_host;		open_devip->reset = 1;		open_devip->used = 1;		memset(open_devip->sense_buff, 0, SDEBUG_SENSE_LEN);		open_devip->sense_buff[0] = 0x70;		return open_devip;        }        return NULL;}static void mk_sense_buffer(struct sdebug_dev_info * devip, int key,			    int asc, int asq, int inbandLen){	unsigned char * sbuff;	sbuff = devip->sense_buff;	memset(sbuff, 0, SDEBUG_SENSE_LEN);	if (inbandLen > SDEBUG_SENSE_LEN)		inbandLen = SDEBUG_SENSE_LEN;	sbuff[0] = 0x70;	sbuff[2] = key;	sbuff[7] = (inbandLen > 7) ? (inbandLen - 8) : 0;	sbuff[12] = asc;	sbuff[13] = asq;}static int scsi_debug_abort(struct scsi_cmnd * SCpnt){	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)		printk(KERN_INFO "scsi_debug: abort\n");	++num_aborts;	stop_queued_cmnd(SCpnt);	return SUCCESS;}static int scsi_debug_biosparam(struct scsi_device *sdev,		struct block_device * bdev, sector_t capacity, int *info){	int res;	unsigned char *buf;	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)		printk(KERN_INFO "scsi_debug: biosparam\n");	buf = scsi_bios_ptable(bdev);	if (buf) {		res = scsi_partsize(buf, capacity,				    &info[2], &info[0], &info[1]);		kfree(buf);		if (! res)			return res;	}	info[0] = sdebug_heads;	info[1] = sdebug_sectors_per;	info[2] = sdebug_cylinders_per;	return 0;}static int scsi_debug_device_reset(struct scsi_cmnd * SCpnt){	struct sdebug_dev_info * devip;	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)		printk(KERN_INFO "scsi_debug: device_reset\n");	++num_dev_resets;	if (SCpnt) {		devip = devInfoReg(SCpnt->device);		if (devip)			devip->reset = 1;	}	return SUCCESS;}static int scsi_debug_bus_reset(struct scsi_cmnd * SCpnt){	struct sdebug_host_info *sdbg_host;        struct sdebug_dev_info * dev_info;        struct scsi_device * sdp;        struct Scsi_Host * hp;	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)		printk(KERN_INFO "scsi_debug: bus_reset\n");	++num_bus_resets;	if (SCpnt && ((sdp = SCpnt->device)) && ((hp = sdp->host))) {		sdbg_host = *(struct sdebug_host_info **) hp->hostdata;		if (sdbg_host) {			list_for_each_entry(dev_info,                                            &sdbg_host->dev_info_list,                                            dev_list)				dev_info->reset = 1;		}	}	return SUCCESS;}static int scsi_debug_host_reset(struct scsi_cmnd * SCpnt){	struct sdebug_host_info * sdbg_host;        struct sdebug_dev_info * dev_info;	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)		printk(KERN_INFO "scsi_debug: host_reset\n");	++num_host_resets;        spin_lock(&sdebug_host_list_lock);        list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {                list_for_each_entry(dev_info, &sdbg_host->dev_info_list,                                    dev_list)                        dev_info->reset = 1;        }        spin_unlock(&sdebug_host_list_lock);	stop_all_queued();	return SUCCESS;}/* Returns 1 if found 'cmnd' and deleted its timer. else returns 0 */static int stop_queued_cmnd(struct scsi_cmnd * cmnd){	unsigned long iflags;	int k;	struct sdebug_queued_cmd * sqcp;	spin_lock_irqsave(&queued_arr_lock, iflags);	for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {		sqcp = &queued_arr[k];		if (sqcp->in_use && (cmnd == sqcp->a_cmnd)) {			del_timer_sync(&sqcp->cmnd_timer);			sqcp->in_use = 0;			sqcp->a_cmnd = NULL;			break;		}	}	spin_unlock_irqrestore(&queued_arr_lock, iflags);	return (k < SCSI_DEBUG_CANQUEUE) ? 1 : 0;}/* Deletes (stops) timers of all queued commands */static void stop_all_queued(void){	unsigned long iflags;	int k;	struct sdebug_queued_cmd * sqcp;	spin_lock_irqsave(&queued_arr_lock, iflags);	for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {		sqcp = &queued_arr[k];		if (sqcp->in_use && sqcp->a_cmnd) {			del_timer_sync(&sqcp->cmnd_timer);			sqcp->in_use = 0;			sqcp->a_cmnd = NULL;		}	}	spin_unlock_irqrestore(&queued_arr_lock, iflags);}/* Initializes timers in queued array */static void __init init_all_queued(void){	unsigned long iflags;	int k;	struct sdebug_queued_cmd * sqcp;	spin_lock_irqsave(&queued_arr_lock, iflags);	for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {		sqcp = &queued_arr[k];		init_timer(&sqcp->cmnd_timer);		sqcp->in_use = 0;		sqcp->a_cmnd = NULL;	}	spin_unlock_irqrestore(&queued_arr_lock, iflags);}static void __init sdebug_build_parts(unsigned char * ramp){	struct partition * pp;	int starts[SDEBUG_MAX_PARTS + 2];	int sectors_per_part, num_sectors, k;	int heads_by_sects, start_sec, end_sec;	/* assume partition table already zeroed */	if ((scsi_debug_num_parts < 1) || (sdebug_store_size < 1048576))		return;	if (scsi_debug_num_parts > SDEBUG_MAX_PARTS) {		scsi_debug_num_parts = SDEBUG_MAX_PARTS;		printk(KERN_WARNING "scsi_debug:build_parts: reducing "				    "partitions to %d\n", SDEBUG_MAX_PARTS);	}	num_sectors = (int)(sdebug_store_size / SECT_SIZE);	sectors_per_part = (num_sectors - sdebug_sectors_per)			   / scsi_debug_num_parts;	heads_by_sects = sdebug_heads * sdebug_sectors_per;        starts[0] = sdebug_sectors_per;	for (k = 1; k < scsi_debug_num_parts; ++k)		starts[k] = ((k * sectors_per_part) / heads_by_sects)			    * heads_by_sects;	starts[scsi_debug_num_parts] = num_sectors;	starts[scsi_debug_num_parts + 1] = 0;	ramp[510] = 0x55;	/* magic partition markings */	ramp[511] = 0xAA;	pp = (struct partition *)(ramp + 0x1be);	for (k = 0; starts[k + 1]; ++k, ++pp) {		start_sec = starts[k];		end_sec = starts[k + 1] - 1;		pp->boot_ind = 0;		pp->cyl = start_sec / heads_by_sects;		pp->head = (start_sec - (pp->cyl * heads_by_sects))			   / sdebug_sectors_per;		pp->sector = (start_sec % sdebug_sectors_per) + 1;		pp->end_cyl = end_sec / heads_by_sects;		pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects))			       / 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->sys_ind = 0x83;	/* plain Linux partition */	}}static int schedule_resp(struct scsi_cmnd * cmnd,			 struct sdebug_dev_info * devip,			 done_funct_t done, int scsi_result, int delta_jiff){	int k, num;	if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmnd) {		printk(KERN_INFO "scsi_debug: cmd ");		for (k = 0, num = cmnd->cmd_len; k < num; ++k)			printk("%02x ", (int)cmnd->cmnd[k]);		printk("\n");		if (scsi_result) {			struct scsi_device * sdp = cmnd->device;			printk(KERN_INFO "scsi_debug: ... <%u %u %u %u> "			       "non-zero result=0x%x\n", sdp->host->host_no,			       sdp->channel, sdp->id, sdp->lun, scsi_result);		}	}	if (cmnd && devip) {		/* simulate autosense by this driver */		if (SAM_STAT_CHECK_CONDITION == (scsi_result & 0xff))			memcpy(cmnd->sense_buffer, devip->sense_buff,			       (SCSI_SENSE_BUFFERSIZE > SDEBUG_SENSE_LEN) ?			       SDEBUG_SENSE_LEN : SCSI_SENSE_BUFFERSIZE);	}	if (delta_jiff <= 0) {		if (cmnd)			cmnd->result = scsi_result;		if (done)			done(cmnd);		return 0;	} else {		unsigned long iflags;		int k;		struct sdebug_queued_cmd * sqcp = NULL;		spin_lock_irqsave(&queued_arr_lock, iflags);		for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {			sqcp = &queued_arr[k];			if (! sqcp->in_use)				break;		}		if (k >= SCSI_DEBUG_CANQUEUE) {			spin_unlock_irqrestore(&queued_arr_lock, iflags);			printk(KERN_WARNING "scsi_debug: can_queue exceeded\n");			return 1;	/* report busy to mid level */		}		sqcp->in_use = 1;		sqcp->a_cmnd = cmnd;		sqcp->scsi_result = scsi_result;		sqcp->done_funct = done;		sqcp->cmnd_timer.function = timer_intr_handler;		sqcp->cmnd_timer.data = k;		sqcp->cmnd_timer.expires = jiffies + delta_jiff;		add_timer(&sqcp->cmnd_timer);		spin_unlock_irqrestore(&queued_arr_lock, iflags);		if (cmnd)			cmnd->result = 0;		return 0;	}}/* Set 'perm' (4th argument) to 0 to disable module_param's definition * of sysfs parameters (which module_param doesn't yet support). * Sysfs parameters defined explicitly below. */module_param_named(add_host, scsi_debug_add_host, int, 0); /* perm=0644 */module_param_named(delay, scsi_debug_delay, int, 0); /* perm=0644 */module_param_named(dev_size_mb, scsi_debug_dev_size_mb, int, 0);module_param_named(every_nth, scsi_debug_every_nth, int, 0);module_param_named(max_luns, scsi_debug_max_luns, int, 0);module_param_named(num_parts, scsi_debug_num_parts, int, 0);module_param_named(num_tgts, scsi_debug_num_tgts, int, 0);module_param_named(opts, scsi_debug_opts, int, 0); /* perm=0644 */module_param_named(ptype, scsi_debug_ptype, int, 0);module_param_named(scsi_level, scsi_debug_scsi_level, int, 0);MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");MODULE_DESCRIPTION("SCSI debug adapter driver");MODULE_LICENSE("GPL");MODULE_VERSION(SCSI_DEBUG_VERSION);MODULE_PARM_DESC(add_host, "0..127 hosts allowed(def=1)");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");MODULE_PARM_DESC(every_nth, "timeout every nth command(def=100)");MODULE_PARM_DESC(max_luns, "number of SCSI LUNs per target to simulate");MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");MODULE_PARM_DESC(num_tgts, "number of SCSI targets per host to simulate");MODULE_PARM_DESC(opts, "1->noise, 2->medium_error, 4->...");MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");MODULE_PARM_DESC(scsi_level, "SCSI level to simulate");static char sdebug_info[256];static const char * scsi_debug_info(struct Scsi_Host * shp){	sprintf(sdebug_info, "scsi_debug, version %s [%s], "		"dev_size_mb=%d, opts=0x%x", SCSI_DEBUG_VERSION,		scsi_debug_version_date, scsi_debug_dev_size_mb,		scsi_debug_opts);	return sdebug_info;}/* 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){	int len, pos, begin;	int orig_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", &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 "	    "%s [%s]\n"	    "num_tgts=%d, shared (ram) size=%d MB, opts=0x%x, "	    "every_nth=%d(curr:%d)\n"	    "delay=%d, max_luns=%d, scsi_level=%d\n"	    "sector_size=%d bytes, cylinders=%d, heads=%d, sectors=%d\n"	    "number of aborts=%d, device_reset=%d, bus_resets=%d, "	    "host_resets=%d\n",	    SCSI_DEBUG_VERSION, scsi_debug_version_date, scsi_debug_num_tgts,	    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);	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;}static ssize_t sdebug_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){        int delay;	char work[20];        if (1 == sscanf(buf, "%10s", work)) {		if ((1 == sscanf(work, "%d", &delay)) && (delay >= 0)) {			scsi_debug_delay = delay;			return count;		}	}	return -EINVAL;

⌨️ 快捷键说明

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