Linux scsi disk driver

sd.c

static void sd_config_discard(struct scsi_disk *, unsigned int);
static void sd_config_write_same(struct scsi_disk *);
static int  sd_revalidate_disk(struct gendisk *);
static void sd_unlock_native_capacity(struct gendisk *disk);
static int  sd_probe(struct device *);
static int  sd_remove(struct device *);
static void sd_shutdown(struct device *);
static int sd_suspend(struct device *);
static int sd_resume(struct device *);
static void sd_rescan(struct device *);
static int sd_init_command(struct scsi_cmnd *SCpnt);
static void sd_uninit_command(struct scsi_cmnd *SCpnt);
static int sd_done(struct scsi_cmnd *);
static int sd_eh_action(struct scsi_cmnd *, int);
static void sd_read_capacity(struct scsi_disk *sdkp, unsigned char *buffer);
static void scsi_disk_release(struct device *cdev);
static void sd_print_sense_hdr(struct scsi_disk *, struct scsi_sense_hdr *);
static void sd_print_result(struct scsi_disk *, int);
module_init(init_sd);

/**
 *	init_sd - entry point for this driver (both when built in or when
 *	a module).
 *
 *	Note: this function registers this driver with the scsi mid-level.
 **/
static int __init init_sd(void)
{
	int majors = 0, i, err;

	SCSI_LOG_HLQUEUE(3, printk("init_sd: sd driver entry point\n"));

	for (i = 0; i < SD_MAJORS; i++)
	        注册驱动
		if (register_blkdev(sd_major(i), "sd") == 0)
			majors++;

	if (!majors)
		return -ENODEV;

	err = class_register(&sd_disk_class);
	if (err)
		goto err_out;

	sd_cdb_cache = kmem_cache_create("sd_ext_cdb", SD_EXT_CDB_SIZE,
					 0, 0, NULL);
	if (!sd_cdb_cache) {
		printk(KERN_ERR "sd: can‘t init extended cdb cache\n");
		goto err_out_class;
	}

	sd_cdb_pool = mempool_create_slab_pool(SD_MEMPOOL_SIZE, sd_cdb_cache);
	if (!sd_cdb_pool) {
		printk(KERN_ERR "sd: can‘t init extended cdb pool\n");
		goto err_out_cache;
	}
        在scsi总线上注册驱动
	err = scsi_register_driver(&sd_template.gendrv);
	if (err)
		goto err_out_driver;

	return 0;

err_out_driver:
	mempool_destroy(sd_cdb_pool);

err_out_cache:
	kmem_cache_destroy(sd_cdb_cache);

err_out_class:
	class_unregister(&sd_disk_class);
err_out:
	for (i = 0; i < SD_MAJORS; i++)
		unregister_blkdev(sd_major(i), "sd");
	return err;
}
int scsi_register_driver(struct device_driver *drv)
{
drv->bus = &scsi_bus_type;
return driver_register(drv);
}

sd_probe->async_schedule_domain(sd_probe_async, sdkp, &scsi_sd_probe_domain);

sd_probe_async->add_disk

sd_revalidate_disk

可以从gendisk获取scsi_disk和scsi_device

struct gendisk *disk

struct scsi_disk *sdkp = scsi_disk(disk);

struct scsi_device *sdp = sdkp->device;

一些接口函数:

static struct scsi_disk *scsi_disk_get(struct gendisk *disk);

static struct scsi_disk *scsi_disk_get_from_dev(struct device *dev);

scsi_scan.c

scsi_rescan_device

scsi_sysfs.c

static ssize_t
store_rescan_field (struct device *dev, struct device_attribute *attr,
		    const char *buf, size_t count)
{
	scsi_rescan_device(dev);
	return count;
}

scsi.c

subsys_initcall(init_scsi);

static int __init init_scsi(void)
{
	int error;

	error = scsi_init_queue();
	if (error)
		return error;
	error = scsi_init_procfs();
	if (error)
		goto cleanup_queue;
	error = scsi_init_devinfo();
	if (error)
		goto cleanup_procfs;
	error = scsi_init_hosts();
	if (error)
		goto cleanup_devlist;
	error = scsi_init_sysctl();
	if (error)
		goto cleanup_hosts;
	error = scsi_sysfs_register();
	if (error)
		goto cleanup_sysctl;

	scsi_netlink_init();

	printk(KERN_NOTICE "SCSI subsystem initialized\n");
	return 0;

cleanup_sysctl:
	scsi_exit_sysctl();
cleanup_hosts:
	scsi_exit_hosts();
cleanup_devlist:
	scsi_exit_devinfo();
cleanup_procfs:
	scsi_exit_procfs();
cleanup_queue:
	scsi_exit_queue();
	printk(KERN_ERR "SCSI subsystem failed to initialize, error = %d\n",
	       -error);
	return error;
}

接口函数:

int scsi_device_get(struct scsi_device *sdev)

