diff options
author | Stephen Rothwell <sfr@canb.auug.org.au> | 2007-10-11 00:59:54 -0400 |
---|---|---|
committer | Paul Mackerras <paulus@samba.org> | 2007-10-11 06:40:48 -0400 |
commit | 8251b4c481bca72568e9c1042ea11189838e5f6d (patch) | |
tree | 41991f93aec12592885ac33a5312dcf4024ebe5f | |
parent | 7465ce0db310d2fa29f721da7e3aacd1dad7090f (diff) |
[POWERPC] iSeries: Move viodasd probing
This way we only have entries in the device tree for disks that actually
exist. A slight complication is that disks may be attached to LPARs
at runtime.
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/platforms/iseries/dt.c | 6 | ||||
-rw-r--r-- | arch/powerpc/platforms/iseries/vio.c | 301 | ||||
-rw-r--r-- | drivers/block/viodasd.c | 77 | ||||
-rw-r--r-- | include/asm-powerpc/iseries/vio.h | 47 |
4 files changed, 282 insertions, 149 deletions
diff --git a/arch/powerpc/platforms/iseries/dt.c b/arch/powerpc/platforms/iseries/dt.c index 2e4ad6b34506..4543c4bc3a56 100644 --- a/arch/powerpc/platforms/iseries/dt.c +++ b/arch/powerpc/platforms/iseries/dt.c | |||
@@ -72,7 +72,6 @@ static char __initdata device_type_cpu[] = "cpu"; | |||
72 | static char __initdata device_type_memory[] = "memory"; | 72 | static char __initdata device_type_memory[] = "memory"; |
73 | static char __initdata device_type_serial[] = "serial"; | 73 | static char __initdata device_type_serial[] = "serial"; |
74 | static char __initdata device_type_network[] = "network"; | 74 | static char __initdata device_type_network[] = "network"; |
75 | static char __initdata device_type_block[] = "block"; | ||
76 | static char __initdata device_type_pci[] = "pci"; | 75 | static char __initdata device_type_pci[] = "pci"; |
77 | static char __initdata device_type_vdevice[] = "vdevice"; | 76 | static char __initdata device_type_vdevice[] = "vdevice"; |
78 | static char __initdata device_type_vscsi[] = "vscsi"; | 77 | static char __initdata device_type_vscsi[] = "vscsi"; |
@@ -374,11 +373,6 @@ static void __init dt_vdevices(struct iseries_flat_dt *dt) | |||
374 | 373 | ||
375 | dt_end_node(dt); | 374 | dt_end_node(dt); |
376 | } | 375 | } |
377 | reg += HVMAXARCHITECTEDVIRTUALLANS; | ||
378 | |||
379 | for (i = 0; i < HVMAXARCHITECTEDVIRTUALDISKS; i++) | ||
380 | dt_do_vdevice(dt, "viodasd", reg, i, device_type_block, | ||
381 | "IBM,iSeries-viodasd", 1); | ||
382 | 376 | ||
383 | dt_end_node(dt); | 377 | dt_end_node(dt); |
384 | } | 378 | } |
diff --git a/arch/powerpc/platforms/iseries/vio.c b/arch/powerpc/platforms/iseries/vio.c index a4cc990a26a0..910b00b4703e 100644 --- a/arch/powerpc/platforms/iseries/vio.c +++ b/arch/powerpc/platforms/iseries/vio.c | |||
@@ -25,8 +25,10 @@ | |||
25 | #include <linux/gfp.h> | 25 | #include <linux/gfp.h> |
26 | #include <linux/completion.h> | 26 | #include <linux/completion.h> |
27 | #include <linux/proc_fs.h> | 27 | #include <linux/proc_fs.h> |
28 | #include <linux/module.h> | ||
28 | 29 | ||
29 | #include <asm/firmware.h> | 30 | #include <asm/firmware.h> |
31 | #include <asm/vio.h> | ||
30 | #include <asm/iseries/vio.h> | 32 | #include <asm/iseries/vio.h> |
31 | #include <asm/iseries/iommu.h> | 33 | #include <asm/iseries/iommu.h> |
32 | #include <asm/iseries/hv_types.h> | 34 | #include <asm/iseries/hv_types.h> |
@@ -57,7 +59,7 @@ struct vio_resource { | |||
57 | char model[3]; | 59 | char model[3]; |
58 | }; | 60 | }; |
59 | 61 | ||
60 | static struct property * __init new_property(const char *name, int length, | 62 | static struct property *new_property(const char *name, int length, |
61 | const void *value) | 63 | const void *value) |
62 | { | 64 | { |
63 | struct property *np = kzalloc(sizeof(*np) + strlen(name) + 1 + length, | 65 | struct property *np = kzalloc(sizeof(*np) + strlen(name) + 1 + length, |
@@ -78,7 +80,7 @@ static void __init free_property(struct property *np) | |||
78 | kfree(np); | 80 | kfree(np); |
79 | } | 81 | } |
80 | 82 | ||
81 | static struct device_node * __init new_node(const char *path, | 83 | static struct device_node *new_node(const char *path, |
82 | struct device_node *parent) | 84 | struct device_node *parent) |
83 | { | 85 | { |
84 | struct device_node *np = kzalloc(sizeof(*np), GFP_KERNEL); | 86 | struct device_node *np = kzalloc(sizeof(*np), GFP_KERNEL); |
@@ -97,7 +99,7 @@ static struct device_node * __init new_node(const char *path, | |||
97 | return np; | 99 | return np; |
98 | } | 100 | } |
99 | 101 | ||
100 | static void __init free_node(struct device_node *np) | 102 | static void free_node(struct device_node *np) |
101 | { | 103 | { |
102 | struct property *next; | 104 | struct property *next; |
103 | struct property *prop; | 105 | struct property *prop; |
@@ -113,7 +115,7 @@ static void __init free_node(struct device_node *np) | |||
113 | kfree(np); | 115 | kfree(np); |
114 | } | 116 | } |
115 | 117 | ||
116 | static int __init add_string_property(struct device_node *np, const char *name, | 118 | static int add_string_property(struct device_node *np, const char *name, |
117 | const char *value) | 119 | const char *value) |
118 | { | 120 | { |
119 | struct property *nprop = new_property(name, strlen(value) + 1, value); | 121 | struct property *nprop = new_property(name, strlen(value) + 1, value); |
@@ -124,7 +126,7 @@ static int __init add_string_property(struct device_node *np, const char *name, | |||
124 | return 1; | 126 | return 1; |
125 | } | 127 | } |
126 | 128 | ||
127 | static int __init add_raw_property(struct device_node *np, const char *name, | 129 | static int add_raw_property(struct device_node *np, const char *name, |
128 | int length, const void *value) | 130 | int length, const void *value) |
129 | { | 131 | { |
130 | struct property *nprop = new_property(name, length, value); | 132 | struct property *nprop = new_property(name, length, value); |
@@ -135,6 +137,201 @@ static int __init add_raw_property(struct device_node *np, const char *name, | |||
135 | return 1; | 137 | return 1; |
136 | } | 138 | } |
137 | 139 | ||
140 | static struct device_node *do_device_node(struct device_node *parent, | ||
141 | const char *name, u32 reg, u32 unit, const char *type, | ||
142 | const char *compat, struct vio_resource *res) | ||
143 | { | ||
144 | struct device_node *np; | ||
145 | char path[32]; | ||
146 | |||
147 | snprintf(path, sizeof(path), "/vdevice/%s@%08x", name, reg); | ||
148 | np = new_node(path, parent); | ||
149 | if (!np) | ||
150 | return NULL; | ||
151 | if (!add_string_property(np, "name", name) || | ||
152 | !add_string_property(np, "device_type", type) || | ||
153 | !add_string_property(np, "compatible", compat) || | ||
154 | !add_raw_property(np, "reg", sizeof(reg), ®) || | ||
155 | !add_raw_property(np, "linux,unit_address", | ||
156 | sizeof(unit), &unit)) { | ||
157 | goto node_free; | ||
158 | } | ||
159 | if (res) { | ||
160 | if (!add_raw_property(np, "linux,vio_rsrcname", | ||
161 | sizeof(res->rsrcname), res->rsrcname) || | ||
162 | !add_raw_property(np, "linux,vio_type", | ||
163 | sizeof(res->type), res->type) || | ||
164 | !add_raw_property(np, "linux,vio_model", | ||
165 | sizeof(res->model), res->model)) | ||
166 | goto node_free; | ||
167 | } | ||
168 | np->name = of_get_property(np, "name", NULL); | ||
169 | np->type = of_get_property(np, "device_type", NULL); | ||
170 | of_attach_node(np); | ||
171 | #ifdef CONFIG_PROC_DEVICETREE | ||
172 | if (parent->pde) { | ||
173 | struct proc_dir_entry *ent; | ||
174 | |||
175 | ent = proc_mkdir(strrchr(np->full_name, '/') + 1, parent->pde); | ||
176 | if (ent) | ||
177 | proc_device_tree_add_node(np, ent); | ||
178 | } | ||
179 | #endif | ||
180 | return np; | ||
181 | |||
182 | node_free: | ||
183 | free_node(np); | ||
184 | return NULL; | ||
185 | } | ||
186 | |||
187 | /* | ||
188 | * This is here so that we can dynamically add viodasd | ||
189 | * devices without exposing all the above infrastructure. | ||
190 | */ | ||
191 | struct vio_dev *vio_create_viodasd(u32 unit) | ||
192 | { | ||
193 | struct device_node *vio_root; | ||
194 | struct device_node *np; | ||
195 | struct vio_dev *vdev = NULL; | ||
196 | |||
197 | vio_root = of_find_node_by_path("/vdevice"); | ||
198 | if (!vio_root) | ||
199 | return NULL; | ||
200 | np = do_device_node(vio_root, "viodasd", FIRST_VIODASD + unit, unit, | ||
201 | "block", "IBM,iSeries-viodasd", NULL); | ||
202 | of_node_put(vio_root); | ||
203 | if (np) { | ||
204 | vdev = vio_register_device_node(np); | ||
205 | if (!vdev) | ||
206 | free_node(np); | ||
207 | } | ||
208 | return vdev; | ||
209 | } | ||
210 | EXPORT_SYMBOL_GPL(vio_create_viodasd); | ||
211 | |||
212 | static void __init handle_block_event(struct HvLpEvent *event) | ||
213 | { | ||
214 | struct vioblocklpevent *bevent = (struct vioblocklpevent *)event; | ||
215 | struct vio_waitevent *pwe; | ||
216 | |||
217 | if (event == NULL) | ||
218 | /* Notification that a partition went away! */ | ||
219 | return; | ||
220 | /* First, we should NEVER get an int here...only acks */ | ||
221 | if (hvlpevent_is_int(event)) { | ||
222 | printk(KERN_WARNING "handle_viod_request: " | ||
223 | "Yikes! got an int in viodasd event handler!\n"); | ||
224 | if (hvlpevent_need_ack(event)) { | ||
225 | event->xRc = HvLpEvent_Rc_InvalidSubtype; | ||
226 | HvCallEvent_ackLpEvent(event); | ||
227 | } | ||
228 | return; | ||
229 | } | ||
230 | |||
231 | switch (event->xSubtype & VIOMINOR_SUBTYPE_MASK) { | ||
232 | case vioblockopen: | ||
233 | /* | ||
234 | * Handle a response to an open request. We get all the | ||
235 | * disk information in the response, so update it. The | ||
236 | * correlation token contains a pointer to a waitevent | ||
237 | * structure that has a completion in it. update the | ||
238 | * return code in the waitevent structure and post the | ||
239 | * completion to wake up the guy who sent the request | ||
240 | */ | ||
241 | pwe = (struct vio_waitevent *)event->xCorrelationToken; | ||
242 | pwe->rc = event->xRc; | ||
243 | pwe->sub_result = bevent->sub_result; | ||
244 | complete(&pwe->com); | ||
245 | break; | ||
246 | case vioblockclose: | ||
247 | break; | ||
248 | default: | ||
249 | printk(KERN_WARNING "handle_viod_request: unexpected subtype!"); | ||
250 | if (hvlpevent_need_ack(event)) { | ||
251 | event->xRc = HvLpEvent_Rc_InvalidSubtype; | ||
252 | HvCallEvent_ackLpEvent(event); | ||
253 | } | ||
254 | } | ||
255 | } | ||
256 | |||
257 | static void __init probe_disk(struct device_node *vio_root, u32 unit) | ||
258 | { | ||
259 | HvLpEvent_Rc hvrc; | ||
260 | struct vio_waitevent we; | ||
261 | u16 flags = 0; | ||
262 | |||
263 | retry: | ||
264 | init_completion(&we.com); | ||
265 | |||
266 | /* Send the open event to OS/400 */ | ||
267 | hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, | ||
268 | HvLpEvent_Type_VirtualIo, | ||
269 | viomajorsubtype_blockio | vioblockopen, | ||
270 | HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck, | ||
271 | viopath_sourceinst(viopath_hostLp), | ||
272 | viopath_targetinst(viopath_hostLp), | ||
273 | (u64)(unsigned long)&we, VIOVERSION << 16, | ||
274 | ((u64)unit << 48) | ((u64)flags<< 32), | ||
275 | 0, 0, 0); | ||
276 | if (hvrc != 0) { | ||
277 | printk(KERN_WARNING "probe_disk: bad rc on HV open %d\n", | ||
278 | (int)hvrc); | ||
279 | return; | ||
280 | } | ||
281 | |||
282 | wait_for_completion(&we.com); | ||
283 | |||
284 | if (we.rc != 0) { | ||
285 | if (flags != 0) | ||
286 | return; | ||
287 | /* try again with read only flag set */ | ||
288 | flags = vioblockflags_ro; | ||
289 | goto retry; | ||
290 | } | ||
291 | |||
292 | /* Send the close event to OS/400. We DON'T expect a response */ | ||
293 | hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, | ||
294 | HvLpEvent_Type_VirtualIo, | ||
295 | viomajorsubtype_blockio | vioblockclose, | ||
296 | HvLpEvent_AckInd_NoAck, HvLpEvent_AckType_ImmediateAck, | ||
297 | viopath_sourceinst(viopath_hostLp), | ||
298 | viopath_targetinst(viopath_hostLp), | ||
299 | 0, VIOVERSION << 16, | ||
300 | ((u64)unit << 48) | ((u64)flags << 32), | ||
301 | 0, 0, 0); | ||
302 | if (hvrc != 0) { | ||
303 | printk(KERN_WARNING "probe_disk: " | ||
304 | "bad rc sending event to OS/400 %d\n", (int)hvrc); | ||
305 | return; | ||
306 | } | ||
307 | |||
308 | do_device_node(vio_root, "viodasd", FIRST_VIODASD + unit, unit, | ||
309 | "block", "IBM,iSeries-viodasd", NULL); | ||
310 | } | ||
311 | |||
312 | static void __init get_viodasd_info(struct device_node *vio_root) | ||
313 | { | ||
314 | int rc; | ||
315 | u32 unit; | ||
316 | |||
317 | rc = viopath_open(viopath_hostLp, viomajorsubtype_blockio, 2); | ||
318 | if (rc) { | ||
319 | printk(KERN_WARNING "get_viodasd_info: " | ||
320 | "error opening path to host partition %d\n", | ||
321 | viopath_hostLp); | ||
322 | return; | ||
323 | } | ||
324 | |||
325 | /* Initialize our request handler */ | ||
326 | vio_setHandler(viomajorsubtype_blockio, handle_block_event); | ||
327 | |||
328 | for (unit = 0; unit < HVMAXARCHITECTEDVIRTUALDISKS; unit++) | ||
329 | probe_disk(vio_root, unit); | ||
330 | |||
331 | vio_clearHandler(viomajorsubtype_blockio); | ||
332 | viopath_close(viopath_hostLp, viomajorsubtype_blockio, 2); | ||
333 | } | ||
334 | |||
138 | static void __init handle_cd_event(struct HvLpEvent *event) | 335 | static void __init handle_cd_event(struct HvLpEvent *event) |
139 | { | 336 | { |
140 | struct viocdlpevent *bevent; | 337 | struct viocdlpevent *bevent; |
@@ -233,49 +430,9 @@ static void __init get_viocd_info(struct device_node *vio_root) | |||
233 | 430 | ||
234 | for (unit = 0; (unit < HVMAXARCHITECTEDVIRTUALCDROMS) && | 431 | for (unit = 0; (unit < HVMAXARCHITECTEDVIRTUALCDROMS) && |
235 | unitinfo[unit].rsrcname[0]; unit++) { | 432 | unitinfo[unit].rsrcname[0]; unit++) { |
236 | struct device_node *np; | 433 | if (!do_device_node(vio_root, "viocd", FIRST_VIOCD + unit, unit, |
237 | char name[64]; | 434 | "block", "IBM,iSeries-viocd", &unitinfo[unit])) |
238 | u32 reg = FIRST_VIOCD + unit; | 435 | break; |
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 | } | 436 | } |
280 | 437 | ||
281 | hv_free: | 438 | hv_free: |
@@ -350,49 +507,10 @@ static void __init get_viotape_info(struct device_node *vio_root) | |||
350 | 507 | ||
351 | for (unit = 0; (unit < HVMAXARCHITECTEDVIRTUALTAPES) && | 508 | for (unit = 0; (unit < HVMAXARCHITECTEDVIRTUALTAPES) && |
352 | unitinfo[unit].rsrcname[0]; unit++) { | 509 | unitinfo[unit].rsrcname[0]; unit++) { |
353 | struct device_node *np; | 510 | if (!do_device_node(vio_root, "viotape", FIRST_VIOTAPE + unit, |
354 | char name[64]; | 511 | unit, "byte", "IBM,iSeries-viotape", |
355 | u32 reg = FIRST_VIOTAPE + unit; | 512 | &unitinfo[unit])) |
356 | 513 | break; | |
357 | snprintf(name, sizeof(name), "/vdevice/viotape@%08x", reg); | ||
358 | np = new_node(name, vio_root); | ||
359 | if (!np) | ||
360 | goto hv_free; | ||
361 | if (!add_string_property(np, "name", "viotape") || | ||
362 | !add_string_property(np, "device_type", "byte") || | ||
363 | !add_string_property(np, "compatible", | ||
364 | "IBM,iSeries-viotape") || | ||
365 | !add_raw_property(np, "reg", sizeof(reg), ®) || | ||
366 | !add_raw_property(np, "linux,unit_address", | ||
367 | sizeof(unit), &unit) || | ||
368 | !add_raw_property(np, "linux,vio_rsrcname", | ||
369 | sizeof(unitinfo[unit].rsrcname), | ||
370 | unitinfo[unit].rsrcname) || | ||
371 | !add_raw_property(np, "linux,vio_type", | ||
372 | sizeof(unitinfo[unit].type), | ||
373 | unitinfo[unit].type) || | ||
374 | !add_raw_property(np, "linux,vio_model", | ||
375 | sizeof(unitinfo[unit].model), | ||
376 | unitinfo[unit].model)) | ||
377 | goto node_free; | ||
378 | np->name = of_get_property(np, "name", NULL); | ||
379 | np->type = of_get_property(np, "device_type", NULL); | ||
380 | of_attach_node(np); | ||
381 | #ifdef CONFIG_PROC_DEVICETREE | ||
382 | if (vio_root->pde) { | ||
383 | struct proc_dir_entry *ent; | ||
384 | |||
385 | ent = proc_mkdir(strrchr(np->full_name, '/') + 1, | ||
386 | vio_root->pde); | ||
387 | if (ent) | ||
388 | proc_device_tree_add_node(np, ent); | ||
389 | } | ||
390 | #endif | ||
391 | continue; | ||
392 | |||
393 | node_free: | ||
394 | free_node(np); | ||
395 | break; | ||
396 | } | 514 | } |
397 | 515 | ||
398 | hv_free: | 516 | hv_free: |
@@ -422,6 +540,7 @@ static int __init iseries_vio_init(void) | |||
422 | goto put_node; | 540 | goto put_node; |
423 | } | 541 | } |
424 | 542 | ||
543 | get_viodasd_info(vio_root); | ||
425 | get_viocd_info(vio_root); | 544 | get_viocd_info(vio_root); |
426 | get_viotape_info(vio_root); | 545 | get_viotape_info(vio_root); |
427 | 546 | ||
diff --git a/drivers/block/viodasd.c b/drivers/block/viodasd.c index af3969a9c963..e824b672e05a 100644 --- a/drivers/block/viodasd.c +++ b/drivers/block/viodasd.c | |||
@@ -74,53 +74,9 @@ enum { | |||
74 | static DEFINE_SPINLOCK(viodasd_spinlock); | 74 | static DEFINE_SPINLOCK(viodasd_spinlock); |
75 | 75 | ||
76 | #define VIOMAXREQ 16 | 76 | #define VIOMAXREQ 16 |
77 | #define VIOMAXBLOCKDMA 12 | ||
78 | 77 | ||
79 | #define DEVICE_NO(cell) ((struct viodasd_device *)(cell) - &viodasd_devices[0]) | 78 | #define DEVICE_NO(cell) ((struct viodasd_device *)(cell) - &viodasd_devices[0]) |
80 | 79 | ||
81 | struct open_data { | ||
82 | u64 disk_size; | ||
83 | u16 max_disk; | ||
84 | u16 cylinders; | ||
85 | u16 tracks; | ||
86 | u16 sectors; | ||
87 | u16 bytes_per_sector; | ||
88 | }; | ||
89 | |||
90 | struct rw_data { | ||
91 | u64 offset; | ||
92 | struct { | ||
93 | u32 token; | ||
94 | u32 reserved; | ||
95 | u64 len; | ||
96 | } dma_info[VIOMAXBLOCKDMA]; | ||
97 | }; | ||
98 | |||
99 | struct vioblocklpevent { | ||
100 | struct HvLpEvent event; | ||
101 | u32 reserved; | ||
102 | u16 version; | ||
103 | u16 sub_result; | ||
104 | u16 disk; | ||
105 | u16 flags; | ||
106 | union { | ||
107 | struct open_data open_data; | ||
108 | struct rw_data rw_data; | ||
109 | u64 changed; | ||
110 | } u; | ||
111 | }; | ||
112 | |||
113 | #define vioblockflags_ro 0x0001 | ||
114 | |||
115 | enum vioblocksubtype { | ||
116 | vioblockopen = 0x0001, | ||
117 | vioblockclose = 0x0002, | ||
118 | vioblockread = 0x0003, | ||
119 | vioblockwrite = 0x0004, | ||
120 | vioblockflush = 0x0005, | ||
121 | vioblockcheck = 0x0007 | ||
122 | }; | ||
123 | |||
124 | struct viodasd_waitevent { | 80 | struct viodasd_waitevent { |
125 | struct completion com; | 81 | struct completion com; |
126 | int rc; | 82 | int rc; |
@@ -429,7 +385,7 @@ static void do_viodasd_request(struct request_queue *q) | |||
429 | * Probe a single disk and fill in the viodasd_device structure | 385 | * Probe a single disk and fill in the viodasd_device structure |
430 | * for it. | 386 | * for it. |
431 | */ | 387 | */ |
432 | static void probe_disk(struct viodasd_device *d) | 388 | static int probe_disk(struct viodasd_device *d) |
433 | { | 389 | { |
434 | HvLpEvent_Rc hvrc; | 390 | HvLpEvent_Rc hvrc; |
435 | struct viodasd_waitevent we; | 391 | struct viodasd_waitevent we; |
@@ -453,14 +409,14 @@ retry: | |||
453 | 0, 0, 0); | 409 | 0, 0, 0); |
454 | if (hvrc != 0) { | 410 | if (hvrc != 0) { |
455 | printk(VIOD_KERN_WARNING "bad rc on HV open %d\n", (int)hvrc); | 411 | printk(VIOD_KERN_WARNING "bad rc on HV open %d\n", (int)hvrc); |
456 | return; | 412 | return 0; |
457 | } | 413 | } |
458 | 414 | ||
459 | wait_for_completion(&we.com); | 415 | wait_for_completion(&we.com); |
460 | 416 | ||
461 | if (we.rc != 0) { | 417 | if (we.rc != 0) { |
462 | if (flags != 0) | 418 | if (flags != 0) |
463 | return; | 419 | return 0; |
464 | /* try again with read only flag set */ | 420 | /* try again with read only flag set */ |
465 | flags = vioblockflags_ro; | 421 | flags = vioblockflags_ro; |
466 | goto retry; | 422 | goto retry; |
@@ -490,15 +446,32 @@ retry: | |||
490 | if (hvrc != 0) { | 446 | if (hvrc != 0) { |
491 | printk(VIOD_KERN_WARNING | 447 | printk(VIOD_KERN_WARNING |
492 | "bad rc sending event to OS/400 %d\n", (int)hvrc); | 448 | "bad rc sending event to OS/400 %d\n", (int)hvrc); |
493 | return; | 449 | return 0; |
494 | } | 450 | } |
451 | |||
452 | if (d->dev == NULL) { | ||
453 | /* this is when we reprobe for new disks */ | ||
454 | if (vio_create_viodasd(dev_no) == NULL) { | ||
455 | printk(VIOD_KERN_WARNING | ||
456 | "cannot allocate virtual device for disk %d\n", | ||
457 | dev_no); | ||
458 | return 0; | ||
459 | } | ||
460 | /* | ||
461 | * The vio_create_viodasd will have recursed into this | ||
462 | * routine with d->dev set to the new vio device and | ||
463 | * will finish the setup of the disk below. | ||
464 | */ | ||
465 | return 1; | ||
466 | } | ||
467 | |||
495 | /* create the request queue for the disk */ | 468 | /* create the request queue for the disk */ |
496 | spin_lock_init(&d->q_lock); | 469 | spin_lock_init(&d->q_lock); |
497 | q = blk_init_queue(do_viodasd_request, &d->q_lock); | 470 | q = blk_init_queue(do_viodasd_request, &d->q_lock); |
498 | if (q == NULL) { | 471 | if (q == NULL) { |
499 | printk(VIOD_KERN_WARNING "cannot allocate queue for disk %d\n", | 472 | printk(VIOD_KERN_WARNING "cannot allocate queue for disk %d\n", |
500 | dev_no); | 473 | dev_no); |
501 | return; | 474 | return 0; |
502 | } | 475 | } |
503 | g = alloc_disk(1 << PARTITION_SHIFT); | 476 | g = alloc_disk(1 << PARTITION_SHIFT); |
504 | if (g == NULL) { | 477 | if (g == NULL) { |
@@ -506,7 +479,7 @@ retry: | |||
506 | "cannot allocate disk structure for disk %d\n", | 479 | "cannot allocate disk structure for disk %d\n", |
507 | dev_no); | 480 | dev_no); |
508 | blk_cleanup_queue(q); | 481 | blk_cleanup_queue(q); |
509 | return; | 482 | return 0; |
510 | } | 483 | } |
511 | 484 | ||
512 | d->disk = g; | 485 | d->disk = g; |
@@ -538,6 +511,7 @@ retry: | |||
538 | 511 | ||
539 | /* register us in the global list */ | 512 | /* register us in the global list */ |
540 | add_disk(g); | 513 | add_disk(g); |
514 | return 1; | ||
541 | } | 515 | } |
542 | 516 | ||
543 | /* returns the total number of scatterlist elements converted */ | 517 | /* returns the total number of scatterlist elements converted */ |
@@ -718,8 +692,7 @@ static int viodasd_probe(struct vio_dev *vdev, const struct vio_device_id *id) | |||
718 | struct viodasd_device *d = &viodasd_devices[vdev->unit_address]; | 692 | struct viodasd_device *d = &viodasd_devices[vdev->unit_address]; |
719 | 693 | ||
720 | d->dev = &vdev->dev; | 694 | d->dev = &vdev->dev; |
721 | probe_disk(d); | 695 | if (!probe_disk(d)) |
722 | if (d->disk == NULL) | ||
723 | return -ENODEV; | 696 | return -ENODEV; |
724 | return 0; | 697 | return 0; |
725 | } | 698 | } |
diff --git a/include/asm-powerpc/iseries/vio.h b/include/asm-powerpc/iseries/vio.h index 2555dfd6fac6..f9ac0d00b951 100644 --- a/include/asm-powerpc/iseries/vio.h +++ b/include/asm-powerpc/iseries/vio.h | |||
@@ -51,6 +51,51 @@ | |||
51 | */ | 51 | */ |
52 | #define VIO_MAX_SUBTYPES 8 | 52 | #define VIO_MAX_SUBTYPES 8 |
53 | 53 | ||
54 | #define VIOMAXBLOCKDMA 12 | ||
55 | |||
56 | struct open_data { | ||
57 | u64 disk_size; | ||
58 | u16 max_disk; | ||
59 | u16 cylinders; | ||
60 | u16 tracks; | ||
61 | u16 sectors; | ||
62 | u16 bytes_per_sector; | ||
63 | }; | ||
64 | |||
65 | struct rw_data { | ||
66 | u64 offset; | ||
67 | struct { | ||
68 | u32 token; | ||
69 | u32 reserved; | ||
70 | u64 len; | ||
71 | } dma_info[VIOMAXBLOCKDMA]; | ||
72 | }; | ||
73 | |||
74 | struct vioblocklpevent { | ||
75 | struct HvLpEvent event; | ||
76 | u32 reserved; | ||
77 | u16 version; | ||
78 | u16 sub_result; | ||
79 | u16 disk; | ||
80 | u16 flags; | ||
81 | union { | ||
82 | struct open_data open_data; | ||
83 | struct rw_data rw_data; | ||
84 | u64 changed; | ||
85 | } u; | ||
86 | }; | ||
87 | |||
88 | #define vioblockflags_ro 0x0001 | ||
89 | |||
90 | enum vioblocksubtype { | ||
91 | vioblockopen = 0x0001, | ||
92 | vioblockclose = 0x0002, | ||
93 | vioblockread = 0x0003, | ||
94 | vioblockwrite = 0x0004, | ||
95 | vioblockflush = 0x0005, | ||
96 | vioblockcheck = 0x0007 | ||
97 | }; | ||
98 | |||
54 | struct viocdlpevent { | 99 | struct viocdlpevent { |
55 | struct HvLpEvent event; | 100 | struct HvLpEvent event; |
56 | u32 reserved; | 101 | u32 reserved; |
@@ -133,6 +178,8 @@ extern void vio_set_hostlp(void); | |||
133 | extern void *vio_get_event_buffer(int subtype); | 178 | extern void *vio_get_event_buffer(int subtype); |
134 | extern void vio_free_event_buffer(int subtype, void *buffer); | 179 | extern void vio_free_event_buffer(int subtype, void *buffer); |
135 | 180 | ||
181 | extern struct vio_dev *vio_create_viodasd(u32 unit); | ||
182 | |||
136 | extern HvLpIndex viopath_hostLp; | 183 | extern HvLpIndex viopath_hostLp; |
137 | extern HvLpIndex viopath_ourLp; | 184 | extern HvLpIndex viopath_ourLp; |
138 | 185 | ||