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,&NBSP;PRINTK ("init_sd: sd driver entry point\n"));for (i = 0; i < sd_majors; i++) Register driver 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) &NBSP;{PRINTK (kern_err "Sd: can ' t init extended cdb pool\n"); goto err_out_ Cache;} register the drive err = scsi_register_driver on the SCSI bus (&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
Scsi_disk and Scsi_device can be obtained from Gendisk
struct Gendisk *disk
struct Scsi_disk *SDKP = scsi_disk (disk);
struct Scsi_device *SDP = sdkp->device;
Some interface functions:
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_devicescsi_sysfs.cstatic Ssize_tstore_rescan_field (struct device *dev, struct device_attribute *attr, con St 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 ();p RINTK (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 ();p RINTK (kern_err "SCSI subsystem failed to initialize, error =%d\n" ,-error); return error;}
Interface functions:
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 is any pending requests.
* May is used to restart request handling after a request have completed.
* This variant runs the ' queue whether or not ' the queue has been
* Stopped. Must is 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
* 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 has 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
* 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 was 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 being 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);
The CMD is routed through the host. such as 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_tstore_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,&NBSP;BUF);if (res == 0) res = count;return res;}; Static int scsi_scan (struct scsi_host *shost, const char *str) {CHAR&NBSP;S1 [15], s2[15], s3[15], junk;unsigned int channel, id, lun;int res;res &NBSP;=&NBSP;SSCANF (str, "%10s %10s %10s %c", s1, s2, s3, &junk); if (res != 3) return -einval;if (Check_set (&CHANNEL,&NBSP;S1)) return -EINVAL; if (Check_set (&ID,&NBSP;S2)) return -einval;if (Check_set (&lUN,&NBSP;S3)) return -einval;if (Shost->transportt->user_scan) res = shost-> Transportt->user_scan (Shost, channel, id, lun); Elseres = scsi_scan_host_selected ( shost, channel, id, lun, 1); return res;}
Linux SCSI Disk Driver