drivers/s390/block/scm_blk.c

Source file repositories/reference/linux-study-clean/drivers/s390/block/scm_blk.c

File Facts

System
Linux kernel
Corpus path
drivers/s390/block/scm_blk.c
Extension
.c
Size
13610 bytes
Lines
582
Domain
Driver Families
Bucket
drivers/s390
Inferred role
Driver Families: operation-table or driver-model contract
Status
pattern 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

static const struct blk_mq_ops scm_mq_ops = {
	.queue_rq = scm_blk_request,
	.complete = scm_blk_request_done,
	.init_hctx = scm_blk_init_hctx,
	.exit_hctx = scm_blk_exit_hctx,
};

int scm_blk_dev_setup(struct scm_blk_dev *bdev, struct scm_device *scmdev)
{
	struct queue_limits lim = {
		.logical_block_size	= 1 << 12,
	};
	unsigned int devindex;
	int len, ret;

	lim.max_segments = min(scmdev->nr_max_block,
		(unsigned int) (PAGE_SIZE / sizeof(struct aidaw)));
	lim.max_hw_sectors = lim.max_segments << 3; /* 8 * 512 = blk_size */

	devindex = atomic_inc_return(&nr_devices) - 1;
	/* scma..scmz + scmaa..scmzz */
	if (devindex > 701) {
		ret = -ENODEV;
		goto out;
	}

	bdev->scmdev = scmdev;
	bdev->state = SCM_OPER;
	spin_lock_init(&bdev->lock);
	atomic_set(&bdev->queued_reqs, 0);

	bdev->tag_set.ops = &scm_mq_ops;
	bdev->tag_set.cmd_size = sizeof(blk_status_t);
	bdev->tag_set.nr_hw_queues = nr_requests;
	bdev->tag_set.queue_depth = nr_requests_per_io * nr_requests;
	bdev->tag_set.numa_node = NUMA_NO_NODE;

	ret = blk_mq_alloc_tag_set(&bdev->tag_set);
	if (ret)
		goto out;

	bdev->gendisk = blk_mq_alloc_disk(&bdev->tag_set, &lim, scmdev);
	if (IS_ERR(bdev->gendisk)) {
		ret = PTR_ERR(bdev->gendisk);
		goto out_tag;
	}
	bdev->gendisk->private_data = scmdev;
	bdev->gendisk->fops = &scm_blk_devops;
	bdev->gendisk->major = scm_major;
	bdev->gendisk->first_minor = devindex * SCM_NR_PARTS;
	bdev->gendisk->minors = SCM_NR_PARTS;

	len = snprintf(bdev->gendisk->disk_name, DISK_NAME_LEN, "scm");
	if (devindex > 25) {
		len += snprintf(bdev->gendisk->disk_name + len,
				DISK_NAME_LEN - len, "%c",
				'a' + (devindex / 26) - 1);
		devindex = devindex % 26;
	}
	snprintf(bdev->gendisk->disk_name + len, DISK_NAME_LEN - len, "%c",
		 'a' + devindex);

	/* 512 byte sectors */
	set_capacity(bdev->gendisk, scmdev->size >> 9);
	ret = device_add_disk(&scmdev->dev, bdev->gendisk, NULL);
	if (ret)
		goto out_cleanup_disk;

	return 0;

out_cleanup_disk:
	put_disk(bdev->gendisk);
out_tag:
	blk_mq_free_tag_set(&bdev->tag_set);
out:
	atomic_dec(&nr_devices);
	return ret;
}

void scm_blk_dev_cleanup(struct scm_blk_dev *bdev)
{
	del_gendisk(bdev->gendisk);
	put_disk(bdev->gendisk);
	blk_mq_free_tag_set(&bdev->tag_set);
}

void scm_blk_set_available(struct scm_blk_dev *bdev)
{
	unsigned long flags;

Annotation

Implementation Notes