diff options
author | Stephen Rothwell <sfr@canb.auug.org.au> | 2007-10-11 00:57:26 -0400 |
---|---|---|
committer | Paul Mackerras <paulus@samba.org> | 2007-10-11 06:40:47 -0400 |
commit | b833b481c10cf591b15cc674948cc514e55d3b94 (patch) | |
tree | 6e02bb29bff6eea2716c0b02c0a2779d2b80480c | |
parent | dd9b67ab37d57da67840276d28957498512d4dd8 (diff) |
[POWERPC] iSeries: Move detection of virtual cdroms
Now we will only have entries in the device tree for the actual existing
devices (including their OS/400 properties). This way viocd.c gets all
the information about the devices from the device tree.
Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
Acked-by: Jens Axboe <jens.axboe@oracle.com>
Signed-off-by: Paul Mackerras <paulus@samba.org>
-rw-r--r-- | arch/powerpc/kernel/vio.c | 3 | ||||
-rw-r--r-- | arch/powerpc/platforms/iseries/Makefile | 2 | ||||
-rw-r--r-- | arch/powerpc/platforms/iseries/dt.c | 4 | ||||
-rw-r--r-- | arch/powerpc/platforms/iseries/vio.c | 317 | ||||
-rw-r--r-- | drivers/cdrom/viocd.c | 116 | ||||
-rw-r--r-- | include/asm-powerpc/iseries/vio.h | 24 |
6 files changed, 361 insertions, 105 deletions
diff --git a/arch/powerpc/kernel/vio.c b/arch/powerpc/kernel/vio.c index b7c9e44ef180..cb22a3557c4e 100644 --- a/arch/powerpc/kernel/vio.c +++ b/arch/powerpc/kernel/vio.c | |||
@@ -247,9 +247,6 @@ static int __init vio_bus_init(void) | |||
247 | int err; | 247 | int err; |
248 | struct device_node *node_vroot; | 248 | struct device_node *node_vroot; |
249 | 249 | ||
250 | if (firmware_has_feature(FW_FEATURE_ISERIES)) | ||
251 | iommu_vio_init(); | ||
252 | |||
253 | err = bus_register(&vio_bus_type); | 250 | err = bus_register(&vio_bus_type); |
254 | if (err) { | 251 | if (err) { |
255 | printk(KERN_ERR "failed to register VIO bus\n"); | 252 | printk(KERN_ERR "failed to register VIO bus\n"); |
diff --git a/arch/powerpc/platforms/iseries/Makefile b/arch/powerpc/platforms/iseries/Makefile index 60db509638f1..a65f1b44abf8 100644 --- a/arch/powerpc/platforms/iseries/Makefile +++ b/arch/powerpc/platforms/iseries/Makefile | |||
@@ -7,7 +7,7 @@ obj-y += hvlog.o hvlpconfig.o lpardata.o setup.o dt_mod.o mf.o lpevents.o \ | |||
7 | hvcall.o proc.o htab.o iommu.o misc.o irq.o | 7 | hvcall.o proc.o htab.o iommu.o misc.o irq.o |
8 | obj-$(CONFIG_PCI) += pci.o vpdinfo.o | 8 | obj-$(CONFIG_PCI) += pci.o vpdinfo.o |
9 | obj-$(CONFIG_SMP) += smp.o | 9 | obj-$(CONFIG_SMP) += smp.o |
10 | obj-$(CONFIG_VIOPATH) += viopath.o | 10 | obj-$(CONFIG_VIOPATH) += viopath.o vio.o |
11 | obj-$(CONFIG_MODULES) += ksyms.o | 11 | obj-$(CONFIG_MODULES) += ksyms.o |
12 | 12 | ||
13 | quiet_cmd_dt_strings = DT_STR $@ | 13 | quiet_cmd_dt_strings = DT_STR $@ |
diff --git a/arch/powerpc/platforms/iseries/dt.c b/arch/powerpc/platforms/iseries/dt.c index 9e8a334a518a..84fcee15eb25 100644 --- a/arch/powerpc/platforms/iseries/dt.c +++ b/arch/powerpc/platforms/iseries/dt.c | |||
@@ -381,10 +381,6 @@ static void __init dt_vdevices(struct iseries_flat_dt *dt) | |||
381 | dt_do_vdevice(dt, "viodasd", reg, i, device_type_block, | 381 | dt_do_vdevice(dt, "viodasd", reg, i, device_type_block, |
382 | "IBM,iSeries-viodasd", 1); | 382 | "IBM,iSeries-viodasd", 1); |
383 | reg += HVMAXARCHITECTEDVIRTUALDISKS; | 383 | reg += HVMAXARCHITECTEDVIRTUALDISKS; |
384 | |||
385 | for (i = 0; i < HVMAXARCHITECTEDVIRTUALCDROMS; i++) | ||
386 | dt_do_vdevice(dt, "viocd", reg, i, device_type_block, | ||
387 | "IBM,iSeries-viocd", 1); | ||
388 | reg += HVMAXARCHITECTEDVIRTUALCDROMS; | 384 | reg += HVMAXARCHITECTEDVIRTUALCDROMS; |
389 | 385 | ||
390 | for (i = 0; i < HVMAXARCHITECTEDVIRTUALTAPES; i++) | 386 | for (i = 0; i < HVMAXARCHITECTEDVIRTUALTAPES; i++) |
diff --git a/arch/powerpc/platforms/iseries/vio.c b/arch/powerpc/platforms/iseries/vio.c new file mode 100644 index 000000000000..f61a97441c3d --- /dev/null +++ b/arch/powerpc/platforms/iseries/vio.c | |||
@@ -0,0 +1,317 @@ | |||
1 | /* | ||
2 | * Legacy iSeries specific vio initialisation | ||
3 | * that needs to be built in (not a module). | ||
4 | * | ||
5 | * © Copyright 2007 IBM Corporation | ||
6 | * Author: Stephen Rothwell | ||
7 | * Some parts collected from various other files | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License as | ||
11 | * published by the Free Software Foundation; either version 2 of the | ||
12 | * License, or (at your option) any later version. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, but | ||
15 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
17 | * General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software Foundation, | ||
21 | * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
22 | */ | ||
23 | #include <linux/of.h> | ||
24 | #include <linux/init.h> | ||
25 | #include <linux/gfp.h> | ||
26 | #include <linux/completion.h> | ||
27 | #include <linux/proc_fs.h> | ||
28 | |||
29 | #include <asm/firmware.h> | ||
30 | #include <asm/iseries/vio.h> | ||
31 | #include <asm/iseries/iommu.h> | ||
32 | #include <asm/iseries/hv_types.h> | ||
33 | #include <asm/iseries/hv_lp_event.h> | ||
34 | |||
35 | #define FIRST_VTY 0 | ||
36 | #define NUM_VTYS 1 | ||
37 | #define FIRST_VSCSI (FIRST_VTY + NUM_VTYS) | ||
38 | #define NUM_VSCSIS 1 | ||
39 | #define FIRST_VLAN (FIRST_VSCSI + NUM_VSCSIS) | ||
40 | #define NUM_VLANS HVMAXARCHITECTEDVIRTUALLANS | ||
41 | #define FIRST_VIODASD (FIRST_VLAN + NUM_VLANS) | ||
42 | #define NUM_VIODASDS HVMAXARCHITECTEDVIRTUALDISKS | ||
43 | #define FIRST_VIOCD (FIRST_VIODASD + NUM_VIODASDS) | ||
44 | #define NUM_VIOCDS HVMAXARCHITECTEDVIRTUALCDROMS | ||
45 | #define FIRST_VIOTAPE (FIRST_VIOCD + NUM_VIOCDS) | ||
46 | #define NUM_VIOTAPES HVMAXARCHITECTEDVIRTUALTAPES | ||
47 | |||
48 | static struct property * __init new_property(const char *name, int length, | ||
49 | const void *value) | ||
50 | { | ||
51 | struct property *np = kzalloc(sizeof(*np) + strlen(name) + 1 + length, | ||
52 | GFP_KERNEL); | ||
53 | |||
54 | if (!np) | ||
55 | return NULL; | ||
56 | np->name = (char *)(np + 1); | ||
57 | np->value = np->name + strlen(name) + 1; | ||
58 | strcpy(np->name, name); | ||
59 | memcpy(np->value, value, length); | ||
60 | np->length = length; | ||
61 | return np; | ||
62 | } | ||
63 | |||
64 | static void __init free_property(struct property *np) | ||
65 | { | ||
66 | kfree(np); | ||
67 | } | ||
68 | |||
69 | static struct device_node * __init new_node(const char *path, | ||
70 | struct device_node *parent) | ||
71 | { | ||
72 | struct device_node *np = kzalloc(sizeof(*np), GFP_KERNEL); | ||
73 | |||
74 | if (!np) | ||
75 | return NULL; | ||
76 | np->full_name = kmalloc(strlen(path) + 1, GFP_KERNEL); | ||
77 | if (!np->full_name) { | ||
78 | kfree(np); | ||
79 | return NULL; | ||
80 | } | ||
81 | strcpy(np->full_name, path); | ||
82 | of_node_set_flag(np, OF_DYNAMIC); | ||
83 | kref_init(&np->kref); | ||
84 | np->parent = of_node_get(parent); | ||
85 | return np; | ||
86 | } | ||
87 | |||
88 | static void __init free_node(struct device_node *np) | ||
89 | { | ||
90 | struct property *next; | ||
91 | struct property *prop; | ||
92 | |||
93 | next = np->properties; | ||
94 | while (next) { | ||
95 | prop = next; | ||
96 | next = prop->next; | ||
97 | free_property(prop); | ||
98 | } | ||
99 | of_node_put(np->parent); | ||
100 | kfree(np->full_name); | ||
101 | kfree(np); | ||
102 | } | ||
103 | |||
104 | static int __init add_string_property(struct device_node *np, const char *name, | ||
105 | const char *value) | ||
106 | { | ||
107 | struct property *nprop = new_property(name, strlen(value) + 1, value); | ||
108 | |||
109 | if (!nprop) | ||
110 | return 0; | ||
111 | prom_add_property(np, nprop); | ||
112 | return 1; | ||
113 | } | ||
114 | |||
115 | static int __init add_raw_property(struct device_node *np, const char *name, | ||
116 | int length, const void *value) | ||
117 | { | ||
118 | struct property *nprop = new_property(name, length, value); | ||
119 | |||
120 | if (!nprop) | ||
121 | return 0; | ||
122 | prom_add_property(np, nprop); | ||
123 | return 1; | ||
124 | } | ||
125 | |||
126 | struct viocd_waitevent { | ||
127 | struct completion com; | ||
128 | int rc; | ||
129 | u16 sub_result; | ||
130 | }; | ||
131 | |||
132 | struct cdrom_info { | ||
133 | char rsrcname[10]; | ||
134 | char type[4]; | ||
135 | char model[3]; | ||
136 | }; | ||
137 | |||
138 | static void __init handle_cd_event(struct HvLpEvent *event) | ||
139 | { | ||
140 | struct viocdlpevent *bevent; | ||
141 | struct viocd_waitevent *pwe; | ||
142 | |||
143 | if (!event) | ||
144 | /* Notification that a partition went away! */ | ||
145 | return; | ||
146 | |||
147 | /* First, we should NEVER get an int here...only acks */ | ||
148 | if (hvlpevent_is_int(event)) { | ||
149 | printk(KERN_WARNING "handle_cd_event: got an unexpected int\n"); | ||
150 | if (hvlpevent_need_ack(event)) { | ||
151 | event->xRc = HvLpEvent_Rc_InvalidSubtype; | ||
152 | HvCallEvent_ackLpEvent(event); | ||
153 | } | ||
154 | return; | ||
155 | } | ||
156 | |||
157 | bevent = (struct viocdlpevent *)event; | ||
158 | |||
159 | switch (event->xSubtype & VIOMINOR_SUBTYPE_MASK) { | ||
160 | case viocdgetinfo: | ||
161 | pwe = (struct viocd_waitevent *)event->xCorrelationToken; | ||
162 | pwe->rc = event->xRc; | ||
163 | pwe->sub_result = bevent->sub_result; | ||
164 | complete(&pwe->com); | ||
165 | break; | ||
166 | |||
167 | default: | ||
168 | printk(KERN_WARNING "handle_cd_event: " | ||
169 | "message with unexpected subtype %0x04X!\n", | ||
170 | event->xSubtype & VIOMINOR_SUBTYPE_MASK); | ||
171 | if (hvlpevent_need_ack(event)) { | ||
172 | event->xRc = HvLpEvent_Rc_InvalidSubtype; | ||
173 | HvCallEvent_ackLpEvent(event); | ||
174 | } | ||
175 | } | ||
176 | } | ||
177 | |||
178 | static void __init get_viocd_info(struct device_node *vio_root) | ||
179 | { | ||
180 | HvLpEvent_Rc hvrc; | ||
181 | u32 unit; | ||
182 | struct viocd_waitevent we; | ||
183 | struct cdrom_info *unitinfo; | ||
184 | dma_addr_t unitinfo_dmaaddr; | ||
185 | int ret; | ||
186 | |||
187 | ret = viopath_open(viopath_hostLp, viomajorsubtype_cdio, 2); | ||
188 | if (ret) { | ||
189 | printk(KERN_WARNING | ||
190 | "get_viocd_info: error opening path to host partition %d\n", | ||
191 | viopath_hostLp); | ||
192 | return; | ||
193 | } | ||
194 | |||
195 | /* Initialize our request handler */ | ||
196 | vio_setHandler(viomajorsubtype_cdio, handle_cd_event); | ||
197 | |||
198 | unitinfo = iseries_hv_alloc( | ||
199 | sizeof(*unitinfo) * HVMAXARCHITECTEDVIRTUALCDROMS, | ||
200 | &unitinfo_dmaaddr, GFP_ATOMIC); | ||
201 | if (!unitinfo) { | ||
202 | printk(KERN_WARNING | ||
203 | "get_viocd_info: error allocating unitinfo\n"); | ||
204 | goto clear_handler; | ||
205 | } | ||
206 | |||
207 | memset(unitinfo, 0, sizeof(*unitinfo) * HVMAXARCHITECTEDVIRTUALCDROMS); | ||
208 | |||
209 | init_completion(&we.com); | ||
210 | |||
211 | hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, | ||
212 | HvLpEvent_Type_VirtualIo, | ||
213 | viomajorsubtype_cdio | viocdgetinfo, | ||
214 | HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck, | ||
215 | viopath_sourceinst(viopath_hostLp), | ||
216 | viopath_targetinst(viopath_hostLp), | ||
217 | (u64)&we, VIOVERSION << 16, unitinfo_dmaaddr, 0, | ||
218 | sizeof(*unitinfo) * HVMAXARCHITECTEDVIRTUALCDROMS, 0); | ||
219 | if (hvrc != HvLpEvent_Rc_Good) { | ||
220 | printk(KERN_WARNING | ||
221 | "get_viocd_info: cdrom error sending event. rc %d\n", | ||
222 | (int)hvrc); | ||
223 | goto hv_free; | ||
224 | } | ||
225 | |||
226 | wait_for_completion(&we.com); | ||
227 | |||
228 | if (we.rc) { | ||
229 | printk(KERN_WARNING "get_viocd_info: bad rc %d:0x%04X\n", | ||
230 | we.rc, we.sub_result); | ||
231 | goto hv_free; | ||
232 | } | ||
233 | |||
234 | for (unit = 0; (unit < HVMAXARCHITECTEDVIRTUALCDROMS) && | ||
235 | unitinfo[unit].rsrcname[0]; unit++) { | ||
236 | struct device_node *np; | ||
237 | char name[64]; | ||
238 | u32 reg = FIRST_VIOCD + unit; | ||
239 | |||
240 | snprintf(name, sizeof(name), "/vdevice/viocd@%08x", reg); | ||
241 | np = new_node(name, vio_root); | ||
242 | if (!np) | ||
243 | goto hv_free; | ||
244 | if (!add_string_property(np, "name", "viocd") || | ||
245 | !add_string_property(np, "device_type", "block") || | ||
246 | !add_string_property(np, "compatible", | ||
247 | "IBM,iSeries-viocd") || | ||
248 | !add_raw_property(np, "reg", sizeof(reg), ®) || | ||
249 | !add_raw_property(np, "linux,unit_address", | ||
250 | sizeof(unit), &unit) || | ||
251 | !add_raw_property(np, "linux,vio_rsrcname", | ||
252 | sizeof(unitinfo[unit].rsrcname), | ||
253 | unitinfo[unit].rsrcname) || | ||
254 | !add_raw_property(np, "linux,vio_type", | ||
255 | sizeof(unitinfo[unit].type), | ||
256 | unitinfo[unit].type) || | ||
257 | !add_raw_property(np, "linux,vio_model", | ||
258 | sizeof(unitinfo[unit].model), | ||
259 | unitinfo[unit].model)) | ||
260 | goto node_free; | ||
261 | np->name = of_get_property(np, "name", NULL); | ||
262 | np->type = of_get_property(np, "device_type", NULL); | ||
263 | of_attach_node(np); | ||
264 | #ifdef CONFIG_PROC_DEVICETREE | ||
265 | if (vio_root->pde) { | ||
266 | struct proc_dir_entry *ent; | ||
267 | |||
268 | ent = proc_mkdir(strrchr(np->full_name, '/') + 1, | ||
269 | vio_root->pde); | ||
270 | if (ent) | ||
271 | proc_device_tree_add_node(np, ent); | ||
272 | } | ||
273 | #endif | ||
274 | continue; | ||
275 | |||
276 | node_free: | ||
277 | free_node(np); | ||
278 | break; | ||
279 | } | ||
280 | |||
281 | hv_free: | ||
282 | iseries_hv_free(sizeof(*unitinfo) * HVMAXARCHITECTEDVIRTUALCDROMS, | ||
283 | unitinfo, unitinfo_dmaaddr); | ||
284 | clear_handler: | ||
285 | vio_clearHandler(viomajorsubtype_cdio); | ||
286 | viopath_close(viopath_hostLp, viomajorsubtype_cdio, 2); | ||
287 | } | ||
288 | |||
289 | static int __init iseries_vio_init(void) | ||
290 | { | ||
291 | struct device_node *vio_root; | ||
292 | |||
293 | if (!firmware_has_feature(FW_FEATURE_ISERIES)) | ||
294 | return -ENODEV; | ||
295 | |||
296 | iommu_vio_init(); | ||
297 | |||
298 | vio_root = of_find_node_by_path("/vdevice"); | ||
299 | if (!vio_root) | ||
300 | return -ENODEV; | ||
301 | |||
302 | if (viopath_hostLp == HvLpIndexInvalid) { | ||
303 | vio_set_hostlp(); | ||
304 | /* If we don't have a host, bail out */ | ||
305 | if (viopath_hostLp == HvLpIndexInvalid) | ||
306 | goto put_node; | ||
307 | } | ||
308 | |||
309 | get_viocd_info(vio_root); | ||
310 | |||
311 | return 0; | ||
312 | |||
313 | put_node: | ||
314 | of_node_put(vio_root); | ||
315 | return -ENODEV; | ||
316 | } | ||
317 | arch_initcall(iseries_vio_init); | ||
diff --git a/drivers/cdrom/viocd.c b/drivers/cdrom/viocd.c index c081e5400ce0..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 | ||
59 | struct 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 | |||
73 | enum 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,17 +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 */ |
132 | static int viocd_numdev; | 108 | static int viocd_numdev; |
133 | 109 | ||
134 | struct cdrom_info { | ||
135 | char rsrcname[10]; | ||
136 | char type[4]; | ||
137 | char model[3]; | ||
138 | }; | ||
139 | |||
140 | struct disk_info { | 110 | struct disk_info { |
141 | struct gendisk *viocd_disk; | 111 | struct gendisk *viocd_disk; |
142 | struct cdrom_device_info viocd_info; | 112 | struct cdrom_device_info viocd_info; |
143 | struct device *dev; | 113 | struct device *dev; |
144 | struct cdrom_info unitinfo; | 114 | const char *rsrcname; |
115 | const char *type; | ||
116 | const char *model; | ||
145 | }; | 117 | }; |
146 | static struct disk_info viocd_diskinfo[VIOCD_MAX_CD]; | 118 | static struct disk_info viocd_diskinfo[VIOCD_MAX_CD]; |
147 | 119 | ||
@@ -159,9 +131,9 @@ static int proc_viocd_show(struct seq_file *m, void *v) | |||
159 | for (i = 0; i < viocd_numdev; i++) { | 131 | for (i = 0; i < viocd_numdev; i++) { |
160 | seq_printf(m, "viocd device %d is iSeries resource %10.10s" | 132 | seq_printf(m, "viocd device %d is iSeries resource %10.10s" |
161 | "type %4.4s, model %3.3s\n", | 133 | "type %4.4s, model %3.3s\n", |
162 | i, viocd_diskinfo[i].unitinfo.rsrcname, | 134 | i, viocd_diskinfo[i].rsrcname, |
163 | viocd_diskinfo[i].unitinfo.type, | 135 | viocd_diskinfo[i].type, |
164 | viocd_diskinfo[i].unitinfo.model); | 136 | viocd_diskinfo[i].model); |
165 | } | 137 | } |
166 | return 0; | 138 | return 0; |
167 | } | 139 | } |
@@ -211,61 +183,6 @@ struct block_device_operations viocd_fops = { | |||
211 | .media_changed = viocd_blk_media_changed, | 183 | .media_changed = viocd_blk_media_changed, |
212 | }; | 184 | }; |
213 | 185 | ||
214 | /* Get info on CD devices from OS/400 */ | ||
215 | static void __init get_viocd_info(void) | ||
216 | { | ||
217 | HvLpEvent_Rc hvrc; | ||
218 | int i; | ||
219 | struct viocd_waitevent we; | ||
220 | struct cdrom_info *viocd_unitinfo; | ||
221 | dma_addr_t unitinfo_dmaaddr; | ||
222 | |||
223 | viocd_unitinfo = iseries_hv_alloc( | ||
224 | sizeof(*viocd_unitinfo) * VIOCD_MAX_CD, | ||
225 | &unitinfo_dmaaddr, GFP_ATOMIC); | ||
226 | if (viocd_unitinfo == NULL) { | ||
227 | printk(VIOCD_KERN_WARNING "error allocating unitinfo\n"); | ||
228 | return; | ||
229 | } | ||
230 | |||
231 | memset(viocd_unitinfo, 0, sizeof(*viocd_unitinfo) * VIOCD_MAX_CD); | ||
232 | |||
233 | init_completion(&we.com); | ||
234 | |||
235 | hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, | ||
236 | HvLpEvent_Type_VirtualIo, | ||
237 | viomajorsubtype_cdio | viocdgetinfo, | ||
238 | HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck, | ||
239 | viopath_sourceinst(viopath_hostLp), | ||
240 | viopath_targetinst(viopath_hostLp), | ||
241 | (u64)&we, VIOVERSION << 16, unitinfo_dmaaddr, 0, | ||
242 | sizeof(*viocd_unitinfo) * VIOCD_MAX_CD, 0); | ||
243 | if (hvrc != HvLpEvent_Rc_Good) { | ||
244 | printk(VIOCD_KERN_WARNING "cdrom error sending event. rc %d\n", | ||
245 | (int)hvrc); | ||
246 | goto error_ret; | ||
247 | } | ||
248 | |||
249 | wait_for_completion(&we.com); | ||
250 | |||
251 | if (we.rc) { | ||
252 | const struct vio_error_entry *err = | ||
253 | vio_lookup_rc(viocd_err_table, we.sub_result); | ||
254 | printk(VIOCD_KERN_WARNING "bad rc %d:0x%04X on getinfo: %s\n", | ||
255 | we.rc, we.sub_result, err->msg); | ||
256 | goto error_ret; | ||
257 | } | ||
258 | |||
259 | for (i = 0; (i < VIOCD_MAX_CD) && viocd_unitinfo[i].rsrcname[0]; i++) { | ||
260 | viocd_diskinfo[viocd_numdev].unitinfo = viocd_unitinfo[i]; | ||
261 | viocd_numdev++; | ||
262 | } | ||
263 | |||
264 | error_ret: | ||
265 | iseries_hv_free(sizeof(*viocd_unitinfo) * VIOCD_MAX_CD, | ||
266 | viocd_unitinfo, unitinfo_dmaaddr); | ||
267 | } | ||
268 | |||
269 | static int viocd_open(struct cdrom_device_info *cdi, int purpose) | 186 | static int viocd_open(struct cdrom_device_info *cdi, int purpose) |
270 | { | 187 | { |
271 | struct disk_info *diskinfo = cdi->handle; | 188 | struct disk_info *diskinfo = cdi->handle; |
@@ -576,7 +493,6 @@ static void vio_handle_cd_event(struct HvLpEvent *event) | |||
576 | bevent->block_size / 512); | 493 | bevent->block_size / 512); |
577 | } | 494 | } |
578 | /* FALLTHROUGH !! */ | 495 | /* FALLTHROUGH !! */ |
579 | case viocdgetinfo: | ||
580 | case viocdlockdoor: | 496 | case viocdlockdoor: |
581 | pwe = (struct viocd_waitevent *)event->xCorrelationToken; | 497 | pwe = (struct viocd_waitevent *)event->xCorrelationToken; |
582 | return_complete: | 498 | return_complete: |
@@ -660,22 +576,30 @@ static int viocd_probe(struct vio_dev *vdev, const struct vio_device_id *id) | |||
660 | int deviceno; | 576 | int deviceno; |
661 | struct disk_info *d; | 577 | struct disk_info *d; |
662 | struct cdrom_device_info *c; | 578 | struct cdrom_device_info *c; |
663 | struct cdrom_info *ci; | ||
664 | struct request_queue *q; | 579 | struct request_queue *q; |
580 | struct device_node *node = vdev->dev.archdata.of_node; | ||
665 | 581 | ||
666 | deviceno = vdev->unit_address; | 582 | deviceno = vdev->unit_address; |
667 | if (deviceno >= viocd_numdev) | 583 | if (deviceno > VIOCD_MAX_CD) |
668 | return -ENODEV; | 584 | return -ENODEV; |
585 | if (!node) | ||
586 | return -ENODEV; | ||
587 | |||
588 | if (deviceno >= viocd_numdev) | ||
589 | viocd_numdev = deviceno + 1; | ||
669 | 590 | ||
670 | 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 | |||
671 | c = &d->viocd_info; | 596 | c = &d->viocd_info; |
672 | ci = &d->unitinfo; | ||
673 | 597 | ||
674 | c->ops = &viocd_dops; | 598 | c->ops = &viocd_dops; |
675 | c->speed = 4; | 599 | c->speed = 4; |
676 | c->capacity = 1; | 600 | c->capacity = 1; |
677 | c->handle = d; | 601 | c->handle = d; |
678 | c->mask = ~find_capability(ci->type); | 602 | c->mask = ~find_capability(d->type); |
679 | sprintf(c->name, VIOCD_DEVICE "%c", 'a' + deviceno); | 603 | sprintf(c->name, VIOCD_DEVICE "%c", 'a' + deviceno); |
680 | 604 | ||
681 | if (register_cdrom(c) != 0) { | 605 | if (register_cdrom(c) != 0) { |
@@ -685,7 +609,7 @@ static int viocd_probe(struct vio_dev *vdev, const struct vio_device_id *id) | |||
685 | } | 609 | } |
686 | printk(VIOCD_KERN_INFO "cd %s is iSeries resource %10.10s " | 610 | printk(VIOCD_KERN_INFO "cd %s is iSeries resource %10.10s " |
687 | "type %4.4s, model %3.3s\n", | 611 | "type %4.4s, model %3.3s\n", |
688 | c->name, ci->rsrcname, ci->type, ci->model); | 612 | c->name, d->rsrcname, d->type, d->model); |
689 | q = blk_init_queue(do_viocd_request, &viocd_reqlock); | 613 | q = blk_init_queue(do_viocd_request, &viocd_reqlock); |
690 | if (q == NULL) { | 614 | if (q == NULL) { |
691 | printk(VIOCD_KERN_WARNING "Cannot allocate queue for %s!\n", | 615 | printk(VIOCD_KERN_WARNING "Cannot allocate queue for %s!\n", |
@@ -794,8 +718,6 @@ static int __init viocd_init(void) | |||
794 | /* Initialize our request handler */ | 718 | /* Initialize our request handler */ |
795 | vio_setHandler(viomajorsubtype_cdio, vio_handle_cd_event); | 719 | vio_setHandler(viomajorsubtype_cdio, vio_handle_cd_event); |
796 | 720 | ||
797 | get_viocd_info(); | ||
798 | |||
799 | spin_lock_init(&viocd_reqlock); | 721 | spin_lock_init(&viocd_reqlock); |
800 | 722 | ||
801 | ret = vio_register_driver(&viocd_driver); | 723 | ret = vio_register_driver(&viocd_driver); |
diff --git a/include/asm-powerpc/iseries/vio.h b/include/asm-powerpc/iseries/vio.h index 5a5cd0f0c095..e5a405b8d461 100644 --- a/include/asm-powerpc/iseries/vio.h +++ b/include/asm-powerpc/iseries/vio.h | |||
@@ -51,6 +51,30 @@ | |||
51 | */ | 51 | */ |
52 | #define VIO_MAX_SUBTYPES 8 | 52 | #define VIO_MAX_SUBTYPES 8 |
53 | 53 | ||
54 | struct viocdlpevent { | ||
55 | struct HvLpEvent event; | ||
56 | u32 reserved; | ||
57 | u16 version; | ||
58 | u16 sub_result; | ||
59 | u16 disk; | ||
60 | u16 flags; | ||
61 | u32 token; | ||
62 | u64 offset; /* On open, max number of disks */ | ||
63 | u64 len; /* On open, size of the disk */ | ||
64 | u32 block_size; /* Only set on open */ | ||
65 | u32 media_size; /* Only set on open */ | ||
66 | }; | ||
67 | |||
68 | enum viocdsubtype { | ||
69 | viocdopen = 0x0001, | ||
70 | viocdclose = 0x0002, | ||
71 | viocdread = 0x0003, | ||
72 | viocdwrite = 0x0004, | ||
73 | viocdlockdoor = 0x0005, | ||
74 | viocdgetinfo = 0x0006, | ||
75 | viocdcheck = 0x0007 | ||
76 | }; | ||
77 | |||
54 | /* | 78 | /* |
55 | * Each subtype can register a handler to process their events. | 79 | * Each subtype can register a handler to process their events. |
56 | * The handler must have this interface. | 80 | * The handler must have this interface. |