pcd: cleanup initialization

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

Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
This commit is contained in:
Christoph Hellwig 2021-09-27 15:01:04 -07:00 committed by Jens Axboe
parent 7d8b72aadd
commit af761f277b

View File

@ -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,90 +630,31 @@ 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;
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;
if ((buffer[11] & 2) == 0)
cd->info.mask |= CDC_CD_RW;
if ((buffer[12] & 1) == 0)
cd->info.mask |= CDC_PLAY_AUDIO;
if ((buffer[14] & 1) == 0)
cd->info.mask |= CDC_LOCK;
if ((buffer[14] & 8) == 0)
cd->info.mask |= CDC_OPEN_TRAY;
if ((buffer[14] >> 6) == 0)
cd->info.mask |= CDC_CLOSE_TRAY;
}
}
ret = pcd_atapi(cd, cmd, 18, buffer, "mode sense capabilities");
if (ret)
return ret;
static int pcd_detect(void)
{
int k, unit;
struct pcd_unit *cd;
/* we should now have the cap page */
if ((buffer[11] & 1) == 0)
cd->info.mask |= CDC_CD_R;
if ((buffer[11] & 2) == 0)
cd->info.mask |= CDC_CD_RW;
if ((buffer[12] & 1) == 0)
cd->info.mask |= CDC_PLAY_AUDIO;
if ((buffer[14] & 1) == 0)
cd->info.mask |= CDC_LOCK;
if ((buffer[14] & 8) == 0)
cd->info.mask |= CDC_OPEN_TRAY;
if ((buffer[14] >> 6) == 0)
cd->info.mask |= CDC_CLOSE_TRAY;
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;
return 0;
}
/* 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 pcd_init_unit(struct pcd_unit *cd, bool autoprobe, int port,
int mode, int unit, int protocol, int delay, int ms)
{
struct gendisk *disk;
int ret;
ret = blk_mq_alloc_sq_tag_set(&cd->tag_set, &pcd_mq_ops, 1,
BLK_MQ_F_SHOULD_MERGE);
if (ret)
return ret;
disk = blk_mq_alloc_disk(&cd->tag_set, cd);
if (IS_ERR(disk)) {
ret = PTR_ERR(disk);
goto out_free_tag_set;
}
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];
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 (!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;
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);
return ret;
}
static int __init pcd_init(void)
{
struct pcd_unit *cd;
int unit;
int found = 0, unit;
if (disable)
return -EINVAL;
pcd_init_units();
if (pcd_detect())
return -ENODEV;
/* get the atapi capabilities page */
pcd_probe_capabilities();
if (register_blkdev(major, name)) {
for (unit = 0, cd = pcd; unit < PCD_UNITS; unit++, cd++) {
if (!cd->disk)
continue;
blk_cleanup_queue(cd->disk->queue);
blk_mq_free_tag_set(&cd->tag_set);
put_disk(cd->disk);
}
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);
del_gendisk(cd->disk);
pi_release(cd->pi);
unregister_cdrom(&cd->info);
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");