X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=drivers%2Fcdrom%2Fviocd.c;h=13929356135c837743f130c2f7de4d3cd85cc4fb;hb=1393fce7189427bdb4d6115ca5566ca8d0fc86f3;hp=f65597081171c7382f8562f5ba26fa0d1d879e84;hpb=ce7b0f46bbf4bff8daab2dd3d878b9e72a623d09;p=safe%2Fjmp%2Flinux-2.6 diff --git a/drivers/cdrom/viocd.c b/drivers/cdrom/viocd.c index f655970..1392935 100644 --- a/drivers/cdrom/viocd.c +++ b/drivers/cdrom/viocd.c @@ -6,7 +6,7 @@ * Authors: Dave Boutcher * Ryan Arnold * Colin Devilbiss - * Stephen Rothwell + * Stephen Rothwell * * (C) Copyright 2000-2004 IBM Corporation * @@ -41,45 +41,21 @@ #include #include #include +#include #include -#include #include #include #include +#include #define VIOCD_DEVICE "iseries/vcd" -#define VIOCD_DEVICE_DEVFS "iseries/vcd" #define VIOCD_VERS "1.06" #define VIOCD_KERN_WARNING KERN_WARNING "viocd: " #define VIOCD_KERN_INFO KERN_INFO "viocd: " -struct viocdlpevent { - struct HvLpEvent event; - u32 reserved; - u16 version; - u16 sub_result; - u16 disk; - u16 flags; - u32 token; - u64 offset; /* On open, max number of disks */ - u64 len; /* On open, size of the disk */ - u32 block_size; /* Only set on open */ - u32 media_size; /* Only set on open */ -}; - -enum viocdsubtype { - viocdopen = 0x0001, - viocdclose = 0x0002, - viocdread = 0x0003, - viocdwrite = 0x0004, - viocdlockdoor = 0x0005, - viocdgetinfo = 0x0006, - viocdcheck = 0x0007 -}; - /* * Should probably make this a module parameter....sigh */ @@ -131,22 +107,13 @@ static struct capability_entry capability_table[] __initdata = { /* These are our internal structures for keeping track of devices */ static int viocd_numdev; -struct cdrom_info { - char rsrcname[10]; - char type[4]; - char model[3]; -}; -/* - * This needs to be allocated since it is passed to the - * Hypervisor and we may be a module. - */ -static struct cdrom_info *viocd_unitinfo; -static dma_addr_t unitinfo_dmaaddr; - struct disk_info { struct gendisk *viocd_disk; struct cdrom_device_info viocd_info; struct device *dev; + const char *rsrcname; + const char *type; + const char *model; }; static struct disk_info viocd_diskinfo[VIOCD_MAX_CD]; @@ -164,9 +131,9 @@ static int proc_viocd_show(struct seq_file *m, void *v) for (i = 0; i < viocd_numdev; i++) { seq_printf(m, "viocd device %d is iSeries resource %10.10s" "type %4.4s, model %3.3s\n", - i, viocd_unitinfo[i].rsrcname, - viocd_unitinfo[i].type, - viocd_unitinfo[i].model); + i, viocd_diskinfo[i].rsrcname, + viocd_diskinfo[i].type, + viocd_diskinfo[i].model); } return 0; } @@ -176,30 +143,32 @@ static int proc_viocd_open(struct inode *inode, struct file *file) return single_open(file, proc_viocd_show, NULL); } -static struct file_operations proc_viocd_operations = { +static const struct file_operations proc_viocd_operations = { + .owner = THIS_MODULE, .open = proc_viocd_open, .read = seq_read, .llseek = seq_lseek, .release = single_release, }; -static int viocd_blk_open(struct inode *inode, struct file *file) +static int viocd_blk_open(struct block_device *bdev, fmode_t mode) { - struct disk_info *di = inode->i_bdev->bd_disk->private_data; - return cdrom_open(&di->viocd_info, inode, file); + struct disk_info *di = bdev->bd_disk->private_data; + return cdrom_open(&di->viocd_info, bdev, mode); } -static int viocd_blk_release(struct inode *inode, struct file *file) +static int viocd_blk_release(struct gendisk *disk, fmode_t mode) { - struct disk_info *di = inode->i_bdev->bd_disk->private_data; - return cdrom_release(&di->viocd_info, file); + struct disk_info *di = disk->private_data; + cdrom_release(&di->viocd_info, mode); + return 0; } -static int viocd_blk_ioctl(struct inode *inode, struct file *file, +static int viocd_blk_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd, unsigned long arg) { - struct disk_info *di = inode->i_bdev->bd_disk->private_data; - return cdrom_ioctl(file, &di->viocd_info, inode, cmd, arg); + struct disk_info *di = bdev->bd_disk->private_data; + return cdrom_ioctl(&di->viocd_info, bdev, mode, cmd, arg); } static int viocd_blk_media_changed(struct gendisk *disk) @@ -212,65 +181,10 @@ struct block_device_operations viocd_fops = { .owner = THIS_MODULE, .open = viocd_blk_open, .release = viocd_blk_release, - .ioctl = viocd_blk_ioctl, + .locked_ioctl = viocd_blk_ioctl, .media_changed = viocd_blk_media_changed, }; -/* Get info on CD devices from OS/400 */ -static void __init get_viocd_info(void) -{ - HvLpEvent_Rc hvrc; - int i; - struct viocd_waitevent we; - - viocd_unitinfo = dma_alloc_coherent(iSeries_vio_dev, - sizeof(*viocd_unitinfo) * VIOCD_MAX_CD, - &unitinfo_dmaaddr, GFP_ATOMIC); - if (viocd_unitinfo == NULL) { - printk(VIOCD_KERN_WARNING "error allocating unitinfo\n"); - return; - } - - memset(viocd_unitinfo, 0, sizeof(*viocd_unitinfo) * VIOCD_MAX_CD); - - init_completion(&we.com); - - hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, - HvLpEvent_Type_VirtualIo, - viomajorsubtype_cdio | viocdgetinfo, - HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck, - viopath_sourceinst(viopath_hostLp), - viopath_targetinst(viopath_hostLp), - (u64)&we, VIOVERSION << 16, unitinfo_dmaaddr, 0, - sizeof(*viocd_unitinfo) * VIOCD_MAX_CD, 0); - if (hvrc != HvLpEvent_Rc_Good) { - printk(VIOCD_KERN_WARNING "cdrom error sending event. rc %d\n", - (int)hvrc); - goto error_ret; - } - - wait_for_completion(&we.com); - - if (we.rc) { - const struct vio_error_entry *err = - vio_lookup_rc(viocd_err_table, we.sub_result); - printk(VIOCD_KERN_WARNING "bad rc %d:0x%04X on getinfo: %s\n", - we.rc, we.sub_result, err->msg); - goto error_ret; - } - - for (i = 0; (i < VIOCD_MAX_CD) && viocd_unitinfo[i].rsrcname[0]; i++) - viocd_numdev++; - -error_ret: - if (viocd_numdev == 0) { - dma_free_coherent(iSeries_vio_dev, - sizeof(*viocd_unitinfo) * VIOCD_MAX_CD, - viocd_unitinfo, unitinfo_dmaaddr); - viocd_unitinfo = NULL; - } -} - static int viocd_open(struct cdrom_device_info *cdi, int purpose) { struct disk_info *diskinfo = cdi->handle; @@ -346,6 +260,7 @@ static int send_request(struct request *req) cmd = viomajorsubtype_cdio | viocdwrite; } + sg_init_table(&sg, 1); if (blk_rq_map_sg(req->q, req, &sg) == 0) { printk(VIOCD_KERN_WARNING "error setting up scatter/gather list\n"); @@ -376,20 +291,36 @@ static int send_request(struct request *req) return 0; } +static void viocd_end_request(struct request *req, int error) +{ + int nsectors = req->hard_nr_sectors; + + /* + * Make sure it's fully ended, and ensure that we process + * at least one sector. + */ + if (blk_pc_request(req)) + nsectors = (req->data_len + 511) >> 9; + if (!nsectors) + nsectors = 1; + + if (__blk_end_request(req, error, nsectors << 9)) + BUG(); +} static int rwreq; -static void do_viocd_request(request_queue_t *q) +static void do_viocd_request(struct request_queue *q) { struct request *req; while ((rwreq == 0) && ((req = elv_next_request(q)) != NULL)) { if (!blk_fs_request(req)) - end_request(req, 0); + viocd_end_request(req, -EIO); else if (send_request(req) < 0) { printk(VIOCD_KERN_WARNING "unable to send message to OS/400!"); - end_request(req, 0); + viocd_end_request(req, -EIO); } else rwreq++; } @@ -562,7 +493,6 @@ static void vio_handle_cd_event(struct HvLpEvent *event) bevent->block_size / 512); } /* FALLTHROUGH !! */ - case viocdgetinfo: case viocdlockdoor: pwe = (struct viocd_waitevent *)event->xCorrelationToken; return_complete: @@ -601,9 +531,9 @@ return_complete: "with rc %d:0x%04X: %s\n", req, event->xRc, bevent->sub_result, err->msg); - end_request(req, 0); + viocd_end_request(req, -EIO); } else - end_request(req, 1); + viocd_end_request(req, 0); /* restart handling of incoming requests */ spin_unlock_irqrestore(&viocd_reqlock, flags); @@ -621,16 +551,23 @@ return_complete: } } +static int viocd_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, + void *arg) +{ + return -EINVAL; +} + static struct cdrom_device_ops viocd_dops = { .open = viocd_open, .release = viocd_release, .media_changed = viocd_media_changed, .lock_door = viocd_lock_door, .generic_packet = viocd_packet, + .audio_ioctl = viocd_audio_ioctl, .capability = CDC_CLOSE_TRAY | CDC_OPEN_TRAY | CDC_LOCK | CDC_SELECT_SPEED | CDC_SELECT_DISC | CDC_MULTI_SESSION | CDC_MCN | CDC_MEDIA_CHANGED | CDC_PLAY_AUDIO | CDC_RESET | CDC_DRIVE_STATUS | CDC_GENERIC_PACKET | CDC_CD_R | CDC_CD_RW | CDC_DVD | CDC_DVD_R | CDC_DVD_RAM | CDC_RAM }; -static int __init find_capability(const char *type) +static int find_capability(const char *type) { struct capability_entry *entry; @@ -646,22 +583,30 @@ static int viocd_probe(struct vio_dev *vdev, const struct vio_device_id *id) int deviceno; struct disk_info *d; struct cdrom_device_info *c; - struct cdrom_info *ci; struct request_queue *q; + struct device_node *node = vdev->dev.archdata.of_node; deviceno = vdev->unit_address; - if (deviceno >= viocd_numdev) + if (deviceno > VIOCD_MAX_CD) return -ENODEV; + if (!node) + return -ENODEV; + + if (deviceno >= viocd_numdev) + viocd_numdev = deviceno + 1; d = &viocd_diskinfo[deviceno]; + d->rsrcname = of_get_property(node, "linux,vio_rsrcname", NULL); + d->type = of_get_property(node, "linux,vio_type", NULL); + d->model = of_get_property(node, "linux,vio_model", NULL); + c = &d->viocd_info; - ci = &viocd_unitinfo[deviceno]; c->ops = &viocd_dops; c->speed = 4; c->capacity = 1; c->handle = d; - c->mask = ~find_capability(ci->type); + c->mask = ~find_capability(d->type); sprintf(c->name, VIOCD_DEVICE "%c", 'a' + deviceno); if (register_cdrom(c) != 0) { @@ -671,7 +616,7 @@ static int viocd_probe(struct vio_dev *vdev, const struct vio_device_id *id) } printk(VIOCD_KERN_INFO "cd %s is iSeries resource %10.10s " "type %4.4s, model %3.3s\n", - c->name, ci->rsrcname, ci->type, ci->model); + c->name, d->rsrcname, d->type, d->model); q = blk_init_queue(do_viocd_request, &viocd_reqlock); if (q == NULL) { printk(VIOCD_KERN_WARNING "Cannot allocate queue for %s!\n", @@ -714,10 +659,7 @@ static int viocd_remove(struct vio_dev *vdev) { struct disk_info *d = &viocd_diskinfo[vdev->unit_address]; - if (unregister_cdrom(&d->viocd_info) != 0) - printk(VIOCD_KERN_WARNING - "Cannot unregister viocd CD-ROM %s!\n", - d->viocd_info.name); + unregister_cdrom(&d->viocd_info); del_gendisk(d->viocd_disk); blk_cleanup_queue(d->viocd_disk->queue); put_disk(d->viocd_disk); @@ -746,9 +688,11 @@ static struct vio_driver viocd_driver = { static int __init viocd_init(void) { - struct proc_dir_entry *e; int ret = 0; + if (!firmware_has_feature(FW_FEATURE_ISERIES)) + return -ENODEV; + if (viopath_hostLp == HvLpIndexInvalid) { vio_set_hostlp(); /* If we don't have a host, bail out */ @@ -777,26 +721,17 @@ static int __init viocd_init(void) /* Initialize our request handler */ vio_setHandler(viomajorsubtype_cdio, vio_handle_cd_event); - get_viocd_info(); - spin_lock_init(&viocd_reqlock); ret = vio_register_driver(&viocd_driver); if (ret) goto out_free_info; - e = create_proc_entry("iSeries/viocd", S_IFREG|S_IRUGO, NULL); - if (e) { - e->owner = THIS_MODULE; - e->proc_fops = &proc_viocd_operations; - } - + proc_create("iSeries/viocd", S_IFREG|S_IRUGO, NULL, + &proc_viocd_operations); return 0; out_free_info: - dma_free_coherent(iSeries_vio_dev, - sizeof(*viocd_unitinfo) * VIOCD_MAX_CD, - viocd_unitinfo, unitinfo_dmaaddr); vio_clearHandler(viomajorsubtype_cdio); viopath_close(viopath_hostLp, viomajorsubtype_cdio, MAX_CD_REQ + 2); out_unregister: @@ -808,10 +743,6 @@ static void __exit viocd_exit(void) { remove_proc_entry("iSeries/viocd", NULL); vio_unregister_driver(&viocd_driver); - if (viocd_unitinfo != NULL) - dma_free_coherent(iSeries_vio_dev, - sizeof(*viocd_unitinfo) * VIOCD_MAX_CD, - viocd_unitinfo, unitinfo_dmaaddr); viopath_close(viopath_hostLp, viomajorsubtype_cdio, MAX_CD_REQ + 2); vio_clearHandler(viomajorsubtype_cdio); unregister_blkdev(VIOCD_MAJOR, VIOCD_DEVICE);