Commit af761f27 authored by Christoph Hellwig's avatar Christoph Hellwig Committed by Jens Axboe
Browse files

pcd: cleanup initialization



Refactor the pcd initialization to have a dedicated helper to initialize
a single disk.

Signed-off-by: default avatarChristoph Hellwig <hch@lst.de>
Signed-off-by: default avatarJens Axboe <axboe@kernel.dk>
parent 7d8b72aa
Loading
Loading
Loading
Loading
+127 −159
Original line number Diff line number Diff line
@@ -183,8 +183,6 @@ static int pcd_audio_ioctl(struct cdrom_device_info *cdi,
static int pcd_packet(struct cdrom_device_info *cdi,
		      struct packet_command *cgc);

static int pcd_detect(void);
static void pcd_probe_capabilities(void);
static void do_pcd_read_drq(void);
static blk_status_t pcd_queue_rq(struct blk_mq_hw_ctx *hctx,
				 const struct blk_mq_queue_data *bd);
@@ -302,53 +300,6 @@ static const struct blk_mq_ops pcd_mq_ops = {
	.queue_rq	= pcd_queue_rq,
};

static void pcd_init_units(void)
{
	struct pcd_unit *cd;
	int unit;

	pcd_drive_count = 0;
	for (unit = 0, cd = pcd; unit < PCD_UNITS; unit++, cd++) {
		struct gendisk *disk;

		if (blk_mq_alloc_sq_tag_set(&cd->tag_set, &pcd_mq_ops, 1,
				BLK_MQ_F_SHOULD_MERGE))
			continue;

		disk = blk_mq_alloc_disk(&cd->tag_set, cd);
		if (IS_ERR(disk)) {
			blk_mq_free_tag_set(&cd->tag_set);
			continue;
		}

		INIT_LIST_HEAD(&cd->rq_list);
		blk_queue_bounce_limit(disk->queue, BLK_BOUNCE_HIGH);
		cd->disk = disk;
		cd->pi = &cd->pia;
		cd->present = 0;
		cd->last_sense = 0;
		cd->changed = 1;
		cd->drive = (*drives[unit])[D_SLV];
		if ((*drives[unit])[D_PRT])
			pcd_drive_count++;

		cd->name = &cd->info.name[0];
		snprintf(cd->name, sizeof(cd->info.name), "%s%d", name, unit);
		cd->info.ops = &pcd_dops;
		cd->info.handle = cd;
		cd->info.speed = 0;
		cd->info.capacity = 1;
		cd->info.mask = 0;
		disk->major = major;
		disk->first_minor = unit;
		disk->minors = 1;
		strcpy(disk->disk_name, cd->name);	/* umm... */
		disk->fops = &pcd_bdops;
		disk->flags = GENHD_FL_BLOCK_EVENTS_ON_EXCL_WRITE;
		disk->events = DISK_EVENT_MEDIA_CHANGE;
	}
}

static int pcd_open(struct cdrom_device_info *cdi, int purpose)
{
	struct pcd_unit *cd = cdi->handle;
@@ -679,19 +630,16 @@ static int pcd_probe(struct pcd_unit *cd, int ms)
	return -1;
}

static void pcd_probe_capabilities(void)
static int pcd_probe_capabilities(struct pcd_unit *cd)
{
	int unit, r;
	char buffer[32];
	char cmd[12] = { 0x5a, 1 << 3, 0x2a, 0, 0, 0, 0, 18, 0, 0, 0, 0 };
	struct pcd_unit *cd;
	char buffer[32];
	int ret;

	ret = pcd_atapi(cd, cmd, 18, buffer, "mode sense capabilities");
	if (ret)
		return ret;

	for (unit = 0, cd = pcd; unit < PCD_UNITS; unit++, cd++) {
		if (!cd->present)
			continue;
		r = pcd_atapi(cd, cmd, 18, buffer, "mode sense capabilities");
		if (r)
			continue;
	/* we should now have the cap page */
	if ((buffer[11] & 1) == 0)
		cd->info.mask |= CDC_CD_R;
@@ -705,64 +653,8 @@ static void pcd_probe_capabilities(void)
		cd->info.mask |= CDC_OPEN_TRAY;
	if ((buffer[14] >> 6) == 0)
		cd->info.mask |= CDC_CLOSE_TRAY;
	}
}

static int pcd_detect(void)
{
	int k, unit;
	struct pcd_unit *cd;

	printk("%s: %s version %s, major %d, nice %d\n",
	       name, name, PCD_VERSION, major, nice);

	par_drv = pi_register_driver(name);
	if (!par_drv) {
		pr_err("failed to register %s driver\n", name);
		return -1;
	}

	k = 0;
	if (pcd_drive_count == 0) { /* nothing spec'd - so autoprobe for 1 */
		cd = pcd;
		if (cd->disk && pi_init(cd->pi, 1, -1, -1, -1, -1, -1,
			    pcd_buffer, PI_PCD, verbose, cd->name)) {
			if (!pcd_probe(cd, -1)) {
				cd->present = 1;
				k++;
			} else
				pi_release(cd->pi);
		}
	} else {
		for (unit = 0, cd = pcd; unit < PCD_UNITS; unit++, cd++) {
			int *conf = *drives[unit];
			if (!conf[D_PRT])
				continue;
			if (!cd->disk)
				continue;
			if (!pi_init(cd->pi, 0, conf[D_PRT], conf[D_MOD],
				     conf[D_UNI], conf[D_PRO], conf[D_DLY],
				     pcd_buffer, PI_PCD, verbose, cd->name)) 
				continue;
			if (!pcd_probe(cd, conf[D_SLV])) {
				cd->present = 1;
				k++;
			} else
				pi_release(cd->pi);
		}
	}
	if (k)
	return 0;

	printk("%s: No CD-ROM drive found\n", name);
	for (unit = 0, cd = pcd; unit < PCD_UNITS; unit++, cd++) {
		if (!cd->disk)
			continue;
		blk_cleanup_disk(cd->disk);
		blk_mq_free_tag_set(&cd->tag_set);
	}
	pi_unregister_driver(par_drv);
	return -1;
}

/* I/O request processing */
@@ -999,43 +891,121 @@ static int pcd_get_mcn(struct cdrom_device_info *cdi, struct cdrom_mcn *mcn)
	return 0;
}

