SCSI 구동 프레임 분석
27278 단어 링크 ux 구동
struct scsi_host_template {
struct module *module;
const char *name; //scsi hba
int (* detect)(struct scsi_host_template *);
int (* release)(struct Scsi_Host *);
const char *(* info)(struct Scsi_Host *);
int (* ioctl)(struct scsi_device *dev, int cmd, void __user *arg);
#ifdef CONFIG_COMPAT
int (* compat_ioctl)(struct scsi_device *dev, int cmd, void __user *arg);
#endif
int (* queuecommand)(struct Scsi_Host *, struct scsi_cmnd *); // SCSI
int (* transfer_response)(struct scsi_cmnd *,
void (*done)(struct scsi_cmnd *));
int (* eh_abort_handler)(struct scsi_cmnd *); //
int (* eh_device_reset_handler)(struct scsi_cmnd *); //scsi
int (* eh_target_reset_handler)(struct scsi_cmnd *); //
int (* eh_bus_reset_handler)(struct scsi_cmnd *); //scsi
int (* eh_host_reset_handler)(struct scsi_cmnd *); //
int (* slave_alloc)(struct scsi_device *); // SCSI
int (* slave_configure)(struct scsi_device *); // SCSI inquiry
void (* slave_destroy)(struct scsi_device *); // scsi
int (* target_alloc)(struct scsi_target *); // scsi
void (* target_destroy)(struct scsi_target *); // scsi
int (* scan_finished)(struct Scsi_Host *, unsigned long);
void (* scan_start)(struct Scsi_Host *);
int (* change_queue_depth)(struct scsi_device *, int, int); //
int (* change_queue_type)(struct scsi_device *, int); // tag
int (* bios_param)(struct scsi_device *, struct block_device *,
sector_t, int []);
void (*unlock_native_capacity)(struct scsi_device *);
int (*proc_info)(struct Scsi_Host *, char *, char **, off_t, int, int);
enum blk_eh_timer_return (*eh_timed_out)(struct scsi_cmnd *);
const char *proc_name;
struct proc_dir_entry *proc_dir;
int can_queue;
int this_id;
unsigned short sg_tablesize;
unsigned short sg_prot_tablesize;
unsigned short max_sectors;
unsigned long dma_boundary;
#define SCSI_DEFAULT_MAX_SECTORS 1024
short cmd_per_lun;
unsigned char present;
unsigned supported_mode:2;
unsigned unchecked_isa_dma:1;
unsigned use_clustering:1;
unsigned emulated:1;
unsigned skip_settle_delay:1;
unsigned ordered_tag:1;
unsigned int max_host_blocked;
#define SCSI_DEFAULT_HOST_BLOCKED 7
struct device_attribute **shost_attrs;
struct device_attribute **sdev_attrs;
struct list_head legacy_hosts;
u64 vendor_id;
};
struct Scsi_Host {
/*
* __devices is protected by the host_lock, but you should
* usually use scsi_device_lookup / shost_for_each_device
* to access it and don't care about locking yourself.
* In the rare case of beeing in irq context you can use
* their __ prefixed variants with the lock held. NEVER
* access this list directly from a driver.
*/
struct list_head __devices; // scsi scsi
struct list_head __targets; // scsi scsi
struct scsi_host_cmd_pool *cmd_pool; //
spinlock_t free_list_lock;
struct list_head free_list; /* backup store of cmd structs */
struct list_head starved_list; //
spinlock_t default_lock;
spinlock_t *host_lock;
struct mutex scan_mutex;/* serialize scanning activity */
struct list_head eh_cmd_q; // scsi
struct task_struct * ehandler; /* Error recovery thread. */ //
struct completion * eh_action; /* Wait for specific actions on the //
host. */
wait_queue_head_t host_wait; //
struct scsi_host_template *hostt; //
struct scsi_transport_template *transportt; //
/*
* Area to keep a shared tag map (if needed, will be
* NULL if not).
*/
struct blk_queue_tag *bqt;
/*
* The following two fields are protected with host_lock;
* however, eh routines can safely access during eh processing
* without acquiring the lock.
*/
unsigned int host_busy; /* commands actually active on low-level */ //
unsigned int host_failed; /* commands that failed. */ //
unsigned int host_eh_scheduled; /* EH scheduled without command */
unsigned int host_no; /* Used for IOCTL_GET_IDLUN, /proc/scsi et al. */ //
int resetting; /* if set, it means that last_reset is a valid value */ // 1,last_reset
unsigned long last_reset; //
/*
* These three parameters can be used to allow for wide scsi,
* and for host adapters that support multiple busses
* The first two should be set to 1 more than the actual max id
* or lun (i.e. 8 for normal systems).
*/
unsigned int max_id; //
unsigned int max_lun; // lun
unsigned int max_channel; //
/*
* This is a unique identifier that must be assigned so that we
* have some way of identifying each detected host adapter properly
* and uniquely. For hosts that do not support more than one card
* in the system at one time, this does not need to be set. It is
* initialized to 0 in scsi_register.
*/
unsigned int unique_id; //
/*
* The maximum length of SCSI commands that this host can accept.
* Probably 12 for most host adapters, but could be 16 for others.
* or 260 if the driver supports variable length cdbs.
* For drivers that don't set this field, a value of 12 is
* assumed.
*/
unsigned short max_cmd_len; // SCSI
int this_id; // scsi id
int can_queue; //
short cmd_per_lun;
short unsigned int sg_tablesize;
short unsigned int sg_prot_tablesize;
short unsigned int max_sectors;
unsigned long dma_boundary;
/*
* Used to assign serial numbers to the cmds.
* Protected by the host lock.
*/
unsigned long cmd_serial_number;
unsigned active_mode:2;
unsigned unchecked_isa_dma:1;
unsigned use_clustering:1;
unsigned use_blk_tcq:1;
/*
* Host has requested that no further requests come through for the
* time being.
*/
unsigned host_self_blocked:1;
/*
* Host uses correct SCSI ordering not PC ordering. The bit is
* set for the minority of drivers whose authors actually read
* the spec ;).
*/
unsigned reverse_ordering:1;
/*
* Ordered write support
*/
unsigned ordered_tag:1;
/* Task mgmt function in progress */
unsigned tmf_in_progress:1;
/* Asynchronous scan in progress */
unsigned async_scan:1;
/*
* Optional work queue to be utilized by the transport
*/
char work_q_name[20];
struct workqueue_struct *work_q;
/*
* Host has rejected a command because it was busy.
*/
unsigned int host_blocked;
/*
* Value host_blocked counts down from
*/
unsigned int max_host_blocked;
/* Protection Information */
unsigned int prot_capabilities;
unsigned char prot_guard_type;
/*
* q used for scsi_tgt msgs, async events or any other requests that
* need to be processed in userspace
*/
struct request_queue *uspace_req_q;
/* legacy crap */
unsigned long base;
unsigned long io_port;
unsigned char n_io_port;
unsigned char dma_channel;
unsigned int irq;
enum scsi_host_state shost_state;
/* ldm bits */
struct device shost_gendev, shost_dev;
/*
* List of hosts per template.
*
* This is only for use by scsi_module.c for legacy templates.
* For these access to it is synchronized implicitly by
* module_init/module_exit.
*/
struct list_head sht_legacy_list;
/*
* Points to the transport data (if any) which is allocated
* separately
*/
void *shost_data;
/*
* Points to the physical bus device we'd use to do DMA
* Needed just in case we have virtual hosts.
*/
struct device *dma_dev;
/*
* We should ensure that this is aligned, both for better performance
* and also because some compilers (m68k) don't automatically force
* alignment to a long boundary.
*/
unsigned long hostdata[0] /* Used for storage of host specific stuff */
__attribute__ ((aligned (sizeof(unsigned long))));
};
struct scsi_target {
struct scsi_device *starget_sdev_user; // lun IO
struct list_head siblings; //
struct list_head devices; // scsi
struct device dev; //
unsigned int reap_ref; /* protected by the host lock */
unsigned int channel; //
unsigned int id; /* target id ... replace
* scsi_device.id eventually */ // ID
unsigned int create:1; /* signal that it needs to be added */ //
unsigned int single_lun:1; /* Indicates we should only
* allow I/O to one of the luns
* for the device at a time. */
unsigned int pdt_1f_for_no_lun; /* PDT = 0x1f */
/* means no lun present */
/* commands actually active on LLD. protected by host lock. */
unsigned int target_busy;
/*
* LLDs should set this in the slave_alloc host template callout.
* If set to zero then there is not limit.
*/
unsigned int can_queue; //
unsigned int target_blocked; //
unsigned int max_target_blocked;
#define SCSI_DEFAULT_TARGET_BLOCKED 3
char scsi_level;
struct execute_work ew; //
enum scsi_target_state state; //
void *hostdata; /* available to low-level driver */
unsigned long starget_data[0]; /* for the transport */
/* starget_data must be the last element!!!! */
} __attribute__((aligned(sizeof(unsigned long))));
struct scsi_device {
struct Scsi_Host *host; //
struct request_queue *request_queue; //
/* the next two are protected by the host->host_lock */
struct list_head siblings; /* list of all devices on this host */ //
struct list_head same_target_siblings; /* just the devices sharing same target id */ //
/* this is now protected by the request_queue->queue_lock */
unsigned int device_busy; /* commands actually active on
* low-level. protected by queue_lock. */ //
spinlock_t list_lock;
struct list_head cmd_list; /* queue of in use SCSI Command structures */ // scsi
struct list_head starved_entry; //
struct scsi_cmnd *current_cmnd; /* currently active command */ //
unsigned short queue_depth; /* How deep of a queue we want */ //
unsigned short max_queue_depth; /* max queue depth */ //
unsigned short last_queue_full_depth; /* These two are used by */ //
unsigned short last_queue_full_count; /* scsi_track_queue_full() */ //
unsigned long last_queue_full_time; /* last queue full time */ //
unsigned long queue_ramp_up_period; /* ramp up period in jiffies */ //
#define SCSI_DEFAULT_RAMP_UP_PERIOD (120 * HZ)
unsigned long last_queue_ramp_up; /* last queue ramp up time */ // ramp up
unsigned int id, lun, channel; // ID,lun ,
unsigned int manufacturer; /* Manufacturer of device, for using
* vendor-specific cmd's */
unsigned sector_size; /* size in bytes */
void *hostdata; /* available to low-level driver */
char type; //scsi
char scsi_level; //scsi
char inq_periph_qual; /* PQ from INQUIRY data */
unsigned char inquiry_len; /* valid bytes in 'inquiry' */
unsigned char * inquiry; /* INQUIRY response data */
const char * vendor; /* [back_compat] point into 'inquiry' ... */
const char * model; /* ... after scan; point to static string */
const char * rev; /* ... "nullnullnullnull" before scan */
unsigned char current_tag; /* current tag */
struct scsi_target *sdev_target; /* used only for single_lun */ // single_lun
unsigned int sdev_bflags; /* black/white flags as also found in
* scsi_devinfo.[hc]. For now used only to
* pass settings from slave_alloc to scsi
* core. */
unsigned writeable:1;
unsigned removable:1;
unsigned changed:1; /* Data invalid due to media change */
unsigned busy:1; /* Used to prevent races */
unsigned lockable:1; /* Able to prevent media removal */
unsigned locked:1; /* Media removal disabled */
unsigned borken:1; /* Tell the Seagate driver to be
* painfully slow on this device */
unsigned disconnect:1; /* can disconnect */
unsigned soft_reset:1; /* Uses soft reset option */
unsigned sdtr:1; /* Device supports SDTR messages */
unsigned wdtr:1; /* Device supports WDTR messages */
unsigned ppr:1; /* Device supports PPR messages */
unsigned tagged_supported:1; /* Supports SCSI-II tagged queuing */
unsigned simple_tags:1; /* simple queue tag messages are enabled */
unsigned ordered_tags:1;/* ordered queue tag messages are enabled */
unsigned was_reset:1; /* There was a bus reset on the bus for
* this device */
unsigned expecting_cc_ua:1; /* Expecting a CHECK_CONDITION/UNIT_ATTN
* because we did a bus reset. */
unsigned use_10_for_rw:1; /* first try 10-byte read / write */
unsigned use_10_for_ms:1; /* first try 10-byte mode sense/select */
unsigned skip_ms_page_8:1; /* do not use MODE SENSE page 0x08 */
unsigned skip_ms_page_3f:1; /* do not use MODE SENSE page 0x3f */
unsigned use_192_bytes_for_3f:1; /* ask for 192 bytes from page 0x3f */
unsigned no_start_on_add:1; /* do not issue start on add */
unsigned allow_restart:1; /* issue START_UNIT in error handler */
unsigned manage_start_stop:1; /* Let HLD (sd) manage start/stop */
unsigned start_stop_pwr_cond:1; /* Set power cond. in START_STOP_UNIT */
unsigned no_uld_attach:1; /* disable connecting to upper level drivers */
unsigned select_no_atn:1;
unsigned fix_capacity:1; /* READ_CAPACITY is too high by 1 */
unsigned guess_capacity:1; /* READ_CAPACITY might be too high by 1 */
unsigned retry_hwerror:1; /* Retry HARDWARE_ERROR */
unsigned last_sector_bug:1; /* do not use multisector accesses on
SD_LAST_BUGGY_SECTORS */
unsigned no_read_disc_info:1; /* Avoid READ_DISC_INFO cmds */
unsigned no_read_capacity_16:1; /* Avoid READ_CAPACITY_16 cmds */
unsigned is_visible:1; /* is the device visible in sysfs */
DECLARE_BITMAP(supported_events, SDEV_EVT_MAXBITS); /* supported events */ //
struct list_head event_list; /* asserted events */ //
struct work_struct event_work; //
unsigned int device_blocked; /* Device returned QUEUE_FULL. */ //
unsigned int max_device_blocked; /* what device_blocked counts down from */
#define SCSI_DEFAULT_DEVICE_BLOCKED 3
atomic_t iorequest_cnt;
atomic_t iodone_cnt;
atomic_t ioerr_cnt;
struct device sdev_gendev,
sdev_dev; //sdev_gendev ,sdev_dev scsi
struct execute_work ew; /* used to get process context on put */
struct work_struct requeue_work;
struct scsi_dh_data *scsi_dh_data;
enum scsi_device_state sdev_state;
unsigned long sdev_data[0];
} __attribute__((aligned(sizeof(unsigned long))));
2. 다음은 중요 한 API 함수:
static int __init init_scsi(void)
{
int error;
error = scsi_init_queue(); //
if (error)
return error;
error = scsi_init_procfs(); // proc
if (error)
goto cleanup_queue;
error = scsi_init_devinfo(); // scsi
if (error)
goto cleanup_procfs;
error = scsi_init_hosts(); // shost_class
if (error)
goto cleanup_devlist;
error = scsi_init_sysctl(); // sysctl
if (error)
goto cleanup_hosts;
error = scsi_sysfs_register(); // scsi sdev_class
if (error)
goto cleanup_sysctl;
scsi_netlink_init(); // scsi netlingk
printk(KERN_NOTICE "SCSI subsystem initialized
");
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
",
-error);
return error;
}
scsi_host_alloc 와 분배 i2c어댑터, 분배 spimaster 는 호스트 어댑터 층 을 분배 하 는 구조 체 와 유사 합 니 다.scsi_add_host 는 시스템 에 scsi 등록host。
struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize)
{
struct Scsi_Host *shost;
gfp_t gfp_mask = GFP_KERNEL;
if (sht->unchecked_isa_dma && privsize)
gfp_mask |= __GFP_DMA;
shost = kzalloc(sizeof(struct Scsi_Host) + privsize, gfp_mask);
if (!shost)
return NULL;
shost->host_lock = &shost->default_lock;
spin_lock_init(shost->host_lock);
shost->shost_state = SHOST_CREATED;
INIT_LIST_HEAD(&shost->__devices);
INIT_LIST_HEAD(&shost->__targets);
INIT_LIST_HEAD(&shost->eh_cmd_q);
INIT_LIST_HEAD(&shost->starved_list);
init_waitqueue_head(&shost->host_wait);
mutex_init(&shost->scan_mutex);
/*
* subtract one because we increment first then return, but we need to
* know what the next host number was before increment
*/
shost->host_no = atomic_inc_return(&scsi_host_next_hn) - 1;
shost->dma_channel = 0xff;
/* These three are default values which can be overridden */
shost->max_channel = 0;
shost->max_id = 8;
shost->max_lun = 8;
/* Give each shost a default transportt */
shost->transportt = &blank_transport_template;
/*
* All drivers right now should be able to handle 12 byte
* commands. Every so often there are requests for 16 byte
* commands, but individual low-level drivers need to certify that
* they actually do something sensible with such commands.
*/
shost->max_cmd_len = 12;
shost->hostt = sht;
shost->this_id = sht->this_id;
shost->can_queue = sht->can_queue;
shost->sg_tablesize = sht->sg_tablesize;
shost->sg_prot_tablesize = sht->sg_prot_tablesize;
shost->cmd_per_lun = sht->cmd_per_lun;
shost->unchecked_isa_dma = sht->unchecked_isa_dma;
shost->use_clustering = sht->use_clustering;
shost->ordered_tag = sht->ordered_tag;
if (sht->supported_mode == MODE_UNKNOWN)
/* means we didn't set it ... default to INITIATOR */
shost->active_mode = MODE_INITIATOR;
else
shost->active_mode = sht->supported_mode;
if (sht->max_host_blocked)
shost->max_host_blocked = sht->max_host_blocked;
else
shost->max_host_blocked = SCSI_DEFAULT_HOST_BLOCKED;
/*
* If the driver imposes no hard sector transfer limit, start at
* machine infinity initially.
*/
if (sht->max_sectors)
shost->max_sectors = sht->max_sectors;
else
shost->max_sectors = SCSI_DEFAULT_MAX_SECTORS;
/*
* assume a 4GB boundary, if not set
*/
if (sht->dma_boundary)
shost->dma_boundary = sht->dma_boundary;
else
shost->dma_boundary = 0xffffffff;
// scsi_host shost_gendev
device_initialize(&shost->shost_gendev);
dev_set_name(&shost->shost_gendev, "host%d", shost->host_no);
shost->shost_gendev.bus = &scsi_bus_type;
shost->shost_gendev.type = &scsi_host_type;
// scsi_host shsot_dev
device_initialize(&shost->shost_dev);
shost->shost_dev.parent = &shost->shost_gendev;
shost->shost_dev.class = &shost_class;
dev_set_name(&shost->shost_dev, "host%d", shost->host_no);
shost->shost_dev.groups = scsi_sysfs_shost_attr_groups;
shost->ehandler = kthread_run(scsi_error_handler, shost,
"scsi_eh_%d", shost->host_no);
if (IS_ERR(shost->ehandler)) {
printk(KERN_WARNING "scsi%d: error handler thread failed to spawn, error = %ld
",
shost->host_no, PTR_ERR(shost->ehandler));
goto fail_kfree;
}
scsi_proc_hostdir_add(shost->hostt);
return shost;
fail_kfree:
kfree(shost);
return NULL;
}
일반적으로 scsi 호스트 어댑터 가 구동 하 는 prob 에서 먼저 scsialloc_host, 그리고 scsiadd_host, 이어서 scsi 호출scan_host 스 캔 scsi 버스.
scsi 버스 스 캔 의 목적 은 프로 토 콜 의 특정 또는 칩 의 특정한 방식 으로 호스트 어댑터 뒤에 걸 려 있 는 목표 노드 와 논리 부 를 탐지 하여 메모리 에 해당 하 는 데이터 구 조 를 구축 하여 시스템 에 추가 하 는 것 입 니 다.
scsi 중간 층 은 가능 한 ID 와 LUN 으로 INQUIRY 명령 을 구성 한 다음 에 이 INQUIRY 명령 을 블록 IO 시스템 에 제출 합 니 다. 후 자 는 최종 적 으로 중간 층 의 정책 루틴 을 호출 하여 SCSI 명령 으로 추출 한 후 scsi 바 텀 구동 의 quuecommand 리 셋 함 수 를 호출 합 니 다.
int scsi_add_host_with_dma(struct Scsi_Host *shost, struct device *dev,
struct device *dma_dev)
{
struct scsi_host_template *sht = shost->hostt;
int error = -EINVAL;
printk(KERN_INFO "scsi%d : %s
", shost->host_no,
sht->info ? sht->info(shost) : sht->name);
if (!shost->can_queue) {
printk(KERN_ERR "%s: can_queue = 0 no longer supported
",
sht->name);
goto fail;
}
error = scsi_setup_command_freelist(shost); // scsi
if (error)
goto fail;
if (!shost->shost_gendev.parent)
shost->shost_gendev.parent = dev ? dev : &platform_bus;
shost->dma_dev = dma_dev;
error = device_add(&shost->shost_gendev); //
if (error)
goto out;
pm_runtime_set_active(&shost->shost_gendev);
pm_runtime_enable(&shost->shost_gendev);
device_enable_async_suspend(&shost->shost_gendev);
scsi_host_set_state(shost, SHOST_RUNNING);
get_device(shost->shost_gendev.parent);
device_enable_async_suspend(&shost->shost_dev);
error = device_add(&shost->shost_dev); //
if (error)
goto out_del_gendev;
get_device(&shost->shost_gendev);
if (shost->transportt->host_size) {
shost->shost_data = kzalloc(shost->transportt->host_size,
GFP_KERNEL);
if (shost->shost_data == NULL) {
error = -ENOMEM;
goto out_del_dev;
}
}
if (shost->transportt->create_work_queue) {
snprintf(shost->work_q_name, sizeof(shost->work_q_name),
"scsi_wq_%d", shost->host_no);
shost->work_q = create_singlethread_workqueue(
shost->work_q_name);
if (!shost->work_q) {
error = -EINVAL;
goto out_free_shost_data;
}
}
error = scsi_sysfs_add_host(shost);
if (error)
goto out_destroy_host;
scsi_proc_host_add(shost);
return error;
out_destroy_host:
if (shost->work_q)
destroy_workqueue(shost->work_q);
out_free_shost_data:
kfree(shost->shost_data);
out_del_dev:
device_del(&shost->shost_dev);
out_del_gendev:
device_del(&shost->shost_gendev);
out:
scsi_destroy_command_freelist(shost);
fail:
return error;
}
void scsi_scan_host(struct Scsi_Host *shost)
{
struct task_struct *p;
struct async_scan_data *data;
if (strncmp(scsi_scan_type, "none", 4) == 0)
return;
if (scsi_autopm_get_host(shost) < 0)
return;
data = scsi_prep_async_scan(shost);
if (!data) {
do_scsi_scan_host(shost); //
scsi_autopm_put_host(shost);
return;
}
p = kthread_run(do_scan_async, data, "scsi_scan_%d", shost->host_no);
if (IS_ERR(p))
do_scan_async(data);
/* scsi_autopm_put_host(shost) is called in do_scan_async() */
}
static void do_scsi_scan_host(struct Scsi_Host *shost)
{
if (shost->hostt->scan_finished) { //
unsigned long start = jiffies;
if (shost->hostt->scan_start)
shost->hostt->scan_start(shost);
while (!shost->hostt->scan_finished(shost, jiffies - start))
msleep(10);
} else {
scsi_scan_host_selected(shost, SCAN_WILD_CARD, SCAN_WILD_CARD,
SCAN_WILD_CARD, 0); //
}
}
int scsi_scan_host_selected(struct Scsi_Host *shost, unsigned int channel,
unsigned int id, unsigned int lun, int rescan)
{
SCSI_LOG_SCAN_BUS(3, shost_printk (KERN_INFO, shost,
"%s:
",
__func__, channel, id, lun));
if (((channel != SCAN_WILD_CARD) && (channel > shost->max_channel)) ||
((id != SCAN_WILD_CARD) && (id >= shost->max_id)) ||
((lun != SCAN_WILD_CARD) && (lun > shost->max_lun)))
return -EINVAL;
mutex_lock(&shost->scan_mutex);
if (!shost->async_scan)
scsi_complete_async_scans();
if (scsi_host_scan_allowed(shost) && scsi_autopm_get_host(shost) == 0) {
if (channel == SCAN_WILD_CARD)
for (channel = 0; channel <= shost->max_channel;
channel++) //
scsi_scan_channel(shost, channel, id, lun,
rescan);
else
scsi_scan_channel(shost, channel, id, lun, rescan);
scsi_autopm_put_host(shost);
}
mutex_unlock(&shost->scan_mutex);
return 0;
}
static void scsi_scan_channel(struct Scsi_Host *shost, unsigned int channel,
unsigned int id, unsigned int lun, int rescan)
{
uint order_id;
if (id == SCAN_WILD_CARD) //
for (id = 0; id < shost->max_id; ++id) {
/*
* XXX adapter drivers when possible (FCP, iSCSI)
* could modify max_id to match the current max,
* not the absolute max.
*
* XXX add a shost id iterator, so for example,
* the FC ID can be the same as a target id
* without a huge overhead of sparse id's.
*/
if (shost->reverse_ordering)
/*
* Scan from high to low id.
*/
order_id = shost->max_id - id - 1;
else
order_id = id;
__scsi_scan_target(&shost->shost_gendev, channel,
order_id, lun, rescan);
}
else
__scsi_scan_target(&shost->shost_gendev, channel,
id, lun, rescan);
}
scsi_probe_and_add_lun 함 수 는 두 가지 과정 으로 나 뉜 다.SCSI INQUIRY 명령 탐지 논리 장치 보 내기 (scsi probe lun)
응답 이 논리 장치 가 존재 하고 유효 하 다 는 것 을 나타 내 면 시스템 에 추가 합 니 다 (scsi add lun)
scsi probe lun 과 scsi add lun 은 더 이상 분석 하지 않 고 코드 를 볼 수 있 습 니 다.
3. scsi 로 disk 를 예 로 들 어 scsi 고 층 구동 을 설명 합 니 다.
module init (init sd); 함수 가 초기 화 되면 scsi 버스 에서 scsi device 와 scsi driver 의 일치 가 실 행 됩 니 다.
static void __scsi_scan_target(struct device *parent, unsigned int channel,
unsigned int id, unsigned int lun, int rescan)
{
struct Scsi_Host *shost = dev_to_shost(parent);
int bflags = 0;
int res;
struct scsi_target *starget;
if (shost->this_id == id)
/*
* Don't scan the host adapter
*/
return;
starget = scsi_alloc_target(parent, channel, id);
if (!starget)
return;
scsi_autopm_get_target(starget);
if (lun != SCAN_WILD_CARD) {
/*
* Scan for a specific host/chan/id/lun.
*/
scsi_probe_and_add_lun(starget, lun, NULL, NULL, rescan, NULL);
goto out_reap;
}
/*
* Scan LUN 0, if there is some response, scan further. Ideally, we
* would not configure LUN 0 until all LUNs are scanned.
*/
// LUN0, LUN0 INQUIRY
res = scsi_probe_and_add_lun(starget, 0, &bflags, NULL, rescan, NULL);
if (res == SCSI_SCAN_LUN_PRESENT || res == SCSI_SCAN_TARGET_PRESENT) {
// LUN0 , lun
if (scsi_report_lun_scan(starget, bflags, rescan) != 0) // lun0 report lun
/*
* The REPORT LUN did not scan the target,
* do a sequential scan.
*/
// , 1 ,
scsi_sequential_lun_scan(starget, bflags,
starget->scsi_level, rescan);
}
out_reap:
scsi_autopm_put_target(starget);
/* now determine if the target has any children at all
* and if not, nuke it */
scsi_target_reap(starget);
put_device(&starget->dev);
}
4. 567913. 사실은 말하자면 scsi device 와 일치 하고 이 scsi 장치 의 유형 도 메 인 이 scsi disk 일 때 sd probe 를 촉발 하여 scsi disk 구조 와 gendisk 구 조 를 분배 한 다음 에 위 (gendisk) 와 아래 (scsi device) 의 관 계 를 구축한다. 커 널 의 대부분 구동 원 리 는 이와 같 고 각 층 간 의 관 계 를 구축한다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
u - boot 2 단계 빗질 시작\ #define DECLARE_GLOBAL_DATA_PTR register volatile gd_t * gd asm ("r8") 설명: register 를 통 해 레지스터 변 수 를 표시 하고, asm ("r8")...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.