本文以usb storage设备驱动来分析,由于usb storage涉及到usb驱动框架,scsi驱动框架,block io驱动框架,先来看下初始化
1. usb storage设备的初始化流程
static struct usb_driver usb_storage_driver = {
.name = "usb-storage",
.probe = storage_probe,
.disconnect = usb_stor_disconnect,
.suspend = usb_stor_suspend,
.resume = usb_stor_resume,
.reset_resume = usb_stor_reset_resume,
.pre_reset = usb_stor_pre_reset,
.post_reset = usb_stor_post_reset,
.id_table = usb_storage_usb_ids,
.supports_autosuspend = 1,
.soft_unbind = 1,
};
static int __init usb_stor_init(void)
{
int retval;
pr_info("Initializing USB Mass Storage driver...\n");
/* register the driver, return usb_register return code if error */
retval = usb_register(&usb_storage_driver);
if (retval == 0) {
pr_info("USB Mass Storage support registered.\n");
usb_usual_set_present(USB_US_TYPE_STOR);
}
return retval;
}
如果开机时有U盘插在hub上,就会在初始化时分配usb_device,然后获取配置,触发generic_probe,选择一个配置usb_choose_configuration,并且设置该配置usb_set_configuration,在该函数里面对每个接口都调用device_add 函数注册到系统。当usb_stor_init 调用时,就会触发usb_device_match,接着调用该驱动的probe函数。
static int storage_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
struct us_data *us;
int result;
/*
* If libusual is configured, let it decide whether a standard
* device should be handled by usb-storage or by ub.
* If the device isn't standard (is handled by a subdriver
* module) then don't accept it.
*/
if (usb_usual_check_type(id, USB_US_TYPE_STOR) ||
usb_usual_ignore_device(intf))
return -ENXIO;
/*
* Call the general probe procedures.
*
* The unusual_dev_list array is parallel to the usb_storage_usb_ids
* table, so we use the index of the id entry to find the
* corresponding unusual_devs entry.
*/
result = usb_stor_probe1(&us, intf, id,
(id - usb_storage_usb_ids) + us_unusual_dev_list);
if (result)
return result;
/* No special transport or protocol settings in the main module */
result = usb_stor_probe2(us);
return result;
}
分了两个阶段,两个函数,usb_stor_probe1和usb_stor_probe2。
int usb_stor_probe1(struct us_data **pus,
struct usb_interface *intf,
const struct usb_device_id *id,
struct us_unusual_dev *unusual_dev)
{
struct Scsi_Host *host;
struct us_data *us;
int result;
US_DEBUGP("USB Mass Storage device detected\n");
/*
* Ask the SCSI layer to allocate a host structure, with extra
* space at the end for our private us_data structure.
*/
host = scsi_host_alloc(&usb_stor_host_template, sizeof(*us)); //虚拟出一个scsi host主机适配器
if (!host) {
dev_warn(&intf->dev,
"Unable to allocate the scsi host\n");
return -ENOMEM;
}
/*
* Allow 16-byte CDBs and thus > 2TB
*/
host->max_cmd_len = 16;
host->sg_tablesize = usb_stor_sg_tablesize(intf);
*pus = us = host_to_us(host);
memset(us, 0, sizeof(struct us_data));
mutex_init(&(us->dev_mutex));
init_completion(&us->cmnd_ready);
init_completion(&(us->notify));
init_waitqueue_head(&us->delay_wait);
init_completion(&us->scanning_done);
/* Associate the us_data structure with the USB device */
result = associate_dev(us, intf);
if (result)
goto BadDevice;
/* Get the unusual_devs entries and the descriptors */
result = get_device_info(us, id, unusual_dev);
if (result)
goto BadDevice;
/* Get standard transport and protocol settings */
get_transport(us);
get_protocol(us);
/* Give the caller a chance to fill in specialized transport
* or protocol settings.
*/
return 0;
BadDevice:
US_DEBUGP("storage_probe() failed\n");
release_everything(us);
return result;
}
struct scsi_host_template usb_stor_host_template = {
/* basic userland interface stuff */
.name = "usb-storage",
.proc_name = "usb-storage",
.proc_info = proc_info,
.info = host_info,
/* command interface -- queued only */
.queuecommand = queuecommand,
/* error and abort handlers */
.eh_abort_handler = command_abort,
.eh_device_reset_handler = device_reset,
.eh_bus_reset_handler = bus_reset,
/* queue commands only, only one command per LUN */
.can_queue = 1,
.cmd_per_lun = 1,
/* unknown initiator id */
.this_id = -1,
.slave_alloc = slave_alloc,
.slave_configure = slave_configure,
/* lots of sg segments can be handled */
.sg_tablesize = SCSI_MAX_SG_CHAIN_SEGMENTS,
/* limit the total size of a transfer to 120 KB */
.max_sectors = 240,
/* merge commands... this seems to help performance, but
* periodically someone should test to see which setting is more
* optimal.
*/
.use_clustering = 1,
/* emulated HBA */
.emulated = 1,
/* we do our own delay after a device or bus reset */
.skip_settle_delay = 1,
/* sysfs device attributes */
.sdev_attrs = sysfs_device_attr_list,
/* module management */
.module = THIS_MODULE
};
int usb_stor_probe2(struct us_data *us)
{
struct task_struct *th;
int result;
struct device *dev = &us->pusb_intf->dev;
/* Make sure the transport and protocol have both been set */
if (!us->transport || !us->proto_handler) {
result = -ENXIO;
goto BadDevice;
}
US_DEBUGP("Transport: %s\n", us->transport_name);
US_DEBUGP("Protocol: %s\n", us->protocol_name);
/* fix for single-lun devices */
if (us->fflags & US_FL_SINGLE_LUN)
us->max_lun = 0;
/* Find the endpoints and calculate pipe values */
result = get_pipes(us);
if (result)
goto BadDevice;
/*
* If the device returns invalid data for the first READ(10)
* command, indicate the command should be retried.
*/
if (us->fflags & US_FL_INITIAL_READ10)
set_bit(US_FLIDX_REDO_READ10, &us->dflags);
/* Acquire all the other resources and add the host */
result = usb_stor_acquire_resources(us); //在这个函数里面还创建了内核线程usb-storage
if (result)
goto BadDevice;
snprintf(us->scsi_name, sizeof(us->scsi_name), "usb-storage %s",
dev_name(&us->pusb_intf->dev));
result = scsi_add_host(us_to_host(us), dev); //看到了熟悉的scsi_add_host函数,那么scsi_scan_host在哪呢
if (result) {
dev_warn(dev,
"Unable to add the scsi host\n");
goto BadDevice;
}
/* Start up the thread for delayed SCSI-device scanning */
th = kthread_create(usb_stor_scan_thread, us, "usb-stor-scan"); //scsi_scan_host函数是在这个内核线程里面被调用的
if (IS_ERR(th)) {
dev_warn(dev,
"Unable to start the device-scanning thread\n");
complete(&us->scanning_done);
quiesce_and_remove_host(us);
result = PTR_ERR(th);
goto BadDevice;
}
usb_autopm_get_interface_no_resume(us->pusb_intf);
wake_up_process(th);
return 0;
/* We come here if there are any problems */
BadDevice:
US_DEBUGP("storage_probe() failed\n");
release_everything(us);
return result;
}
有两个内核线程usb-stor-scan和usb-storage
static int usb_stor_scan_thread(void * __us)
{
struct us_data *us = (struct us_data *)__us;
struct device *dev = &us->pusb_intf->dev;
dev_dbg(dev, "device found\n");
set_freezable();
/* Wait for the timeout to expire or for a disconnect */
if (delay_use > 0) {
dev_dbg(dev, "waiting for device to settle "
"before scanning\n");
wait_event_freezable_timeout(us->delay_wait,
test_bit(US_FLIDX_DONT_SCAN, &us->dflags),
delay_use * HZ);
}
/* If the device is still connected, perform the scanning */
if (!test_bit(US_FLIDX_DONT_SCAN, &us->dflags)) {
/* For bulk-only devices, determine the max LUN value */
if (us->protocol == USB_PR_BULK &&
!(us->fflags & US_FL_SINGLE_LUN)) {
mutex_lock(&us->dev_mutex);
us->max_lun = usb_stor_Bulk_max_lun(us);
mutex_unlock(&us->dev_mutex);
}
scsi_scan_host(us_to_host(us));
dev_dbg(dev, "scan complete\n");
/* Should we unbind if no devices were detected? */
}
usb_autopm_put_interface(us->pusb_intf);
complete_and_exit(&us->scanning_done, 0);
}
static int usb_stor_control_thread(void * __us)
{
struct us_data *us = (struct us_data *)__us;
struct Scsi_Host *host = us_to_host(us);
for(;;) {
US_DEBUGP("*** thread sleeping.\n");
if (wait_for_completion_interruptible(&us->cmnd_ready)) //等待completion变量
break;
US_DEBUGP("*** thread awakened.\n");
/* lock the device pointers */
mutex_lock(&(us->dev_mutex));
/* lock access to the state */
scsi_lock(host);
/* When we are called with no command pending, we're done */
if (us->srb == NULL) {
scsi_unlock(host);
mutex_unlock(&us->dev_mutex);
US_DEBUGP("-- exiting\n");
break;
}
/* has the command timed out *already* ? */
if (test_bit(US_FLIDX_TIMED_OUT, &us->dflags)) {
us->srb->result = DID_ABORT << 16;
goto SkipForAbort;
}
scsi_unlock(host);
/* reject the command if the direction indicator
* is UNKNOWN
*/
if (us->srb->sc_data_direction == DMA_BIDIRECTIONAL) {
US_DEBUGP("UNKNOWN data direction\n");
us->srb->result = DID_ERROR << 16;
}
/* reject if target != 0 or if LUN is higher than
* the maximum known LUN
*/
else if (us->srb->device->id &&
!(us->fflags & US_FL_SCM_MULT_TARG)) {
US_DEBUGP("Bad target number (%d:%d)\n",
us->srb->device->id, us->srb->device->lun);
us->srb->result = DID_BAD_TARGET << 16;
}
else if (us->srb->device->lun > us->max_lun) {
US_DEBUGP("Bad LUN (%d:%d)\n",
us->srb->device->id, us->srb->device->lun);
us->srb->result = DID_BAD_TARGET << 16;
}
/* Handle those devices which need us to fake
* their inquiry data */
else if ((us->srb->cmnd[0] == INQUIRY) &&
(us->fflags & US_FL_FIX_INQUIRY)) {
unsigned char data_ptr[36] = {
0x00, 0x80, 0x02, 0x02,
0x1F, 0x00, 0x00, 0x00};
US_DEBUGP("Faking INQUIRY command\n");
fill_inquiry_response(us, data_ptr, 36);
us->srb->result = SAM_STAT_GOOD;
}
/* we've got a command, let's do it! */
else {
US_DEBUG(usb_stor_show_command(us->srb));
us->proto_handler(us->srb, us); //处理命令的函数
usb_mark_last_busy(us->pusb_dev);
}
/* lock access to the state */
scsi_lock(host);
/* indicate that the command is done */
if (us->srb->result != DID_ABORT << 16) {
US_DEBUGP("scsi cmd done, result=0x%x\n",
us->srb->result);
us->srb->scsi_done(us->srb);
} else {
SkipForAbort:
US_DEBUGP("scsi command aborted\n");
}
/* If an abort request was received we need to signal that
* the abort has finished. The proper test for this is
* the TIMED_OUT flag, not srb->result == DID_ABORT, because
* the timeout might have occurred after the command had
* already completed with a different result code. */
if (test_bit(US_FLIDX_TIMED_OUT, &us->dflags)) {
complete(&(us->notify));
/* Allow USB transfers to resume */
clear_bit(US_FLIDX_ABORTING, &us->dflags);
clear_bit(US_FLIDX_TIMED_OUT, &us->dflags);
}
/* finished working on this command */
us->srb = NULL;
scsi_unlock(host);
/* unlock the device pointers */
mutex_unlock(&us->dev_mutex);
} /* for (;;) */
/* Wait until we are told to stop */
for (;;) {
set_current_state(TASK_INTERRUPTIBLE);
if (kthread_should_stop())
break;
schedule();
}
__set_current_state(TASK_RUNNING);
return 0;
}
把storage_probe的调用流程贴下,网上网友总结的非常详细:
storage_probe
usb_stor_probe1
scsi_alloc_host
associate_dev
get_device_info
get_transport //us->transport = usb_stor_CB_transport;
get_protocol //us->proto_handler = usb_stor_transparent_scsi_command
usb_stor_probe2
get_pipe
usb_stor_acquire_resources
usb_alloc_urb
kthread_run(usb_stor_control_thread,us,"usb-storage")
scsi_add_host
kthread_run(usb_stor_scan_thread, us, "usb-stor-scan")
wake_up_process //wake up kthread usb_stor_scan_thread
接下来先看usb_stor_scan_thread线程的流程:
usb_stor_scan_thread
usb_stor_Bulk_max_lun
usb_stor_control_msg
usb_fill_control_urb
usb_stor_msg_common
init_completion
usb_submit_urb
wait_for_completion_interruptible_timeout
scsi_scan_host
2. usb storage设备的读写流程
(1)scsi层:当用户需要访问usb设备,scsi-core会调用scsi_dispatch_cmd函数,scsi_dispatch_cmd会调用scsi_host_template中的queuecommand,对应usb store就是queuecommand函数。
static DEF_SCSI_QCMD(queuecommand)
#define DEF_SCSI_QCMD(func_name) \
int func_name(struct Scsi_Host *shost, struct scsi_cmnd *cmd) \
{ \
unsigned long irq_flags; \
int rc; \
spin_lock_irqsave(shost->host_lock, irq_flags); \
scsi_cmd_get_serial(shost, cmd); \
rc = func_name##_lck (cmd, cmd->scsi_done); \
spin_unlock_irqrestore(shost->host_lock, irq_flags); \
return rc; \
}
static int queuecommand_lck(struct scsi_cmnd *srb,
void (*done)(struct scsi_cmnd *))
{
struct us_data *us = host_to_us(srb->device->host);
US_DEBUGP("%s called\n", __func__);
/* check for state-transition errors */
if (us->srb != NULL) {
printk(KERN_ERR USB_STORAGE "Error in %s: us->srb = %p\n",
__func__, us->srb);
return SCSI_MLQUEUE_HOST_BUSY;
}
/* fail the command if we are disconnecting */
if (test_bit(US_FLIDX_DISCONNECTING, &us->dflags)) {
US_DEBUGP("Fail command during disconnect\n");
srb->result = DID_NO_CONNECT << 16;
done(srb);
return 0;
}
/* enqueue the command and wake up the control thread */
srb->scsi_done = done;
us->srb = srb;
complete(&us->cmnd_ready);
return 0;
}
(2)queuecommand唤醒了usb_stor_control_thread线程
该线程会调用us->proto_handler(us->srb, us),此接口在probe的时候已经定义为usb_stor_Bulk_transport
void usb_stor_transparent_scsi_command(struct scsi_cmnd *srb,
struct us_data *us)
{
/* send the command to the transport layer */
usb_stor_invoke_transport(srb, us);
}
usb_stor_invoke_transport
scsi_set_resid(srb, 0)
us->transport(srb, us) //对应usb_stor_CB_transport
usb_stor_CB_transport
usb_stor_ctrl_transfer //发送命令
usb_fill_control_urb
usb_stor_msg_common
init_completion
usb_submit_urb
wait_for_completion_interruptible_timeout
interpret_urb_result
usb_stor_bulk_srb //传输数据
usb_stor_bulk_transfer_sglist
usb_sg_init
usb_sg_wait
interpret_urb_result
scsi_set_resid
usb_stor_intr_transfer //获取传输状态
usb_fill_int_urb
usb_stor_msg_common
interpret_urb_result