scsi_sysfs.c

scsi_scan->scsi_scan_host_selected->scsi_scan_channel->__scsi_scan_target->scsi_probe_and_add_lun->scsi_probe_lun->scsi_execute_req->scsi_execute_req_flags->scsi_execute->blk_execute_rq->blk_execute_rq_nowait->

__elv_add_request(q, rq, where);

__blk_run_queue(q);->

/**

* __blk_run_queue_uncond - run a queue whether or not it has been stopped

* @q: The queue to run

*

* Description:

*    Invoke request handling on a queue if there are any pending requests.

*    May be used to restart request handling after a request has completed.

*    This variant runs the queue whether or not the queue has been

*    stopped. Must be called with the queue lock held and interrupts

*    disabled. See also @blk_run_queue.

*/

inline void __blk_run_queue_uncond(struct request_queue *q)

{

if (unlikely(blk_queue_dead(q)))

return;

/*

* Some request_fn implementations, e.g. scsi_request_fn(), unlock

* the queue lock internally. As a result multiple threads may be

* running such a request function concurrently. Keep track of the

* number of active request_fn invocations such that blk_drain_queue()

* can wait until all these request_fn calls have finished.

*/

q->request_fn_active++;

q->request_fn(q);

q->request_fn_active--;

}

scsi_request_fn->scsi_dispatch_cmd->

/**

* scsi_dispatch_command - Dispatch a command to the low-level driver.

* @cmd: command block we are dispatching.

*

* Return: nonzero return request was rejected and device‘s queue needs to be

* plugged.

*/

int scsi_dispatch_cmd(struct scsi_cmnd *cmd)

{

struct Scsi_Host *host = cmd->device->host;

int rtn = 0;

atomic_inc(&cmd->device->iorequest_cnt);

/* check if the device is still usable */

if (unlikely(cmd->device->sdev_state == SDEV_DEL)) {

/* in SDEV_DEL we error all commands. DID_NO_CONNECT

* returns an immediate error upwards, and signals

* that the device is no longer present */

cmd->result = DID_NO_CONNECT << 16;

scsi_done(cmd);

/* return 0 (because the command has been processed) */

goto out;

}

/* Check to see if the scsi lld made this device blocked. */

if (unlikely(scsi_device_blocked(cmd->device))) {

/*

* in blocked state, the command is just put back on

* the device queue.  The suspend state has already

* blocked the queue so future requests should not

* occur until the device transitions out of the

* suspend state.

*/

scsi_queue_insert(cmd, SCSI_MLQUEUE_DEVICE_BUSY);

SCSI_LOG_MLQUEUE(3, printk("queuecommand : device blocked \n"));

/*

* NOTE: rtn is still zero here because we don‘t need the

* queue to be plugged on return (it‘s already stopped)

*/

goto out;

}

/*

* If SCSI-2 or lower, store the LUN value in cmnd.

*/

if (cmd->device->scsi_level <= SCSI_2 &&

cmd->device->scsi_level != SCSI_UNKNOWN) {

cmd->cmnd[1] = (cmd->cmnd[1] & 0x1f) |

(cmd->device->lun << 5 & 0xe0);

}

scsi_log_send(cmd);

/*

* Before we queue this command, check if the command

* length exceeds what the host adapter can handle.

*/

if (cmd->cmd_len > cmd->device->host->max_cmd_len) {

SCSI_LOG_MLQUEUE(3,

printk("queuecommand : command too long. "

"cdb_size=%d host->max_cmd_len=%d\n",

cmd->cmd_len, cmd->device->host->max_cmd_len));

cmd->result = (DID_ABORT << 16);

scsi_done(cmd);

goto out;

}

if (unlikely(host->shost_state == SHOST_DEL)) {

cmd->result = (DID_NO_CONNECT << 16);

scsi_done(cmd);

} else {

trace_scsi_dispatch_cmd_start(cmd);

cmd->scsi_done = scsi_done;

rtn = host->hostt->queuecommand(host, cmd);

              通过host将cmd传送出去。如FC、IB(srp)

}

if (rtn) {

trace_scsi_dispatch_cmd_error(cmd, rtn);

if (rtn != SCSI_MLQUEUE_DEVICE_BUSY &&

rtn != SCSI_MLQUEUE_TARGET_BUSY)

rtn = SCSI_MLQUEUE_HOST_BUSY;

scsi_queue_insert(cmd, rtn);

SCSI_LOG_MLQUEUE(3,

printk("queuecommand : request rejected\n"));

}

out:

SCSI_LOG_MLQUEUE(3, printk("leaving scsi_dispatch_cmnd()\n"));

return rtn;

}

/*
 * Create the actual show/store functions and data structures.
 */

static ssize_t
store_scan(struct device *dev, struct device_attribute *attr,
	   const char *buf, size_t count)
{
	struct Scsi_Host *shost = class_to_shost(dev);
	int res;

	res = scsi_scan(shost, buf);
	if (res == 0)
		res = count;
	return res;
};

