aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/cdrom/viocd.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/cdrom/viocd.c')
-rw-r--r--drivers/cdrom/viocd.c128
1 files changed, 19 insertions, 109 deletions
diff --git a/drivers/cdrom/viocd.c b/drivers/cdrom/viocd.c
index e51550db1575..880b5dce3a62 100644
--- a/drivers/cdrom/viocd.c
+++ b/drivers/cdrom/viocd.c
@@ -56,30 +56,6 @@
56#define VIOCD_KERN_WARNING KERN_WARNING "viocd: " 56#define VIOCD_KERN_WARNING KERN_WARNING "viocd: "
57#define VIOCD_KERN_INFO KERN_INFO "viocd: " 57#define VIOCD_KERN_INFO KERN_INFO "viocd: "
58 58
59struct viocdlpevent {
60 struct HvLpEvent event;
61 u32 reserved;
62 u16 version;
63 u16 sub_result;
64 u16 disk;
65 u16 flags;
66 u32 token;
67 u64 offset; /* On open, max number of disks */
68 u64 len; /* On open, size of the disk */
69 u32 block_size; /* Only set on open */
70 u32 media_size; /* Only set on open */
71};
72
73enum viocdsubtype {
74 viocdopen = 0x0001,
75 viocdclose = 0x0002,
76 viocdread = 0x0003,
77 viocdwrite = 0x0004,
78 viocdlockdoor = 0x0005,
79 viocdgetinfo = 0x0006,
80 viocdcheck = 0x0007
81};
82
83/* 59/*
84 * Should probably make this a module parameter....sigh 60 * Should probably make this a module parameter....sigh
85 */ 61 */
@@ -131,22 +107,13 @@ static struct capability_entry capability_table[] __initdata = {
131/* These are our internal structures for keeping track of devices */ 107/* These are our internal structures for keeping track of devices */
132static int viocd_numdev; 108static int viocd_numdev;
133 109
134struct cdrom_info {
135 char rsrcname[10];
136 char type[4];
137 char model[3];
138};
139/*
140 * This needs to be allocated since it is passed to the
141 * Hypervisor and we may be a module.
142 */
143static struct cdrom_info *viocd_unitinfo;
144static dma_addr_t unitinfo_dmaaddr;
145
146struct disk_info { 110struct disk_info {
147 struct gendisk *viocd_disk; 111 struct gendisk *viocd_disk;
148 struct cdrom_device_info viocd_info; 112 struct cdrom_device_info viocd_info;
149 struct device *dev; 113 struct device *dev;
114 const char *rsrcname;
115 const char *type;
116 const char *model;
150}; 117};
151static struct disk_info viocd_diskinfo[VIOCD_MAX_CD]; 118static struct disk_info viocd_diskinfo[VIOCD_MAX_CD];
152 119
@@ -164,9 +131,9 @@ static int proc_viocd_show(struct seq_file *m, void *v)
164 for (i = 0; i < viocd_numdev; i++) { 131 for (i = 0; i < viocd_numdev; i++) {
165 seq_printf(m, "viocd device %d is iSeries resource %10.10s" 132 seq_printf(m, "viocd device %d is iSeries resource %10.10s"
166 "type %4.4s, model %3.3s\n", 133 "type %4.4s, model %3.3s\n",
167 i, viocd_unitinfo[i].rsrcname, 134 i, viocd_diskinfo[i].rsrcname,
168 viocd_unitinfo[i].type, 135 viocd_diskinfo[i].type,
169 viocd_unitinfo[i].model); 136 viocd_diskinfo[i].model);
170 } 137 }
171 return 0; 138 return 0;
172} 139}
@@ -216,61 +183,6 @@ struct block_device_operations viocd_fops = {
216 .media_changed = viocd_blk_media_changed, 183 .media_changed = viocd_blk_media_changed,
217}; 184};
218 185
219/* Get info on CD devices from OS/400 */
220static void __init get_viocd_info(void)
221{
222 HvLpEvent_Rc hvrc;
223 int i;
224 struct viocd_waitevent we;
225
226 viocd_unitinfo = dma_alloc_coherent(iSeries_vio_dev,
227 sizeof(*viocd_unitinfo) * VIOCD_MAX_CD,
228 &unitinfo_dmaaddr, GFP_ATOMIC);
229 if (viocd_unitinfo == NULL) {
230 printk(VIOCD_KERN_WARNING "error allocating unitinfo\n");
231 return;
232 }
233
234 memset(viocd_unitinfo, 0, sizeof(*viocd_unitinfo) * VIOCD_MAX_CD);
235
236 init_completion(&we.com);
237
238 hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
239 HvLpEvent_Type_VirtualIo,
240 viomajorsubtype_cdio | viocdgetinfo,
241 HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck,
242 viopath_sourceinst(viopath_hostLp),
243 viopath_targetinst(viopath_hostLp),
244 (u64)&we, VIOVERSION << 16, unitinfo_dmaaddr, 0,
245 sizeof(*viocd_unitinfo) * VIOCD_MAX_CD, 0);
246 if (hvrc != HvLpEvent_Rc_Good) {
247 printk(VIOCD_KERN_WARNING "cdrom error sending event. rc %d\n",
248 (int)hvrc);
249 goto error_ret;
250 }
251
252 wait_for_completion(&we.com);
253
254 if (we.rc) {
255 const struct vio_error_entry *err =
256 vio_lookup_rc(viocd_err_table, we.sub_result);
257 printk(VIOCD_KERN_WARNING "bad rc %d:0x%04X on getinfo: %s\n",
258 we.rc, we.sub_result, err->msg);
259 goto error_ret;
260 }
261
262 for (i = 0; (i < VIOCD_MAX_CD) && viocd_unitinfo[i].rsrcname[0]; i++)
263 viocd_numdev++;
264
265error_ret:
266 if (viocd_numdev == 0) {
267 dma_free_coherent(iSeries_vio_dev,
268 sizeof(*viocd_unitinfo) * VIOCD_MAX_CD,
269 viocd_unitinfo, unitinfo_dmaaddr);
270 viocd_unitinfo = NULL;
271 }
272}
273
274static int viocd_open(struct cdrom_device_info *cdi, int purpose) 186static int viocd_open(struct cdrom_device_info *cdi, int purpose)
275{ 187{
276 struct disk_info *diskinfo = cdi->handle; 188 struct disk_info *diskinfo = cdi->handle;
@@ -581,7 +493,6 @@ static void vio_handle_cd_event(struct HvLpEvent *event)
581 bevent->block_size / 512); 493 bevent->block_size / 512);
582 } 494 }
583 /* FALLTHROUGH !! */ 495 /* FALLTHROUGH !! */
584 case viocdgetinfo:
585 case viocdlockdoor: 496 case viocdlockdoor:
586 pwe = (struct viocd_waitevent *)event->xCorrelationToken; 497 pwe = (struct viocd_waitevent *)event->xCorrelationToken;
587return_complete: 498return_complete:
@@ -665,22 +576,30 @@ static int viocd_probe(struct vio_dev *vdev, const struct vio_device_id *id)
665 int deviceno; 576 int deviceno;
666 struct disk_info *d; 577 struct disk_info *d;
667 struct cdrom_device_info *c; 578 struct cdrom_device_info *c;
668 struct cdrom_info *ci;
669 struct request_queue *q; 579 struct request_queue *q;
580 struct device_node *node = vdev->dev.archdata.of_node;
670 581
671 deviceno = vdev->unit_address; 582 deviceno = vdev->unit_address;
672 if (deviceno >= viocd_numdev) 583 if (deviceno > VIOCD_MAX_CD)
673 return -ENODEV; 584 return -ENODEV;
585 if (!node)
586 return -ENODEV;
587
588 if (deviceno >= viocd_numdev)
589 viocd_numdev = deviceno + 1;
674 590
675 d = &viocd_diskinfo[deviceno]; 591 d = &viocd_diskinfo[deviceno];
592 d->rsrcname = of_get_property(node, "linux,vio_rsrcname", NULL);
593 d->type = of_get_property(node, "linux,vio_type", NULL);
594 d->model = of_get_property(node, "linux,vio_model", NULL);
595
676 c = &d->viocd_info; 596 c = &d->viocd_info;
677 ci = &viocd_unitinfo[deviceno];
678 597
679 c->ops = &viocd_dops; 598 c->ops = &viocd_dops;
680 c->speed = 4; 599 c->speed = 4;
681 c->capacity = 1; 600 c->capacity = 1;
682 c->handle = d; 601 c->handle = d;
683 c->mask = ~find_capability(ci->type); 602 c->mask = ~find_capability(d->type);
684 sprintf(c->name, VIOCD_DEVICE "%c", 'a' + deviceno); 603 sprintf(c->name, VIOCD_DEVICE "%c", 'a' + deviceno);
685 604
686 if (register_cdrom(c) != 0) { 605 if (register_cdrom(c) != 0) {
@@ -690,7 +609,7 @@ static int viocd_probe(struct vio_dev *vdev, const struct vio_device_id *id)
690 } 609 }
691 printk(VIOCD_KERN_INFO "cd %s is iSeries resource %10.10s " 610 printk(VIOCD_KERN_INFO "cd %s is iSeries resource %10.10s "
692 "type %4.4s, model %3.3s\n", 611 "type %4.4s, model %3.3s\n",
693 c->name, ci->rsrcname, ci->type, ci->model); 612 c->name, d->rsrcname, d->type, d->model);
694 q = blk_init_queue(do_viocd_request, &viocd_reqlock); 613 q = blk_init_queue(do_viocd_request, &viocd_reqlock);
695 if (q == NULL) { 614 if (q == NULL) {
696 printk(VIOCD_KERN_WARNING "Cannot allocate queue for %s!\n", 615 printk(VIOCD_KERN_WARNING "Cannot allocate queue for %s!\n",
@@ -799,8 +718,6 @@ static int __init viocd_init(void)
799 /* Initialize our request handler */ 718 /* Initialize our request handler */
800 vio_setHandler(viomajorsubtype_cdio, vio_handle_cd_event); 719 vio_setHandler(viomajorsubtype_cdio, vio_handle_cd_event);
801 720
802 get_viocd_info();
803
804 spin_lock_init(&viocd_reqlock); 721 spin_lock_init(&viocd_reqlock);
805 722
806 ret = vio_register_driver(&viocd_driver); 723 ret = vio_register_driver(&viocd_driver);
@@ -816,9 +733,6 @@ static int __init viocd_init(void)
816 return 0; 733 return 0;
817 734
818out_free_info: 735out_free_info:
819 dma_free_coherent(iSeries_vio_dev,
820 sizeof(*viocd_unitinfo) * VIOCD_MAX_CD,
821 viocd_unitinfo, unitinfo_dmaaddr);
822 vio_clearHandler(viomajorsubtype_cdio); 736 vio_clearHandler(viomajorsubtype_cdio);
823 viopath_close(viopath_hostLp, viomajorsubtype_cdio, MAX_CD_REQ + 2); 737 viopath_close(viopath_hostLp, viomajorsubtype_cdio, MAX_CD_REQ + 2);
824out_unregister: 738out_unregister:
@@ -830,10 +744,6 @@ static void __exit viocd_exit(void)
830{ 744{
831 remove_proc_entry("iSeries/viocd", NULL); 745 remove_proc_entry("iSeries/viocd", NULL);
832 vio_unregister_driver(&viocd_driver); 746 vio_unregister_driver(&viocd_driver);
833 if (viocd_unitinfo != NULL)
834 dma_free_coherent(iSeries_vio_dev,
835 sizeof(*viocd_unitinfo) * VIOCD_MAX_CD,
836 viocd_unitinfo, unitinfo_dmaaddr);
837 viopath_close(viopath_hostLp, viomajorsubtype_cdio, MAX_CD_REQ + 2); 747 viopath_close(viopath_hostLp, viomajorsubtype_cdio, MAX_CD_REQ + 2);
838 vio_clearHandler(viomajorsubtype_cdio); 748 vio_clearHandler(viomajorsubtype_cdio);
839 unregister_blkdev(VIOCD_MAJOR, VIOCD_DEVICE); 749 unregister_blkdev(VIOCD_MAJOR, VIOCD_DEVICE);