drivers/scsi/hosts.c

Source file repositories/reference/linux-study-clean/drivers/scsi/hosts.c

File Facts

System
Linux kernel
Corpus path
drivers/scsi/hosts.c
Extension
.c
Size
19891 bytes
Lines
770
Domain
Driver Families
Bucket
drivers/scsi
Inferred role
Driver Families: exported/initcall integration point
Status
integration implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

error = device_add(&shost->shost_gendev);
	if (error)
		goto out_disable_runtime_pm;

	scsi_host_set_state(shost, SHOST_RUNNING);
	get_device(shost->shost_gendev.parent);

	device_enable_async_suspend(&shost->shost_dev);

	get_device(&shost->shost_gendev);
	error = device_add(&shost->shost_dev);
	if (error)
		goto out_del_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) {
		shost->work_q = alloc_workqueue(
			"scsi_wq_%d",
			WQ_SYSFS | __WQ_LEGACY | WQ_MEM_RECLAIM | WQ_UNBOUND, 1,
			shost->host_no);

		if (!shost->work_q) {
			error = -EINVAL;
			goto out_del_dev;
		}
	}

	error = scsi_sysfs_add_host(shost);
	if (error)
		goto out_del_dev;

	if (shost->nr_reserved_cmds) {
		shost->pseudo_sdev = scsi_get_pseudo_sdev(shost);
		if (!shost->pseudo_sdev) {
			error = -ENOMEM;
			goto out_del_dev;
		}
	}

	scsi_proc_host_add(shost);
	scsi_autopm_put_host(shost);
	return error;

	/*
	 * Any host allocation in this function will be freed in
	 * scsi_host_dev_release().
	 */
 out_del_dev:
	device_del(&shost->shost_dev);
 out_del_gendev:
	/*
	 * Host state is SHOST_RUNNING so we have to explicitly release
	 * ->shost_dev.
	 */
	put_device(&shost->shost_dev);
	device_del(&shost->shost_gendev);
 out_disable_runtime_pm:
	device_disable_async_suspend(&shost->shost_gendev);
	pm_runtime_disable(&shost->shost_gendev);
	pm_runtime_set_suspended(&shost->shost_gendev);
	pm_runtime_put_noidle(&shost->shost_gendev);
	kref_put(&shost->tagset_refcnt, scsi_mq_free_tags);
 fail:
	return error;
}
EXPORT_SYMBOL(scsi_add_host_with_dma);

static void scsi_host_dev_release(struct device *dev)
{
	struct Scsi_Host *shost = dev_to_shost(dev);
	struct device *parent = dev->parent;

	/* Wait for functions invoked through call_rcu(&scmd->rcu, ...) */
	rcu_barrier();

	if (shost->tmf_work_q)
		destroy_workqueue(shost->tmf_work_q);
	if (shost->ehandler)
		kthread_stop(shost->ehandler);
	if (shost->work_q)
		destroy_workqueue(shost->work_q);

Annotation

Implementation Notes