ia64/linux-2.6.18-xen.hg

view drivers/block/viodasd.c @ 897:329ea0ccb344

balloon: try harder to balloon up under memory pressure.

Currently if the balloon driver is unable to increase the guest's
reservation it assumes the failure was due to reaching its full
allocation, gives up on the ballooning operation and records the limit
it reached as the "hard limit". The driver will not try again until
the target is set again (even to the same value).

However it is possible that ballooning has in fact failed due to
memory pressure in the host and therefore it is desirable to keep
attempting to reach the target in case memory becomes available. The
most likely scenario is that some guests are ballooning down while
others are ballooning up and therefore there is temporary memory
pressure while things stabilise. You would not expect a well behaved
toolstack to ask a domain to balloon to more than its allocation nor
would you expect it to deliberately over-commit memory by setting
balloon targets which exceed the total host memory.

This patch drops the concept of a hard limit and causes the balloon
driver to retry increasing the reservation on a timer in the same
manner as when decreasing the reservation.

Also if we partially succeed in increasing the reservation
(i.e. receive less pages than we asked for) then we may as well keep
those pages rather than returning them to Xen.

Signed-off-by: Ian Campbell <ian.campbell@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Fri Jun 05 14:01:20 2009 +0100 (2009-06-05)
parents 831230e53067
children
line source
1 /* -*- linux-c -*-
2 * viodasd.c
3 * Authors: Dave Boutcher <boutcher@us.ibm.com>
4 * Ryan Arnold <ryanarn@us.ibm.com>
5 * Colin Devilbiss <devilbis@us.ibm.com>
6 * Stephen Rothwell <sfr@au1.ibm.com>
7 *
8 * (C) Copyright 2000-2004 IBM Corporation
9 *
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License as
12 * published by the Free Software Foundation; either version 2 of the
13 * License, or (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 *
24 * This routine provides access to disk space (termed "DASD" in historical
25 * IBM terms) owned and managed by an OS/400 partition running on the
26 * same box as this Linux partition.
27 *
28 * All disk operations are performed by sending messages back and forth to
29 * the OS/400 partition.
30 */
31 #include <linux/major.h>
32 #include <linux/fs.h>
33 #include <linux/module.h>
34 #include <linux/kernel.h>
35 #include <linux/blkdev.h>
36 #include <linux/genhd.h>
37 #include <linux/hdreg.h>
38 #include <linux/errno.h>
39 #include <linux/init.h>
40 #include <linux/string.h>
41 #include <linux/dma-mapping.h>
42 #include <linux/completion.h>
43 #include <linux/device.h>
44 #include <linux/kernel.h>
46 #include <asm/uaccess.h>
47 #include <asm/vio.h>
48 #include <asm/iseries/hv_types.h>
49 #include <asm/iseries/hv_lp_event.h>
50 #include <asm/iseries/hv_lp_config.h>
51 #include <asm/iseries/vio.h>
53 MODULE_DESCRIPTION("iSeries Virtual DASD");
54 MODULE_AUTHOR("Dave Boutcher");
55 MODULE_LICENSE("GPL");
57 /*
58 * We only support 7 partitions per physical disk....so with minor
59 * numbers 0-255 we get a maximum of 32 disks.
60 */
61 #define VIOD_GENHD_NAME "iseries/vd"
63 #define VIOD_VERS "1.64"
65 #define VIOD_KERN_WARNING KERN_WARNING "viod: "
66 #define VIOD_KERN_INFO KERN_INFO "viod: "
68 enum {
69 PARTITION_SHIFT = 3,
70 MAX_DISKNO = HVMAXARCHITECTEDVIRTUALDISKS,
71 MAX_DISK_NAME = sizeof(((struct gendisk *)0)->disk_name)
72 };
74 static DEFINE_SPINLOCK(viodasd_spinlock);
76 #define VIOMAXREQ 16
77 #define VIOMAXBLOCKDMA 12
79 #define DEVICE_NO(cell) ((struct viodasd_device *)(cell) - &viodasd_devices[0])
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 };
90 struct rw_data {
91 u64 offset;
92 struct {
93 u32 token;
94 u32 reserved;
95 u64 len;
96 } dma_info[VIOMAXBLOCKDMA];
97 };
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 };
113 #define vioblockflags_ro 0x0001
115 enum vioblocksubtype {
116 vioblockopen = 0x0001,
117 vioblockclose = 0x0002,
118 vioblockread = 0x0003,
119 vioblockwrite = 0x0004,
120 vioblockflush = 0x0005,
121 vioblockcheck = 0x0007
122 };
124 struct viodasd_waitevent {
125 struct completion com;
126 int rc;
127 u16 sub_result;
128 int max_disk; /* open */
129 };
131 static const struct vio_error_entry viodasd_err_table[] = {
132 { 0x0201, EINVAL, "Invalid Range" },
133 { 0x0202, EINVAL, "Invalid Token" },
134 { 0x0203, EIO, "DMA Error" },
135 { 0x0204, EIO, "Use Error" },
136 { 0x0205, EIO, "Release Error" },
137 { 0x0206, EINVAL, "Invalid Disk" },
138 { 0x0207, EBUSY, "Cant Lock" },
139 { 0x0208, EIO, "Already Locked" },
140 { 0x0209, EIO, "Already Unlocked" },
141 { 0x020A, EIO, "Invalid Arg" },
142 { 0x020B, EIO, "Bad IFS File" },
143 { 0x020C, EROFS, "Read Only Device" },
144 { 0x02FF, EIO, "Internal Error" },
145 { 0x0000, 0, NULL },
146 };
148 /*
149 * Figure out the biggest I/O request (in sectors) we can accept
150 */
151 #define VIODASD_MAXSECTORS (4096 / 512 * VIOMAXBLOCKDMA)
153 /*
154 * Number of disk I/O requests we've sent to OS/400
155 */
156 static int num_req_outstanding;
158 /*
159 * This is our internal structure for keeping track of disk devices
160 */
161 struct viodasd_device {
162 u16 cylinders;
163 u16 tracks;
164 u16 sectors;
165 u16 bytes_per_sector;
166 u64 size;
167 int read_only;
168 spinlock_t q_lock;
169 struct gendisk *disk;
170 struct device *dev;
171 } viodasd_devices[MAX_DISKNO];
173 /*
174 * External open entry point.
175 */
176 static int viodasd_open(struct inode *ino, struct file *fil)
177 {
178 struct viodasd_device *d = ino->i_bdev->bd_disk->private_data;
179 HvLpEvent_Rc hvrc;
180 struct viodasd_waitevent we;
181 u16 flags = 0;
183 if (d->read_only) {
184 if ((fil != NULL) && (fil->f_mode & FMODE_WRITE))
185 return -EROFS;
186 flags = vioblockflags_ro;
187 }
189 init_completion(&we.com);
191 /* Send the open event to OS/400 */
192 hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
193 HvLpEvent_Type_VirtualIo,
194 viomajorsubtype_blockio | vioblockopen,
195 HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck,
196 viopath_sourceinst(viopath_hostLp),
197 viopath_targetinst(viopath_hostLp),
198 (u64)(unsigned long)&we, VIOVERSION << 16,
199 ((u64)DEVICE_NO(d) << 48) | ((u64)flags << 32),
200 0, 0, 0);
201 if (hvrc != 0) {
202 printk(VIOD_KERN_WARNING "HV open failed %d\n", (int)hvrc);
203 return -EIO;
204 }
206 wait_for_completion(&we.com);
208 /* Check the return code */
209 if (we.rc != 0) {
210 const struct vio_error_entry *err =
211 vio_lookup_rc(viodasd_err_table, we.sub_result);
213 printk(VIOD_KERN_WARNING
214 "bad rc opening disk: %d:0x%04x (%s)\n",
215 (int)we.rc, we.sub_result, err->msg);
216 return -EIO;
217 }
219 return 0;
220 }
222 /*
223 * External release entry point.
224 */
225 static int viodasd_release(struct inode *ino, struct file *fil)
226 {
227 struct viodasd_device *d = ino->i_bdev->bd_disk->private_data;
228 HvLpEvent_Rc hvrc;
230 /* Send the event to OS/400. We DON'T expect a response */
231 hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
232 HvLpEvent_Type_VirtualIo,
233 viomajorsubtype_blockio | vioblockclose,
234 HvLpEvent_AckInd_NoAck, HvLpEvent_AckType_ImmediateAck,
235 viopath_sourceinst(viopath_hostLp),
236 viopath_targetinst(viopath_hostLp),
237 0, VIOVERSION << 16,
238 ((u64)DEVICE_NO(d) << 48) /* | ((u64)flags << 32) */,
239 0, 0, 0);
240 if (hvrc != 0)
241 printk(VIOD_KERN_WARNING "HV close call failed %d\n",
242 (int)hvrc);
243 return 0;
244 }
247 /* External ioctl entry point.
248 */
249 static int viodasd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
250 {
251 struct gendisk *disk = bdev->bd_disk;
252 struct viodasd_device *d = disk->private_data;
254 geo->sectors = d->sectors ? d->sectors : 0;
255 geo->heads = d->tracks ? d->tracks : 64;
256 geo->cylinders = d->cylinders ? d->cylinders :
257 get_capacity(disk) / (geo->cylinders * geo->heads);
259 return 0;
260 }
262 /*
263 * Our file operations table
264 */
265 static struct block_device_operations viodasd_fops = {
266 .owner = THIS_MODULE,
267 .open = viodasd_open,
268 .release = viodasd_release,
269 .getgeo = viodasd_getgeo,
270 };
272 /*
273 * End a request
274 */
275 static void viodasd_end_request(struct request *req, int uptodate,
276 int num_sectors)
277 {
278 if (end_that_request_first(req, uptodate, num_sectors))
279 return;
280 add_disk_randomness(req->rq_disk);
281 end_that_request_last(req, uptodate);
282 }
284 /*
285 * Send an actual I/O request to OS/400
286 */
287 static int send_request(struct request *req)
288 {
289 u64 start;
290 int direction;
291 int nsg;
292 u16 viocmd;
293 HvLpEvent_Rc hvrc;
294 struct vioblocklpevent *bevent;
295 struct HvLpEvent *hev;
296 struct scatterlist sg[VIOMAXBLOCKDMA];
297 int sgindex;
298 int statindex;
299 struct viodasd_device *d;
300 unsigned long flags;
302 start = (u64)req->sector << 9;
304 if (rq_data_dir(req) == READ) {
305 direction = DMA_FROM_DEVICE;
306 viocmd = viomajorsubtype_blockio | vioblockread;
307 statindex = 0;
308 } else {
309 direction = DMA_TO_DEVICE;
310 viocmd = viomajorsubtype_blockio | vioblockwrite;
311 statindex = 1;
312 }
314 d = req->rq_disk->private_data;
316 /* Now build the scatter-gather list */
317 nsg = blk_rq_map_sg(req->q, req, sg);
318 nsg = dma_map_sg(d->dev, sg, nsg, direction);
320 spin_lock_irqsave(&viodasd_spinlock, flags);
321 num_req_outstanding++;
323 /* This optimization handles a single DMA block */
324 if (nsg == 1)
325 hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
326 HvLpEvent_Type_VirtualIo, viocmd,
327 HvLpEvent_AckInd_DoAck,
328 HvLpEvent_AckType_ImmediateAck,
329 viopath_sourceinst(viopath_hostLp),
330 viopath_targetinst(viopath_hostLp),
331 (u64)(unsigned long)req, VIOVERSION << 16,
332 ((u64)DEVICE_NO(d) << 48), start,
333 ((u64)sg_dma_address(&sg[0])) << 32,
334 sg_dma_len(&sg[0]));
335 else {
336 bevent = (struct vioblocklpevent *)
337 vio_get_event_buffer(viomajorsubtype_blockio);
338 if (bevent == NULL) {
339 printk(VIOD_KERN_WARNING
340 "error allocating disk event buffer\n");
341 goto error_ret;
342 }
344 /*
345 * Now build up the actual request. Note that we store
346 * the pointer to the request in the correlation
347 * token so we can match the response up later
348 */
349 memset(bevent, 0, sizeof(struct vioblocklpevent));
350 hev = &bevent->event;
351 hev->flags = HV_LP_EVENT_VALID | HV_LP_EVENT_DO_ACK |
352 HV_LP_EVENT_INT;
353 hev->xType = HvLpEvent_Type_VirtualIo;
354 hev->xSubtype = viocmd;
355 hev->xSourceLp = HvLpConfig_getLpIndex();
356 hev->xTargetLp = viopath_hostLp;
357 hev->xSizeMinus1 =
358 offsetof(struct vioblocklpevent, u.rw_data.dma_info) +
359 (sizeof(bevent->u.rw_data.dma_info[0]) * nsg) - 1;
360 hev->xSourceInstanceId = viopath_sourceinst(viopath_hostLp);
361 hev->xTargetInstanceId = viopath_targetinst(viopath_hostLp);
362 hev->xCorrelationToken = (u64)req;
363 bevent->version = VIOVERSION;
364 bevent->disk = DEVICE_NO(d);
365 bevent->u.rw_data.offset = start;
367 /*
368 * Copy just the dma information from the sg list
369 * into the request
370 */
371 for (sgindex = 0; sgindex < nsg; sgindex++) {
372 bevent->u.rw_data.dma_info[sgindex].token =
373 sg_dma_address(&sg[sgindex]);
374 bevent->u.rw_data.dma_info[sgindex].len =
375 sg_dma_len(&sg[sgindex]);
376 }
378 /* Send the request */
379 hvrc = HvCallEvent_signalLpEvent(&bevent->event);
380 vio_free_event_buffer(viomajorsubtype_blockio, bevent);
381 }
383 if (hvrc != HvLpEvent_Rc_Good) {
384 printk(VIOD_KERN_WARNING
385 "error sending disk event to OS/400 (rc %d)\n",
386 (int)hvrc);
387 goto error_ret;
388 }
389 spin_unlock_irqrestore(&viodasd_spinlock, flags);
390 return 0;
392 error_ret:
393 num_req_outstanding--;
394 spin_unlock_irqrestore(&viodasd_spinlock, flags);
395 dma_unmap_sg(d->dev, sg, nsg, direction);
396 return -1;
397 }
399 /*
400 * This is the external request processing routine
401 */
402 static void do_viodasd_request(request_queue_t *q)
403 {
404 struct request *req;
406 /*
407 * If we already have the maximum number of requests
408 * outstanding to OS/400 just bail out. We'll come
409 * back later.
410 */
411 while (num_req_outstanding < VIOMAXREQ) {
412 req = elv_next_request(q);
413 if (req == NULL)
414 return;
415 /* dequeue the current request from the queue */
416 blkdev_dequeue_request(req);
417 /* check that request contains a valid command */
418 if (!blk_fs_request(req)) {
419 viodasd_end_request(req, 0, req->hard_nr_sectors);
420 continue;
421 }
422 /* Try sending the request */
423 if (send_request(req) != 0)
424 viodasd_end_request(req, 0, req->hard_nr_sectors);
425 }
426 }
428 /*
429 * Probe a single disk and fill in the viodasd_device structure
430 * for it.
431 */
432 static void probe_disk(struct viodasd_device *d)
433 {
434 HvLpEvent_Rc hvrc;
435 struct viodasd_waitevent we;
436 int dev_no = DEVICE_NO(d);
437 struct gendisk *g;
438 struct request_queue *q;
439 u16 flags = 0;
441 retry:
442 init_completion(&we.com);
444 /* Send the open event to OS/400 */
445 hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
446 HvLpEvent_Type_VirtualIo,
447 viomajorsubtype_blockio | vioblockopen,
448 HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck,
449 viopath_sourceinst(viopath_hostLp),
450 viopath_targetinst(viopath_hostLp),
451 (u64)(unsigned long)&we, VIOVERSION << 16,
452 ((u64)dev_no << 48) | ((u64)flags<< 32),
453 0, 0, 0);
454 if (hvrc != 0) {
455 printk(VIOD_KERN_WARNING "bad rc on HV open %d\n", (int)hvrc);
456 return;
457 }
459 wait_for_completion(&we.com);
461 if (we.rc != 0) {
462 if (flags != 0)
463 return;
464 /* try again with read only flag set */
465 flags = vioblockflags_ro;
466 goto retry;
467 }
468 if (we.max_disk > (MAX_DISKNO - 1)) {
469 static int warned;
471 if (warned == 0) {
472 warned++;
473 printk(VIOD_KERN_INFO
474 "Only examining the first %d "
475 "of %d disks connected\n",
476 MAX_DISKNO, we.max_disk + 1);
477 }
478 }
480 /* Send the close event to OS/400. We DON'T expect a response */
481 hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
482 HvLpEvent_Type_VirtualIo,
483 viomajorsubtype_blockio | vioblockclose,
484 HvLpEvent_AckInd_NoAck, HvLpEvent_AckType_ImmediateAck,
485 viopath_sourceinst(viopath_hostLp),
486 viopath_targetinst(viopath_hostLp),
487 0, VIOVERSION << 16,
488 ((u64)dev_no << 48) | ((u64)flags << 32),
489 0, 0, 0);
490 if (hvrc != 0) {
491 printk(VIOD_KERN_WARNING
492 "bad rc sending event to OS/400 %d\n", (int)hvrc);
493 return;
494 }
495 /* create the request queue for the disk */
496 spin_lock_init(&d->q_lock);
497 q = blk_init_queue(do_viodasd_request, &d->q_lock);
498 if (q == NULL) {
499 printk(VIOD_KERN_WARNING "cannot allocate queue for disk %d\n",
500 dev_no);
501 return;
502 }
503 g = alloc_disk(1 << PARTITION_SHIFT);
504 if (g == NULL) {
505 printk(VIOD_KERN_WARNING
506 "cannot allocate disk structure for disk %d\n",
507 dev_no);
508 blk_cleanup_queue(q);
509 return;
510 }
512 d->disk = g;
513 blk_queue_max_hw_segments(q, VIOMAXBLOCKDMA);
514 blk_queue_max_phys_segments(q, VIOMAXBLOCKDMA);
515 blk_queue_max_sectors(q, VIODASD_MAXSECTORS);
516 g->major = VIODASD_MAJOR;
517 g->first_minor = dev_no << PARTITION_SHIFT;
518 if (dev_no >= 26)
519 snprintf(g->disk_name, sizeof(g->disk_name),
520 VIOD_GENHD_NAME "%c%c",
521 'a' + (dev_no / 26) - 1, 'a' + (dev_no % 26));
522 else
523 snprintf(g->disk_name, sizeof(g->disk_name),
524 VIOD_GENHD_NAME "%c", 'a' + (dev_no % 26));
525 g->fops = &viodasd_fops;
526 g->queue = q;
527 g->private_data = d;
528 g->driverfs_dev = d->dev;
529 set_capacity(g, d->size >> 9);
531 printk(VIOD_KERN_INFO "disk %d: %lu sectors (%lu MB) "
532 "CHS=%d/%d/%d sector size %d%s\n",
533 dev_no, (unsigned long)(d->size >> 9),
534 (unsigned long)(d->size >> 20),
535 (int)d->cylinders, (int)d->tracks,
536 (int)d->sectors, (int)d->bytes_per_sector,
537 d->read_only ? " (RO)" : "");
539 /* register us in the global list */
540 add_disk(g);
541 }
543 /* returns the total number of scatterlist elements converted */
544 static int block_event_to_scatterlist(const struct vioblocklpevent *bevent,
545 struct scatterlist *sg, int *total_len)
546 {
547 int i, numsg;
548 const struct rw_data *rw_data = &bevent->u.rw_data;
549 static const int offset =
550 offsetof(struct vioblocklpevent, u.rw_data.dma_info);
551 static const int element_size = sizeof(rw_data->dma_info[0]);
553 numsg = ((bevent->event.xSizeMinus1 + 1) - offset) / element_size;
554 if (numsg > VIOMAXBLOCKDMA)
555 numsg = VIOMAXBLOCKDMA;
557 *total_len = 0;
558 memset(sg, 0, sizeof(sg[0]) * VIOMAXBLOCKDMA);
560 for (i = 0; (i < numsg) && (rw_data->dma_info[i].len > 0); ++i) {
561 sg_dma_address(&sg[i]) = rw_data->dma_info[i].token;
562 sg_dma_len(&sg[i]) = rw_data->dma_info[i].len;
563 *total_len += rw_data->dma_info[i].len;
564 }
565 return i;
566 }
568 /*
569 * Restart all queues, starting with the one _after_ the disk given,
570 * thus reducing the chance of starvation of higher numbered disks.
571 */
572 static void viodasd_restart_all_queues_starting_from(int first_index)
573 {
574 int i;
576 for (i = first_index + 1; i < MAX_DISKNO; ++i)
577 if (viodasd_devices[i].disk)
578 blk_run_queue(viodasd_devices[i].disk->queue);
579 for (i = 0; i <= first_index; ++i)
580 if (viodasd_devices[i].disk)
581 blk_run_queue(viodasd_devices[i].disk->queue);
582 }
584 /*
585 * For read and write requests, decrement the number of outstanding requests,
586 * Free the DMA buffers we allocated.
587 */
588 static int viodasd_handle_read_write(struct vioblocklpevent *bevent)
589 {
590 int num_sg, num_sect, pci_direction, total_len;
591 struct request *req;
592 struct scatterlist sg[VIOMAXBLOCKDMA];
593 struct HvLpEvent *event = &bevent->event;
594 unsigned long irq_flags;
595 struct viodasd_device *d;
596 int error;
597 spinlock_t *qlock;
599 num_sg = block_event_to_scatterlist(bevent, sg, &total_len);
600 num_sect = total_len >> 9;
601 if (event->xSubtype == (viomajorsubtype_blockio | vioblockread))
602 pci_direction = DMA_FROM_DEVICE;
603 else
604 pci_direction = DMA_TO_DEVICE;
605 req = (struct request *)bevent->event.xCorrelationToken;
606 d = req->rq_disk->private_data;
608 dma_unmap_sg(d->dev, sg, num_sg, pci_direction);
610 /*
611 * Since this is running in interrupt mode, we need to make sure
612 * we're not stepping on any global I/O operations
613 */
614 spin_lock_irqsave(&viodasd_spinlock, irq_flags);
615 num_req_outstanding--;
616 spin_unlock_irqrestore(&viodasd_spinlock, irq_flags);
618 error = event->xRc != HvLpEvent_Rc_Good;
619 if (error) {
620 const struct vio_error_entry *err;
621 err = vio_lookup_rc(viodasd_err_table, bevent->sub_result);
622 printk(VIOD_KERN_WARNING "read/write error %d:0x%04x (%s)\n",
623 event->xRc, bevent->sub_result, err->msg);
624 num_sect = req->hard_nr_sectors;
625 }
626 qlock = req->q->queue_lock;
627 spin_lock_irqsave(qlock, irq_flags);
628 viodasd_end_request(req, !error, num_sect);
629 spin_unlock_irqrestore(qlock, irq_flags);
631 /* Finally, try to get more requests off of this device's queue */
632 viodasd_restart_all_queues_starting_from(DEVICE_NO(d));
634 return 0;
635 }
637 /* This routine handles incoming block LP events */
638 static void handle_block_event(struct HvLpEvent *event)
639 {
640 struct vioblocklpevent *bevent = (struct vioblocklpevent *)event;
641 struct viodasd_waitevent *pwe;
643 if (event == NULL)
644 /* Notification that a partition went away! */
645 return;
646 /* First, we should NEVER get an int here...only acks */
647 if (hvlpevent_is_int(event)) {
648 printk(VIOD_KERN_WARNING
649 "Yikes! got an int in viodasd event handler!\n");
650 if (hvlpevent_need_ack(event)) {
651 event->xRc = HvLpEvent_Rc_InvalidSubtype;
652 HvCallEvent_ackLpEvent(event);
653 }
654 }
656 switch (event->xSubtype & VIOMINOR_SUBTYPE_MASK) {
657 case vioblockopen:
658 /*
659 * Handle a response to an open request. We get all the
660 * disk information in the response, so update it. The
661 * correlation token contains a pointer to a waitevent
662 * structure that has a completion in it. update the
663 * return code in the waitevent structure and post the
664 * completion to wake up the guy who sent the request
665 */
666 pwe = (struct viodasd_waitevent *)event->xCorrelationToken;
667 pwe->rc = event->xRc;
668 pwe->sub_result = bevent->sub_result;
669 if (event->xRc == HvLpEvent_Rc_Good) {
670 const struct open_data *data = &bevent->u.open_data;
671 struct viodasd_device *device =
672 &viodasd_devices[bevent->disk];
673 device->read_only =
674 bevent->flags & vioblockflags_ro;
675 device->size = data->disk_size;
676 device->cylinders = data->cylinders;
677 device->tracks = data->tracks;
678 device->sectors = data->sectors;
679 device->bytes_per_sector = data->bytes_per_sector;
680 pwe->max_disk = data->max_disk;
681 }
682 complete(&pwe->com);
683 break;
684 case vioblockclose:
685 break;
686 case vioblockread:
687 case vioblockwrite:
688 viodasd_handle_read_write(bevent);
689 break;
691 default:
692 printk(VIOD_KERN_WARNING "invalid subtype!");
693 if (hvlpevent_need_ack(event)) {
694 event->xRc = HvLpEvent_Rc_InvalidSubtype;
695 HvCallEvent_ackLpEvent(event);
696 }
697 }
698 }
700 /*
701 * Get the driver to reprobe for more disks.
702 */
703 static ssize_t probe_disks(struct device_driver *drv, const char *buf,
704 size_t count)
705 {
706 struct viodasd_device *d;
708 for (d = viodasd_devices; d < &viodasd_devices[MAX_DISKNO]; d++) {
709 if (d->disk == NULL)
710 probe_disk(d);
711 }
712 return count;
713 }
714 static DRIVER_ATTR(probe, S_IWUSR, NULL, probe_disks);
716 static int viodasd_probe(struct vio_dev *vdev, const struct vio_device_id *id)
717 {
718 struct viodasd_device *d = &viodasd_devices[vdev->unit_address];
720 d->dev = &vdev->dev;
721 probe_disk(d);
722 if (d->disk == NULL)
723 return -ENODEV;
724 return 0;
725 }
727 static int viodasd_remove(struct vio_dev *vdev)
728 {
729 struct viodasd_device *d;
731 d = &viodasd_devices[vdev->unit_address];
732 if (d->disk) {
733 del_gendisk(d->disk);
734 blk_cleanup_queue(d->disk->queue);
735 put_disk(d->disk);
736 d->disk = NULL;
737 }
738 d->dev = NULL;
739 return 0;
740 }
742 /**
743 * viodasd_device_table: Used by vio.c to match devices that we
744 * support.
745 */
746 static struct vio_device_id viodasd_device_table[] __devinitdata = {
747 { "block", "IBM,iSeries-viodasd" },
748 { "", "" }
749 };
750 MODULE_DEVICE_TABLE(vio, viodasd_device_table);
752 static struct vio_driver viodasd_driver = {
753 .id_table = viodasd_device_table,
754 .probe = viodasd_probe,
755 .remove = viodasd_remove,
756 .driver = {
757 .name = "viodasd",
758 .owner = THIS_MODULE,
759 }
760 };
762 /*
763 * Initialize the whole device driver. Handle module and non-module
764 * versions
765 */
766 static int __init viodasd_init(void)
767 {
768 int rc;
770 /* Try to open to our host lp */
771 if (viopath_hostLp == HvLpIndexInvalid)
772 vio_set_hostlp();
774 if (viopath_hostLp == HvLpIndexInvalid) {
775 printk(VIOD_KERN_WARNING "invalid hosting partition\n");
776 return -EIO;
777 }
779 printk(VIOD_KERN_INFO "vers " VIOD_VERS ", hosting partition %d\n",
780 viopath_hostLp);
782 /* register the block device */
783 if (register_blkdev(VIODASD_MAJOR, VIOD_GENHD_NAME)) {
784 printk(VIOD_KERN_WARNING
785 "Unable to get major number %d for %s\n",
786 VIODASD_MAJOR, VIOD_GENHD_NAME);
787 return -EIO;
788 }
789 /* Actually open the path to the hosting partition */
790 if (viopath_open(viopath_hostLp, viomajorsubtype_blockio,
791 VIOMAXREQ + 2)) {
792 printk(VIOD_KERN_WARNING
793 "error opening path to host partition %d\n",
794 viopath_hostLp);
795 unregister_blkdev(VIODASD_MAJOR, VIOD_GENHD_NAME);
796 return -EIO;
797 }
799 /* Initialize our request handler */
800 vio_setHandler(viomajorsubtype_blockio, handle_block_event);
802 rc = vio_register_driver(&viodasd_driver);
803 if (rc == 0)
804 driver_create_file(&viodasd_driver.driver, &driver_attr_probe);
805 return rc;
806 }
807 module_init(viodasd_init);
809 void viodasd_exit(void)
810 {
811 driver_remove_file(&viodasd_driver.driver, &driver_attr_probe);
812 vio_unregister_driver(&viodasd_driver);
813 vio_clearHandler(viomajorsubtype_blockio);
814 unregister_blkdev(VIODASD_MAJOR, VIOD_GENHD_NAME);
815 viopath_close(viopath_hostLp, viomajorsubtype_blockio, VIOMAXREQ + 2);
816 }
818 module_exit(viodasd_exit);