static int __init pcd_init(void)
static int pcd_init_unit(struct pcd_unit *cd, bool autoprobe, int port,
		int mode, int unit, int protocol, int delay, int ms)
{
	struct pcd_unit *cd;
	int unit;
	struct gendisk *disk;
	int ret;

	if (disable)
		return -EINVAL;
	ret = blk_mq_alloc_sq_tag_set(&cd->tag_set, &pcd_mq_ops, 1,
				      BLK_MQ_F_SHOULD_MERGE);
	if (ret)
		return ret;

	pcd_init_units();
	disk = blk_mq_alloc_disk(&cd->tag_set, cd);
	if (IS_ERR(disk)) {
		ret = PTR_ERR(disk);
		goto out_free_tag_set;
	}

	if (pcd_detect())
		return -ENODEV;
	INIT_LIST_HEAD(&cd->rq_list);
	blk_queue_bounce_limit(disk->queue, BLK_BOUNCE_HIGH);
	cd->disk = disk;
	cd->pi = &cd->pia;
	cd->present = 0;
	cd->last_sense = 0;
	cd->changed = 1;
	cd->drive = (*drives[cd - pcd])[D_SLV];

	/* get the atapi capabilities page */
	pcd_probe_capabilities();
	cd->name = &cd->info.name[0];
	snprintf(cd->name, sizeof(cd->info.name), "%s%d", name, unit);
	cd->info.ops = &pcd_dops;
	cd->info.handle = cd;
	cd->info.speed = 0;
	cd->info.capacity = 1;
	cd->info.mask = 0;
	disk->major = major;
	disk->first_minor = unit;
	disk->minors = 1;
	strcpy(disk->disk_name, cd->name);	/* umm... */
	disk->fops = &pcd_bdops;
	disk->flags = GENHD_FL_BLOCK_EVENTS_ON_EXCL_WRITE;
	disk->events = DISK_EVENT_MEDIA_CHANGE;

	if (register_blkdev(major, name)) {
		for (unit = 0, cd = pcd; unit < PCD_UNITS; unit++, cd++) {
			if (!cd->disk)
				continue;
	if (!pi_init(cd->pi, autoprobe, port, mode, unit, protocol, delay,
			pcd_buffer, PI_PCD, verbose, cd->name))
		goto out_free_disk;
	if (pcd_probe(cd, ms))
		goto out_pi_release;

			blk_cleanup_queue(cd->disk->queue);
	cd->present = 1;
	pcd_probe_capabilities(cd);
	register_cdrom(cd->disk, &cd->info);
	add_disk(cd->disk);
	return 0;

out_pi_release:
	pi_release(cd->pi);
out_free_disk:
	blk_cleanup_disk(cd->disk);
out_free_tag_set:
	blk_mq_free_tag_set(&cd->tag_set);
			put_disk(cd->disk);
	return ret;
}

static int __init pcd_init(void)
{
	int found = 0, unit;

	if (disable)
		return -EINVAL;

	if (register_blkdev(major, name))
		return -EBUSY;

	pr_info("%s: %s version %s, major %d, nice %d\n",
		name, name, PCD_VERSION, major, nice);

	par_drv = pi_register_driver(name);
	if (!par_drv) {
		pr_err("failed to register %s driver\n", name);
		goto out_unregister_blkdev;
	}

	for (unit = 0, cd = pcd; unit < PCD_UNITS; unit++, cd++) {
		if (cd->present) {
			register_cdrom(cd->disk, &cd->info);
			cd->disk->private_data = cd;
			add_disk(cd->disk);
	for (unit = 0; unit < PCD_UNITS; unit++) {
		if ((*drives[unit])[D_PRT])
			pcd_drive_count++;
	}

	if (pcd_drive_count == 0) { /* nothing spec'd - so autoprobe for 1 */
		if (!pcd_init_unit(pcd, 1, -1, -1, -1, -1, -1, -1))
			found++;
	} else {
		for (unit = 0; unit < PCD_UNITS; unit++) {
			struct pcd_unit *cd = &pcd[unit];
			int *conf = *drives[unit];

			if (!conf[D_PRT])
				continue;
			if (!pcd_init_unit(cd, 0, conf[D_PRT], conf[D_MOD],
					conf[D_UNI], conf[D_PRO], conf[D_DLY],
					conf[D_SLV]))
				found++;
		}
	}

	if (!found) {
		pr_info("%s: No CD-ROM drive found\n", name);
		goto out_unregister_pi_driver;
	}

	return 0;

out_unregister_pi_driver:
	pi_unregister_driver(par_drv);
out_unregister_blkdev:
	unregister_blkdev(major, name);
	return -ENODEV;
}

static void __exit pcd_exit(void)
@@ -1044,20 +1014,18 @@ static void __exit pcd_exit(void)
	int unit;

	for (unit = 0, cd = pcd; unit < PCD_UNITS; unit++, cd++) {
		if (!cd->disk)
		if (!cd->present)
			continue;

		if (cd->present) {
		del_gendisk(cd->disk);
		pi_release(cd->pi);
		unregister_cdrom(&cd->info);
		}
		blk_cleanup_queue(cd->disk->queue);
		blk_cleanup_disk(cd->disk);

		blk_mq_free_tag_set(&cd->tag_set);
		put_disk(cd->disk);
	}
	unregister_blkdev(major, name);
	pi_unregister_driver(par_drv);
	unregister_blkdev(major, name);
}

MODULE_LICENSE("GPL");