static int scsi_scan(struct Scsi_Host *shost, const char *str)
{
	char s1[15], s2[15], s3[15], junk;
	unsigned int channel, id, lun;
	int res;

	res = sscanf(str, "%10s %10s %10s %c", s1, s2, s3, &junk);
	if (res != 3)
		return -EINVAL;
	if (check_set(&channel, s1))
		return -EINVAL;
	if (check_set(&id, s2))
		return -EINVAL;
	if (check_set(&lun, s3))
		return -EINVAL;
	if (shost->transportt->user_scan)
		res = shost->transportt->user_scan(shost, channel, id, lun);
	else
		res = scsi_scan_host_selected(shost, channel, id, lun, 1);
	return res;
}
时间: 2024-08-30 05:50:53

Linux scsi disk driver的相关文章

Linux SCSI回调IO的分析

本文转载自:http://blog.csdn.net/xushiyan/article/details/6941640,如需参考,请访问原始链接地址. 没找到如何转载的入口,只好全文copy了. -----------------------------------分割线------------------------------------------------- LINUX 内核中 SCSI 子系统由 SCSI 上层,中间层和底层驱动模块 [1] 三部分组成,主要负责管理 SCSI 资源和

Linux scsi driver overview

iscsi initiator config ISCSI_TCP tristate "iSCSI Initiator over TCP/IP" depends on SCSI && INET select CRYPTO select CRYPTO_MD5 select CRYPTO_CRC32C select SCSI_ISCSI_ATTRS help  The iSCSI Driver provides a host with the ability to acces

Linux Ethernet Bonding Driver HOWTO 英文原版

Linux Ethernet Bonding Driver HOWTO Latest update: 12 November 2007 Initial release : Thomas Davis <tadavis at lbl.gov> Corrections, HA extensions : 2000/10/03-15 : - Willy Tarreau <willy at meta-x.org> - Constantine Gavrilov <const-g at xp

I.MX6 Linux I2C device&amp; driver hacking

/******************************************************************************************* * I.MX6 Linux I2C device& driver hacking * 声明: * 1. 本文主要是对Linux I2C驱动进行代码跟踪,主要是为了能够对I2C驱动框架有个全面的了解: * 2. 本文源代码来自myzr_android4_2_2_1_1_0.tar.bz2: * 3. 如果你有兴趣,

Configure Red Hat Enterprise Linux shared disk cluster for SQL Server

下面一步一步介绍一下如何在Red Hat Enterprise Linux系统上为SQL Server配置共享磁盘集群(Shared Disk Cluster)及其相关使用(仅供测试学习之用,基础篇) 一.      创建共享磁盘和 Cluster 微软官方配置文档:https://docs.microsoft.com/en-us/sql/linux/sql-server-linux-shared-disk-cluster-red-hat-7-configure. Linux Cluster结构

Configure Red Hat Enterprise Linux shared disk cluster for SQL Server——RHEL上的“类”SQL Server Cluster功能

下面一步一步介绍一下如何在Red Hat Enterprise Linux系统上为SQL Server配置共享磁盘集群(Shared Disk Cluster)及其相关使用(仅供测试学习之用,基础篇) 一.      创建共享磁盘和 Cluster 微软官方配置文档:https://docs.microsoft.com/en-us/sql/linux/sql-server-linux-shared-disk-cluster-red-hat-7-configure. Linux Cluster结构

linux platform device/driver(三)--Platform Device和Platform_driver注册过程之代码对比

转自:http://blog.csdn.net/thl789/article/details/6723350 Linux 2.6的设备驱动模型中,所有的device都是通过Bus相连.device_register() / driver_register()执行时通过枚举BUS上的Driver/Device来实现绑定,本文详解这一过程.这是整个LINUX设备驱动的基础,PLATFORM设备,I2C上的设备等诸设备的注册最终也是调用本文讲述的注册函数来实现的. Linux Device的注册最终都

linux platform device/driver(二)--Platform Device和Platform_driver注册过程

从 Linux 2.6 起引入了一套新的驱动管理和注册机制 :Platform_device 和 Platform_driver . Linux 中大部分的设备驱动,都可以使用这套机制 ,  设备用 Platform_device 表示,驱动用 Platform_driver 进行注册. Linux platform driver 机制和传统的 device driver  机制 ( 通过 driver_register 函数进行注册 ) 相比,一个十分明显的优势在于 platform 机制将设

linux platform device/driver(一)

1.platform device是怎么"自动"关联到platform driver上的? 转向linux driver有些时间了,前段时间碰到个问题,在Linux kernel 3.10的drivers/tty/serial/imx.c中,注册driver的时候调用platform_driver_register(&serial_imx_driver),serial_imx_driver类型为platform_driver, serial_imx_driver中有个成员变量p