scsi_scan.c

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

C
1,906
字号
/* * scsi_scan.c * * Copyright (C) 2000 Eric Youngdale, * Copyright (C) 2002 Patrick Mansfield * * The general scanning/probing algorithm is as follows, exceptions are * made to it depending on device specific flags, compilation options, and * global variable (boot or module load time) settings. * * A specific LUN is scanned via an INQUIRY command; if the LUN has a * device attached, a scsi_device is allocated and setup for it. * * For every id of every channel on the given host: * * 	Scan LUN 0; if the target responds to LUN 0 (even if there is no * 	device or storage attached to LUN 0): * * 		If LUN 0 has a device attached, allocate and setup a * 		scsi_device for it. * * 		If target is SCSI-3 or up, issue a REPORT LUN, and scan * 		all of the LUNs returned by the REPORT LUN; else, * 		sequentially scan LUNs up until some maximum is reached, * 		or a LUN is seen that cannot have a device attached to it. */#include <linux/module.h>#include <linux/moduleparam.h>#include <linux/init.h>#include <linux/blkdev.h>#include <linux/delay.h>#include <linux/kthread.h>#include <linux/spinlock.h>#include <scsi/scsi.h>#include <scsi/scsi_cmnd.h>#include <scsi/scsi_device.h>#include <scsi/scsi_driver.h>#include <scsi/scsi_devinfo.h>#include <scsi/scsi_host.h>#include <scsi/scsi_transport.h>#include <scsi/scsi_eh.h>#include "scsi_priv.h"#include "scsi_logging.h"#define ALLOC_FAILURE_MSG	KERN_ERR "%s: Allocation failure during" \	" SCSI scanning, some SCSI devices might not be configured\n"/* * Default timeout */#define SCSI_TIMEOUT (2*HZ)/* * Prefix values for the SCSI id's (stored in sysfs name field) */#define SCSI_UID_SER_NUM 'S'#define SCSI_UID_UNKNOWN 'Z'/* * Return values of some of the scanning functions. * * SCSI_SCAN_NO_RESPONSE: no valid response received from the target, this * includes allocation or general failures preventing IO from being sent. * * SCSI_SCAN_TARGET_PRESENT: target responded, but no device is available * on the given LUN. * * SCSI_SCAN_LUN_PRESENT: target responded, and a device is available on a * given LUN. */#define SCSI_SCAN_NO_RESPONSE		0#define SCSI_SCAN_TARGET_PRESENT	1#define SCSI_SCAN_LUN_PRESENT		2static const char *scsi_null_device_strs = "nullnullnullnull";#define MAX_SCSI_LUNS	512#ifdef CONFIG_SCSI_MULTI_LUNstatic unsigned int max_scsi_luns = MAX_SCSI_LUNS;#elsestatic unsigned int max_scsi_luns = 1;#endifmodule_param_named(max_luns, max_scsi_luns, uint, S_IRUGO|S_IWUSR);MODULE_PARM_DESC(max_luns,		 "last scsi LUN (should be between 1 and 2^32-1)");#ifdef CONFIG_SCSI_SCAN_ASYNC#define SCSI_SCAN_TYPE_DEFAULT "async"#else#define SCSI_SCAN_TYPE_DEFAULT "sync"#endifstatic char scsi_scan_type[6] = SCSI_SCAN_TYPE_DEFAULT;module_param_string(scan, scsi_scan_type, sizeof(scsi_scan_type), S_IRUGO);MODULE_PARM_DESC(scan, "sync, async or none");/* * max_scsi_report_luns: the maximum number of LUNS that will be * returned from the REPORT LUNS command. 8 times this value must * be allocated. In theory this could be up to an 8 byte value, but * in practice, the maximum number of LUNs suppored by any device * is about 16k. */static unsigned int max_scsi_report_luns = 511;module_param_named(max_report_luns, max_scsi_report_luns, uint, S_IRUGO|S_IWUSR);MODULE_PARM_DESC(max_report_luns,		 "REPORT LUNS maximum number of LUNS received (should be"		 " between 1 and 16384)");static unsigned int scsi_inq_timeout = SCSI_TIMEOUT/HZ+3;module_param_named(inq_timeout, scsi_inq_timeout, uint, S_IRUGO|S_IWUSR);MODULE_PARM_DESC(inq_timeout, 		 "Timeout (in seconds) waiting for devices to answer INQUIRY."		 " Default is 5. Some non-compliant devices need more.");/* This lock protects only this list */static DEFINE_SPINLOCK(async_scan_lock);static LIST_HEAD(scanning_hosts);struct async_scan_data {	struct list_head list;	struct Scsi_Host *shost;	struct completion prev_finished;};/** * scsi_complete_async_scans - Wait for asynchronous scans to complete * * When this function returns, any host which started scanning before * this function was called will have finished its scan.  Hosts which * started scanning after this function was called may or may not have * finished. */int scsi_complete_async_scans(void){	struct async_scan_data *data;	do {		if (list_empty(&scanning_hosts))			return 0;		/* If we can't get memory immediately, that's OK.  Just		 * sleep a little.  Even if we never get memory, the async		 * scans will finish eventually.		 */		data = kmalloc(sizeof(*data), GFP_KERNEL);		if (!data)			msleep(1);	} while (!data);	data->shost = NULL;	init_completion(&data->prev_finished);	spin_lock(&async_scan_lock);	/* Check that there's still somebody else on the list */	if (list_empty(&scanning_hosts))		goto done;	list_add_tail(&data->list, &scanning_hosts);	spin_unlock(&async_scan_lock);	printk(KERN_INFO "scsi: waiting for bus probes to complete ...\n");	wait_for_completion(&data->prev_finished);	spin_lock(&async_scan_lock);	list_del(&data->list);	if (!list_empty(&scanning_hosts)) {		struct async_scan_data *next = list_entry(scanning_hosts.next,				struct async_scan_data, list);		complete(&next->prev_finished);	} done:	spin_unlock(&async_scan_lock);	kfree(data);	return 0;}/* Only exported for the benefit of scsi_wait_scan */EXPORT_SYMBOL_GPL(scsi_complete_async_scans);#ifndef MODULE/* * For async scanning we need to wait for all the scans to complete before * trying to mount the root fs.  Otherwise non-modular drivers may not be ready * yet. */late_initcall(scsi_complete_async_scans);#endif/** * scsi_unlock_floptical - unlock device via a special MODE SENSE command * @sdev:	scsi device to send command to * @result:	area to store the result of the MODE SENSE * * Description: *     Send a vendor specific MODE SENSE (not a MODE SELECT) command. *     Called for BLIST_KEY devices. **/static void scsi_unlock_floptical(struct scsi_device *sdev,				  unsigned char *result){	unsigned char scsi_cmd[MAX_COMMAND_SIZE];	printk(KERN_NOTICE "scsi: unlocking floptical drive\n");	scsi_cmd[0] = MODE_SENSE;	scsi_cmd[1] = 0;	scsi_cmd[2] = 0x2e;	scsi_cmd[3] = 0;	scsi_cmd[4] = 0x2a;     /* size */	scsi_cmd[5] = 0;	scsi_execute_req(sdev, scsi_cmd, DMA_FROM_DEVICE, result, 0x2a, NULL,			 SCSI_TIMEOUT, 3);}/** * scsi_alloc_sdev - allocate and setup a scsi_Device * * Description: *     Allocate, initialize for io, and return a pointer to a scsi_Device. *     Stores the @shost, @channel, @id, and @lun in the scsi_Device, and *     adds scsi_Device to the appropriate list. * * Return value: *     scsi_Device pointer, or NULL on failure. **/static struct scsi_device *scsi_alloc_sdev(struct scsi_target *starget,					   unsigned int lun, void *hostdata){	struct scsi_device *sdev;	int display_failure_msg = 1, ret;	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);	extern void scsi_evt_thread(struct work_struct *work);	sdev = kzalloc(sizeof(*sdev) + shost->transportt->device_size,		       GFP_ATOMIC);	if (!sdev)		goto out;	sdev->vendor = scsi_null_device_strs;	sdev->model = scsi_null_device_strs;	sdev->rev = scsi_null_device_strs;	sdev->host = shost;	sdev->id = starget->id;	sdev->lun = lun;	sdev->channel = starget->channel;	sdev->sdev_state = SDEV_CREATED;	INIT_LIST_HEAD(&sdev->siblings);	INIT_LIST_HEAD(&sdev->same_target_siblings);	INIT_LIST_HEAD(&sdev->cmd_list);	INIT_LIST_HEAD(&sdev->starved_entry);	INIT_LIST_HEAD(&sdev->event_list);	spin_lock_init(&sdev->list_lock);	INIT_WORK(&sdev->event_work, scsi_evt_thread);	sdev->sdev_gendev.parent = get_device(&starget->dev);	sdev->sdev_target = starget;	/* usually NULL and set by ->slave_alloc instead */	sdev->hostdata = hostdata;	/* if the device needs this changing, it may do so in the	 * slave_configure function */	sdev->max_device_blocked = SCSI_DEFAULT_DEVICE_BLOCKED;	/*	 * Some low level driver could use device->type	 */	sdev->type = -1;	/*	 * Assume that the device will have handshaking problems,	 * and then fix this field later if it turns out it	 * doesn't	 */	sdev->borken = 1;	sdev->request_queue = scsi_alloc_queue(sdev);	if (!sdev->request_queue) {		/* release fn is set up in scsi_sysfs_device_initialise, so		 * have to free and put manually here */		put_device(&starget->dev);		kfree(sdev);		goto out;	}	sdev->request_queue->queuedata = sdev;	scsi_adjust_queue_depth(sdev, 0, sdev->host->cmd_per_lun);	scsi_sysfs_device_initialize(sdev);	if (shost->hostt->slave_alloc) {		ret = shost->hostt->slave_alloc(sdev);		if (ret) {			/*			 * if LLDD reports slave not present, don't clutter			 * console with alloc failure messages			 */			if (ret == -ENXIO)				display_failure_msg = 0;			goto out_device_destroy;		}	}	return sdev;out_device_destroy:	transport_destroy_device(&sdev->sdev_gendev);	put_device(&sdev->sdev_gendev);out:	if (display_failure_msg)		printk(ALLOC_FAILURE_MSG, __FUNCTION__);	return NULL;}static void scsi_target_dev_release(struct device *dev){	struct device *parent = dev->parent;	struct scsi_target *starget = to_scsi_target(dev);	kfree(starget);	put_device(parent);}int scsi_is_target_device(const struct device *dev){	return dev->release == scsi_target_dev_release;}EXPORT_SYMBOL(scsi_is_target_device);static struct scsi_target *__scsi_find_target(struct device *parent,					      int channel, uint id){	struct scsi_target *starget, *found_starget = NULL;	struct Scsi_Host *shost = dev_to_shost(parent);	/*	 * Search for an existing target for this sdev.	 */	list_for_each_entry(starget, &shost->__targets, siblings) {		if (starget->id == id &&		    starget->channel == channel) {			found_starget = starget;			break;		}	}	if (found_starget)		get_device(&found_starget->dev);	return found_starget;}/** * scsi_alloc_target - allocate a new or find an existing target * @parent:	parent of the target (need not be a scsi host) * @channel:	target channel number (zero if no channels) * @id:		target id number * * Return an existing target if one exists, provided it hasn't already * gone into STARGET_DEL state, otherwise allocate a new target. * * The target is returned with an incremented reference, so the caller * is responsible for both reaping and doing a last put */static struct scsi_target *scsi_alloc_target(struct device *parent,					     int channel, uint id){	struct Scsi_Host *shost = dev_to_shost(parent);	struct device *dev = NULL;	unsigned long flags;	const int size = sizeof(struct scsi_target)		+ shost->transportt->target_size;	struct scsi_target *starget;	struct scsi_target *found_target;	int error;	starget = kzalloc(size, GFP_KERNEL);	if (!starget) {		printk(KERN_ERR "%s: allocation failure\n", __FUNCTION__);		return NULL;	}	dev = &starget->dev;	device_initialize(dev);	starget->reap_ref = 1;	dev->parent = get_device(parent);	dev->release = scsi_target_dev_release;	sprintf(dev->bus_id, "target%d:%d:%d",		shost->host_no, channel, id);	starget->id = id;	starget->channel = channel;	INIT_LIST_HEAD(&starget->siblings);	INIT_LIST_HEAD(&starget->devices);	starget->state = STARGET_RUNNING;	starget->scsi_level = SCSI_2; retry:	spin_lock_irqsave(shost->host_lock, flags);	found_target = __scsi_find_target(parent, channel, id);	if (found_target)		goto found;	list_add_tail(&starget->siblings, &shost->__targets);	spin_unlock_irqrestore(shost->host_lock, flags);	/* allocate and add */	transport_setup_device(dev);	error = device_add(dev);	if (error) {		dev_err(dev, "target device_add failed, error %d\n", error);		spin_lock_irqsave(shost->host_lock, flags);		list_del_init(&starget->siblings);		spin_unlock_irqrestore(shost->host_lock, flags);		transport_destroy_device(dev);		put_device(parent);		kfree(starget);		return NULL;	}	transport_add_device(dev);	if (shost->hostt->target_alloc) {		error = shost->hostt->target_alloc(starget);		if(error) {			dev_printk(KERN_ERR, dev, "target allocation failed, error %d\n", error);			/* don't want scsi_target_reap to do the final			 * put because it will be under the host lock */			get_device(dev);			scsi_target_reap(starget);			put_device(dev);			return NULL;		}	}	get_device(dev);	return starget; found:	found_target->reap_ref++;	spin_unlock_irqrestore(shost->host_lock, flags);	if (found_target->state != STARGET_DEL) {		put_device(parent);		kfree(starget);		return found_target;	}	/* Unfortunately, we found a dying target; need to	 * wait until it's dead before we can get a new one */	put_device(&found_target->dev);	flush_scheduled_work();	goto retry;}static void scsi_target_reap_usercontext(struct work_struct *work){	struct scsi_target *starget =		container_of(work, struct scsi_target, ew.work);	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);	unsigned long flags;	transport_remove_device(&starget->dev);	device_del(&starget->dev);	transport_destroy_device(&starget->dev);	spin_lock_irqsave(shost->host_lock, flags);	if (shost->hostt->target_destroy)		shost->hostt->target_destroy(starget);	list_del_init(&starget->siblings);	spin_unlock_irqrestore(shost->host_lock, flags);	put_device(&starget->dev);}/** * scsi_target_reap - check to see if target is in use and destroy if not * * @starget: target to be checked *

⌨️ 快捷键说明

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