block: add rq->resid_len
[safe/jmp/linux-2.6] / drivers / block / xsysace.c
index 3847464..b1e1d7e 100644 (file)
@@ -89,6 +89,7 @@
 #include <linux/delay.h>
 #include <linux/slab.h>
 #include <linux/blkdev.h>
+#include <linux/ata.h>
 #include <linux/hdreg.h>
 #include <linux/platform_device.h>
 #if defined(CONFIG_OF)
@@ -194,8 +195,8 @@ struct ace_device {
        int in_irq;
 
        /* Details of hardware device */
-       unsigned long physaddr;
-       void *baseaddr;
+       resource_size_t physaddr;
+       void __iomem *baseaddr;
        int irq;
        int bus_width;          /* 0 := 8 bit; 1 := 16 bit */
        struct ace_reg_ops *reg_ops;
@@ -208,7 +209,7 @@ struct ace_device {
        struct gendisk *gd;
 
        /* Inserted CF card parameters */
-       struct hd_driveid cf_id;
+       u16 cf_id[ATA_ID_WORDS];
 };
 
 static int ace_major;
@@ -227,20 +228,20 @@ struct ace_reg_ops {
 /* 8 Bit bus width */
 static u16 ace_in_8(struct ace_device *ace, int reg)
 {
-       void *r = ace->baseaddr + reg;
+       void __iomem *r = ace->baseaddr + reg;
        return in_8(r) | (in_8(r + 1) << 8);
 }
 
 static void ace_out_8(struct ace_device *ace, int reg, u16 val)
 {
-       void *r = ace->baseaddr + reg;
+       void __iomem *r = ace->baseaddr + reg;
        out_8(r, val);
        out_8(r + 1, val >> 8);
 }
 
 static void ace_datain_8(struct ace_device *ace)
 {
-       void *r = ace->baseaddr + 0x40;
+       void __iomem *r = ace->baseaddr + 0x40;
        u8 *dst = ace->data_ptr;
        int i = ACE_FIFO_SIZE;
        while (i--)
@@ -250,7 +251,7 @@ static void ace_datain_8(struct ace_device *ace)
 
 static void ace_dataout_8(struct ace_device *ace)
 {
-       void *r = ace->baseaddr + 0x40;
+       void __iomem *r = ace->baseaddr + 0x40;
        u8 *src = ace->data_ptr;
        int i = ACE_FIFO_SIZE;
        while (i--)
@@ -390,8 +391,8 @@ static inline void ace_dump_mem(void *base, int len)
 static void ace_dump_regs(struct ace_device *ace)
 {
        dev_info(ace->dev, "    ctrl:  %.8x  seccnt/cmd: %.4x      ver:%.4x\n"
-                "    status:%.8x  mpu_lba:%.8x  busmode:%4x\n"
-                "    error: %.8x  cfg_lba:%.8x  fatstat:%.4x\n",
+                KERN_INFO "    status:%.8x  mpu_lba:%.8x  busmode:%4x\n"
+                KERN_INFO "    error: %.8x  cfg_lba:%.8x  fatstat:%.4x\n",
                 ace_in32(ace, ACE_CTRL),
                 ace_in(ace, ACE_SECCNTCMD),
                 ace_in(ace, ACE_VERSION),
@@ -402,21 +403,14 @@ static void ace_dump_regs(struct ace_device *ace)
                 ace_in32(ace, ACE_CFGLBA), ace_in(ace, ACE_FATSTAT));
 }
 
-void ace_fix_driveid(struct hd_driveid *id)
+void ace_fix_driveid(u16 *id)
 {
 #if defined(__BIG_ENDIAN)
-       u16 *buf = (void *)id;
        int i;
 
        /* All half words have wrong byte order; swap the bytes */
-       for (i = 0; i < sizeof(struct hd_driveid); i += 2, buf++)
-               *buf = le16_to_cpu(*buf);
-
-       /* Some of the data values are 32bit; swap the half words  */
-       id->lba_capacity = ((id->lba_capacity >> 16) & 0x0000FFFF) |
-           ((id->lba_capacity << 16) & 0xFFFF0000);
-       id->spg = ((id->spg >> 16) & 0x0000FFFF) |
-           ((id->spg << 16) & 0xFFFF0000);
+       for (i = 0; i < ATA_ID_WORDS; i++, id++)
+               *id = le16_to_cpu(*id);
 #endif
 }
 
@@ -472,7 +466,7 @@ struct request *ace_get_next_request(struct request_queue * q)
        while ((req = elv_next_request(q)) != NULL) {
                if (blk_fs_request(req))
                        break;
-               end_request(req, 0);
+               __blk_end_request_cur(req, -EIO);
        }
        return req;
 }
@@ -483,13 +477,34 @@ static void ace_fsm_dostate(struct ace_device *ace)
        u32 status;
        u16 val;
        int count;
-       int i;
 
 #if defined(DEBUG)
        dev_dbg(ace->dev, "fsm_state=%i, id_req_count=%i\n",
                ace->fsm_state, ace->id_req_count);
 #endif
 
+       /* Verify that there is actually a CF in the slot. If not, then
+        * bail out back to the idle state and wake up all the waiters */
+       status = ace_in32(ace, ACE_STATUS);
+       if ((status & ACE_STATUS_CFDETECT) == 0) {
+               ace->fsm_state = ACE_FSM_STATE_IDLE;
+               ace->media_change = 1;
+               set_capacity(ace->gd, 0);
+               dev_info(ace->dev, "No CF in slot\n");
+
+               /* Drop all pending requests */
+               while ((req = elv_next_request(ace->queue)) != NULL)
+                       __blk_end_request_cur(req, -EIO);
+
+               /* Drop back to IDLE state and notify waiters */
+               ace->fsm_state = ACE_FSM_STATE_IDLE;
+               ace->id_result = -EIO;
+               while (ace->id_req_count) {
+                       complete(&ace->id_completion);
+                       ace->id_req_count--;
+               }
+       }
+
        switch (ace->fsm_state) {
        case ACE_FSM_STATE_IDLE:
                /* See if there is anything to do */
@@ -548,7 +563,7 @@ static void ace_fsm_dostate(struct ace_device *ace)
        case ACE_FSM_STATE_IDENTIFY_PREPARE:
                /* Send identify command */
                ace->fsm_task = ACE_TASK_IDENTIFY;
-               ace->data_ptr = &ace->cf_id;
+               ace->data_ptr = ace->cf_id;
                ace->data_count = ACE_BUF_PER_SECTOR;
                ace_out(ace, ACE_SECCNTCMD, ACE_SECCNTCMD_IDENTIFY);
 
@@ -593,8 +608,8 @@ static void ace_fsm_dostate(struct ace_device *ace)
                break;
 
        case ACE_FSM_STATE_IDENTIFY_COMPLETE:
-               ace_fix_driveid(&ace->cf_id);
-               ace_dump_mem(&ace->cf_id, 512); /* Debug: Dump out disk ID */
+               ace_fix_driveid(ace->cf_id);
+               ace_dump_mem(ace->cf_id, 512);  /* Debug: Dump out disk ID */
 
                if (ace->data_result) {
                        /* Error occured, disable the disk */
@@ -606,9 +621,10 @@ static void ace_fsm_dostate(struct ace_device *ace)
                        ace->media_change = 0;
 
                        /* Record disk parameters */
-                       set_capacity(ace->gd, ace->cf_id.lba_capacity);
+                       set_capacity(ace->gd,
+                               ata_id_u32(ace->cf_id, ATA_ID_LBA_CAPACITY));
                        dev_info(ace->dev, "capacity: %i sectors\n",
-                                ace->cf_id.lba_capacity);
+                               ata_id_u32(ace->cf_id, ATA_ID_LBA_CAPACITY));
                }
 
                /* We're done, drop to IDLE state and notify waiters */
@@ -629,8 +645,8 @@ static void ace_fsm_dostate(struct ace_device *ace)
 
                /* Okay, it's a data request, set it up for transfer */
                dev_dbg(ace->dev,
-                       "request: sec=%lx hcnt=%lx, ccnt=%x, dir=%i\n",
-                       req->sector, req->hard_nr_sectors,
+                       "request: sec=%llx hcnt=%lx, ccnt=%x, dir=%i\n",
+                       (unsigned long long) req->sector, req->hard_nr_sectors,
                        req->current_nr_sectors, rq_data_dir(req));
 
                ace->req = req;
@@ -688,7 +704,6 @@ static void ace_fsm_dostate(struct ace_device *ace)
                }
 
                /* Transfer the next buffer */
-               i = 16;
                if (ace->fsm_task == ACE_TASK_WRITE)
                        ace->reg_ops->dataout(ace);
                else
@@ -702,8 +717,8 @@ static void ace_fsm_dostate(struct ace_device *ace)
                }
 
                /* bio finished; is there another one? */
-               i = ace->req->current_nr_sectors;
-               if (end_that_request_first(ace->req, 1, i)) {
+               if (__blk_end_request(ace->req, 0,
+                                       blk_rq_cur_bytes(ace->req))) {
                        /* dev_dbg(ace->dev, "next block; h=%li c=%i\n",
                         *      ace->req->hard_nr_sectors,
                         *      ace->req->current_nr_sectors);
@@ -718,9 +733,6 @@ static void ace_fsm_dostate(struct ace_device *ace)
                break;
 
        case ACE_FSM_STATE_REQ_COMPLETE:
-               /* Complete the block request */
-               blkdev_dequeue_request(ace->req);
-               end_that_request_last(ace->req, 1);
                ace->req = NULL;
 
                /* Finished request; go to idle state */
@@ -875,25 +887,24 @@ static int ace_revalidate_disk(struct gendisk *gd)
        return ace->id_result;
 }
 
-static int ace_open(struct inode *inode, struct file *filp)
+static int ace_open(struct block_device *bdev, fmode_t mode)
 {
-       struct ace_device *ace = inode->i_bdev->bd_disk->private_data;
+       struct ace_device *ace = bdev->bd_disk->private_data;
        unsigned long flags;
 
        dev_dbg(ace->dev, "ace_open() users=%i\n", ace->users + 1);
 
-       filp->private_data = ace;
        spin_lock_irqsave(&ace->lock, flags);
        ace->users++;
        spin_unlock_irqrestore(&ace->lock, flags);
 
-       check_disk_change(inode->i_bdev);
+       check_disk_change(bdev);
        return 0;
 }
 
-static int ace_release(struct inode *inode, struct file *filp)
+static int ace_release(struct gendisk *disk, fmode_t mode)
 {
-       struct ace_device *ace = inode->i_bdev->bd_disk->private_data;
+       struct ace_device *ace = disk->private_data;
        unsigned long flags;
        u16 val;
 
@@ -912,12 +923,13 @@ static int ace_release(struct inode *inode, struct file *filp)
 static int ace_getgeo(struct block_device *bdev, struct hd_geometry *geo)
 {
        struct ace_device *ace = bdev->bd_disk->private_data;
+       u16 *cf_id = ace->cf_id;
 
        dev_dbg(ace->dev, "ace_getgeo()\n");
 
-       geo->heads = ace->cf_id.heads;
-       geo->sectors = ace->cf_id.sectors;
-       geo->cylinders = ace->cf_id.cyls;
+       geo->heads      = cf_id[ATA_ID_HEADS];
+       geo->sectors    = cf_id[ATA_ID_SECTORS];
+       geo->cylinders  = cf_id[ATA_ID_CYLS];
 
        return 0;
 }
@@ -941,7 +953,8 @@ static int __devinit ace_setup(struct ace_device *ace)
        int rc;
 
        dev_dbg(ace->dev, "ace_setup(ace=0x%p)\n", ace);
-       dev_dbg(ace->dev, "physaddr=0x%lx irq=%i\n", ace->physaddr, ace->irq);
+       dev_dbg(ace->dev, "physaddr=0x%llx irq=%i\n",
+               (unsigned long long)ace->physaddr, ace->irq);
 
        spin_lock_init(&ace->lock);
        init_completion(&ace->id_completion);
@@ -1005,11 +1018,6 @@ static int __devinit ace_setup(struct ace_device *ace)
        ace_out(ace, ACE_CTRL, ACE_CTRL_FORCECFGMODE |
                ACE_CTRL_DATABUFRDYIRQ | ACE_CTRL_ERRORIRQ);
 
-       /* Enable interrupts */
-       val = ace_in(ace, ACE_CTRL);
-       val |= ACE_CTRL_DATABUFRDYIRQ | ACE_CTRL_ERRORIRQ;
-       ace_out(ace, ACE_CTRL, val);
-
        /* Now we can hook up the irq handler */
        if (ace->irq != NO_IRQ) {
                rc = request_irq(ace->irq, ace_interrupt, 0, "systemace", ace);
@@ -1020,11 +1028,16 @@ static int __devinit ace_setup(struct ace_device *ace)
                }
        }
 
+       /* Enable interrupts */
+       val = ace_in(ace, ACE_CTRL);
+       val |= ACE_CTRL_DATABUFRDYIRQ | ACE_CTRL_ERRORIRQ;
+       ace_out(ace, ACE_CTRL, val);
+
        /* Print the identification */
        dev_info(ace->dev, "Xilinx SystemACE revision %i.%i.%i\n",
                 (version >> 12) & 0xf, (version >> 8) & 0x0f, version & 0xff);
-       dev_dbg(ace->dev, "physaddr 0x%lx, mapped to 0x%p, irq=%i\n",
-               ace->physaddr, ace->baseaddr, ace->irq);
+       dev_dbg(ace->dev, "physaddr 0x%llx, mapped to 0x%p, irq=%i\n",
+               (unsigned long long) ace->physaddr, ace->baseaddr, ace->irq);
 
        ace->media_change = 1;
        ace_revalidate_disk(ace->gd);
@@ -1041,8 +1054,8 @@ err_alloc_disk:
 err_blk_initq:
        iounmap(ace->baseaddr);
 err_ioremap:
-       dev_info(ace->dev, "xsysace: error initializing device at 0x%lx\n",
-              ace->physaddr);
+       dev_info(ace->dev, "xsysace: error initializing device at 0x%llx\n",
+                (unsigned long long) ace->physaddr);
        return -ENOMEM;
 }
 
@@ -1065,7 +1078,7 @@ static void __devexit ace_teardown(struct ace_device *ace)
 }
 
 static int __devinit
