X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=drivers%2Fblock%2Fviodasd.c;h=9e61fca46117e618677483aa74c2ac90c310352c;hb=b23c9cc0ce652089a2f0af8c7f1541f10dc9b5db;hp=af3969a9c96301d3ab515c44b1554c472ddcd4e3;hpb=27196c30db1ed4ab09c2071149b3324a1a53cfb9;p=linux-2.6 diff --git a/drivers/block/viodasd.c b/drivers/block/viodasd.c index af3969a9c9..9e61fca461 100644 --- a/drivers/block/viodasd.c +++ b/drivers/block/viodasd.c @@ -41,6 +41,7 @@ #include #include #include +#include #include #include @@ -74,53 +75,9 @@ enum { static DEFINE_SPINLOCK(viodasd_spinlock); #define VIOMAXREQ 16 -#define VIOMAXBLOCKDMA 12 #define DEVICE_NO(cell) ((struct viodasd_device *)(cell) - &viodasd_devices[0]) -struct open_data { - u64 disk_size; - u16 max_disk; - u16 cylinders; - u16 tracks; - u16 sectors; - u16 bytes_per_sector; -}; - -struct rw_data { - u64 offset; - struct { - u32 token; - u32 reserved; - u64 len; - } dma_info[VIOMAXBLOCKDMA]; -}; - -struct vioblocklpevent { - struct HvLpEvent event; - u32 reserved; - u16 version; - u16 sub_result; - u16 disk; - u16 flags; - union { - struct open_data open_data; - struct rw_data rw_data; - u64 changed; - } u; -}; - -#define vioblockflags_ro 0x0001 - -enum vioblocksubtype { - vioblockopen = 0x0001, - vioblockclose = 0x0002, - vioblockread = 0x0003, - vioblockwrite = 0x0004, - vioblockflush = 0x0005, - vioblockcheck = 0x0007 -}; - struct viodasd_waitevent { struct completion com; int rc; @@ -272,13 +229,10 @@ static struct block_device_operations viodasd_fops = { /* * End a request */ -static void viodasd_end_request(struct request *req, int uptodate, +static void viodasd_end_request(struct request *req, int error, int num_sectors) { - if (end_that_request_first(req, uptodate, num_sectors)) - return; - add_disk_randomness(req->rq_disk); - end_that_request_last(req, uptodate); + __blk_end_request(req, error, num_sectors << 9); } /* @@ -314,6 +268,7 @@ static int send_request(struct request *req) d = req->rq_disk->private_data; /* Now build the scatter-gather list */ + sg_init_table(sg, VIOMAXBLOCKDMA); nsg = blk_rq_map_sg(req->q, req, sg); nsg = dma_map_sg(d->dev, sg, nsg, direction); @@ -416,12 +371,12 @@ static void do_viodasd_request(struct request_queue *q) blkdev_dequeue_request(req); /* check that request contains a valid command */ if (!blk_fs_request(req)) { - viodasd_end_request(req, 0, req->hard_nr_sectors); + viodasd_end_request(req, -EIO, req->hard_nr_sectors); continue; } /* Try sending the request */ if (send_request(req) != 0) - viodasd_end_request(req, 0, req->hard_nr_sectors); + viodasd_end_request(req, -EIO, req->hard_nr_sectors); } } @@ -429,7 +384,7 @@ static void do_viodasd_request(struct request_queue *q) * Probe a single disk and fill in the viodasd_device structure * for it. */ -static void probe_disk(struct viodasd_device *d) +static int probe_disk(struct viodasd_device *d) { HvLpEvent_Rc hvrc; struct viodasd_waitevent we; @@ -453,14 +408,14 @@ retry: 0, 0, 0); if (hvrc != 0) { printk(VIOD_KERN_WARNING "bad rc on HV open %d\n", (int)hvrc); - return; + return 0; } wait_for_completion(&we.com); if (we.rc != 0) { if (flags != 0) - return; + return 0; /* try again with read only flag set */ flags = vioblockflags_ro; goto retry; @@ -490,15 +445,32 @@ retry: if (hvrc != 0) { printk(VIOD_KERN_WARNING "bad rc sending event to OS/400 %d\n", (int)hvrc); - return; + return 0; + } + + if (d->dev == NULL) { + /* this is when we reprobe for new disks */ + if (vio_create_viodasd(dev_no) == NULL) { + printk(VIOD_KERN_WARNING + "cannot allocate virtual device for disk %d\n", + dev_no); + return 0; + } + /* + * The vio_create_viodasd will have recursed into this + * routine with d->dev set to the new vio device and + * will finish the setup of the disk below. + */ + return 1; } + /* create the request queue for the disk */ spin_lock_init(&d->q_lock); q = blk_init_queue(do_viodasd_request, &d->q_lock); if (q == NULL) { printk(VIOD_KERN_WARNING "cannot allocate queue for disk %d\n", dev_no); - return; + return 0; } g = alloc_disk(1 << PARTITION_SHIFT); if (g == NULL) { @@ -506,7 +478,7 @@ retry: "cannot allocate disk structure for disk %d\n", dev_no); blk_cleanup_queue(q); - return; + return 0; } d->disk = g; @@ -538,6 +510,7 @@ retry: /* register us in the global list */ add_disk(g); + return 1; } /* returns the total number of scatterlist elements converted */ @@ -615,7 +588,7 @@ static int viodasd_handle_read_write(struct vioblocklpevent *bevent) num_req_outstanding--; spin_unlock_irqrestore(&viodasd_spinlock, irq_flags); - error = event->xRc != HvLpEvent_Rc_Good; + error = (event->xRc == HvLpEvent_Rc_Good) ? 0 : -EIO; if (error) { const struct vio_error_entry *err; err = vio_lookup_rc(viodasd_err_table, bevent->sub_result); @@ -625,7 +598,7 @@ static int viodasd_handle_read_write(struct vioblocklpevent *bevent) } qlock = req->q->queue_lock; spin_lock_irqsave(qlock, irq_flags); - viodasd_end_request(req, !error, num_sect); + viodasd_end_request(req, error, num_sect); spin_unlock_irqrestore(qlock, irq_flags); /* Finally, try to get more requests off of this device's queue */ @@ -718,8 +691,7 @@ static int viodasd_probe(struct vio_dev *vdev, const struct vio_device_id *id) struct viodasd_device *d = &viodasd_devices[vdev->unit_address]; d->dev = &vdev->dev; - probe_disk(d); - if (d->disk == NULL) + if (!probe_disk(d)) return -ENODEV; return 0; }