-ace_alloc(struct device *dev, int id, unsigned long physaddr,
+ace_alloc(struct device *dev, int id, resource_size_t physaddr,
          int irq, int bus_width)
 {
        struct ace_device *ace;
@@ -1125,7 +1138,7 @@ static void __devexit ace_free(struct device *dev)
 
 static int __devinit ace_probe(struct platform_device *dev)
 {
-       unsigned long physaddr = 0;
+       resource_size_t physaddr = 0;
        int bus_width = ACE_BUS_WIDTH_16; /* FIXME: should not be hard coded */
        int id = dev->id;
        int irq = NO_IRQ;
@@ -1171,7 +1184,7 @@ static int __devinit
 ace_of_probe(struct of_device *op, const struct of_device_id *match)
 {
        struct resource res;
-       unsigned long physaddr;
+       resource_size_t physaddr;
        const u32 *id;
        int irq, bus_width, rc;
 
@@ -1207,8 +1220,11 @@ static int __devexit ace_of_remove(struct of_device *op)
 }
 
 /* Match table for of_platform binding */
-static struct of_device_id __devinit ace_of_match[] = {
-       { .compatible = "xilinx,xsysace", },
+static struct of_device_id ace_of_match[] __devinitdata = {
+       { .compatible = "xlnx,opb-sysace-1.00.b", },
+       { .compatible = "xlnx,opb-sysace-1.00.c", },
+       { .compatible = "xlnx,xps-sysace-1.00.a", },
+       { .compatible = "xlnx,sysace", },
        {},
 };
 MODULE_DEVICE_TABLE(of, ace_of_match);