Fedora kernel-2.6.17-1.2142_FC4 patched with stable patch-2.6.17.4-vs2.0.2-rc26.diff
[linux-2.6.git] / drivers / block / sx8.c
index 797f598..2ae08b3 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  sx8.c: Driver for Promise SATA SX8 looks-like-I2O hardware
  *
- *  Copyright 2004 Red Hat, Inc.
+ *  Copyright 2004-2005 Red Hat, Inc.
  *
  *  Author/maintainer:  Jeff Garzik <jgarzik@pobox.com>
  *
 #include <linux/delay.h>
 #include <linux/time.h>
 #include <linux/hdreg.h>
+#include <linux/dma-mapping.h>
+#include <linux/completion.h>
 #include <asm/io.h>
-#include <asm/semaphore.h>
 #include <asm/uaccess.h>
 
-MODULE_AUTHOR("Jeff Garzik");
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Promise SATA SX8 block driver");
-
 #if 0
 #define CARM_DEBUG
 #define CARM_VERBOSE_DEBUG
@@ -44,9 +41,35 @@ MODULE_DESCRIPTION("Promise SATA SX8 block driver");
 #undef CARM_NDEBUG
 
 #define DRV_NAME "sx8"
-#define DRV_VERSION "0.8"
+#define DRV_VERSION "1.0"
 #define PFX DRV_NAME ": "
 
+MODULE_AUTHOR("Jeff Garzik");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Promise SATA SX8 block driver");
+MODULE_VERSION(DRV_VERSION);
+
+/*
+ * SX8 hardware has a single message queue for all ATA ports.
+ * When this driver was written, the hardware (firmware?) would
+ * corrupt data eventually, if more than one request was outstanding.
+ * As one can imagine, having 8 ports bottlenecking on a single
+ * command hurts performance.
+ *
+ * Based on user reports, later versions of the hardware (firmware?)
+ * seem to be able to survive with more than one command queued.
+ *
+ * Therefore, we default to the safe option -- 1 command -- but
+ * allow the user to increase this.
+ *
+ * SX8 should be able to support up to ~60 queued commands (CARM_MAX_REQ),
+ * but problems seem to occur when you exceed ~30, even on newer hardware.
+ */
+static int max_queue = 1;
+module_param(max_queue, int, 0444);
+MODULE_PARM_DESC(max_queue, "Maximum number of queued commands. (min==1, max==30, safe==1)");
+
+
 #define NEXT_RESP(idx) ((idx + 1) % RMSG_Q_LEN)
 
 /* 0xf is just arbitrary, non-zero noise; this is sorta like poisoning */
@@ -89,12 +112,10 @@ enum {
 
        /* command message queue limits */
        CARM_MAX_REQ            = 64,          /* max command msgs per host */
-       CARM_MAX_Q              = 1,               /* one command at a time */
        CARM_MSG_LOW_WATER      = (CARM_MAX_REQ / 4),        /* refill mark */
 
        /* S/G limits, host-wide and per-request */
        CARM_MAX_REQ_SG         = 32,        /* max s/g entries per request */
-       CARM_SG_BOUNDARY        = 0xffffUL,         /* s/g segment boundary */
        CARM_MAX_HOST_SG        = 600,          /* max s/g entries per host */
        CARM_SG_LOW_WATER       = (CARM_MAX_HOST_SG / 4),   /* re-fill mark */
 
@@ -180,6 +201,10 @@ enum {
        FL_DYN_MAJOR            = (1 << 17),
 };
 
+enum {
+       CARM_SG_BOUNDARY        = 0xffffUL,         /* s/g segment boundary */
+};
+
 enum scatter_gather_types {
        SGT_32BIT               = 0,
        SGT_64BIT               = 1,
@@ -217,7 +242,6 @@ static const char *state_name[] = {
 
 struct carm_port {
        unsigned int                    port_no;
-       unsigned int                    n_queued;
        struct gendisk                  *disk;
        struct carm_host                *host;
 
@@ -279,7 +303,7 @@ struct carm_host {
 
        struct work_struct              fsm_task;
 
-       struct semaphore                probe_sem;
+       struct completion               probe_comp;
 };
 
 struct carm_response {
@@ -383,8 +407,7 @@ struct carm_array_info {
 
 static int carm_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
 static void carm_remove_one (struct pci_dev *pdev);
-static int carm_bdev_ioctl(struct inode *ino, struct file *fil,
-                          unsigned int cmd, unsigned long arg);
+static int carm_bdev_getgeo(struct block_device *bdev, struct hd_geometry *geo);
 
 static struct pci_device_id carm_pci_tbl[] = {
        { PCI_VENDOR_ID_PROMISE, 0x8000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
@@ -402,7 +425,7 @@ static struct pci_driver carm_driver = {
 
 static struct block_device_operations carm_bd_ops = {
        .owner          = THIS_MODULE,
-       .ioctl          = carm_bdev_ioctl,
+       .getgeo         = carm_bdev_getgeo,
 };
 
 static unsigned int carm_host_id;
@@ -410,32 +433,14 @@ static unsigned long carm_major_alloc;
 
 
 
-static int carm_bdev_ioctl(struct inode *ino, struct file *fil,
-                          unsigned int cmd, unsigned long arg)
+static int carm_bdev_getgeo(struct block_device *bdev, struct hd_geometry *geo)
 {
-       void __user *usermem = (void __user *) arg;
-       struct carm_port *port = ino->i_bdev->bd_disk->private_data;
-       struct hd_geometry geom;
-
-       switch (cmd) {
-       case HDIO_GETGEO:
-               if (!usermem)
-                       return -EINVAL;
-
-               geom.heads = (u8) port->dev_geom_head;
-               geom.sectors = (u8) port->dev_geom_sect;
-               geom.cylinders = port->dev_geom_cyl;
-               geom.start = get_start_sect(ino->i_bdev);
-
-               if (copy_to_user(usermem, &geom, sizeof(geom)))
-                       return -EFAULT;
-               return 0;
+       struct carm_port *port = bdev->bd_disk->private_data;
 
-       default:
-               break;
-       }
-
-       return -EOPNOTSUPP;
+       geo->heads = (u8) port->dev_geom_head;
+       geo->sectors = (u8) port->dev_geom_sect;
+       geo->cylinders = port->dev_geom_cyl;
+       return 0;
 }
 
 static const u32 msg_sizes[] = { 32, 64, 128, CARM_MSG_SIZE };
@@ -447,7 +452,7 @@ static inline int carm_lookup_bucket(u32 msg_size)
        for (i = 0; i < ARRAY_SIZE(msg_sizes); i++)
                if (msg_size <= msg_sizes[i])
                        return i;
-       
+
        return -ENOENT;
 }
 
@@ -508,7 +513,7 @@ static struct carm_request *carm_get_request(struct carm_host *host)
        if (host->hw_sg_used >= (CARM_MAX_HOST_SG - CARM_MAX_REQ_SG))
                return NULL;
 
-       for (i = 0; i < CARM_MAX_Q; i++)
+       for (i = 0; i < max_queue; i++)
                if ((host->msg_alloc & (1ULL << i)) == 0) {
                        struct carm_request *crq = &host->req[i];
                        crq->port = NULL;
@@ -520,14 +525,14 @@ static struct carm_request *carm_get_request(struct carm_host *host)
                        assert(host->n_msgs <= CARM_MAX_REQ);
                        return crq;
                }
-       
+
        DPRINTK("no request available, returning NULL\n");
        return NULL;
 }
 
 static int carm_put_request(struct carm_host *host, struct carm_request *crq)
 {
-       assert(crq->tag < CARM_MAX_Q);
+       assert(crq->tag < max_queue);
 
        if (unlikely((host->msg_alloc & (1ULL << crq->tag)) == 0))
                return -EINVAL; /* tried to clear a tag that was not active */
@@ -614,7 +619,7 @@ static int carm_array_info (struct carm_host *host, unsigned int array_idx)
        spin_unlock_irq(&host->lock);
 
        DPRINTK("blk_insert_request, tag == %u\n", idx);
-       blk_insert_request(host->oob_q, crq->rq, 1, crq, 0);
+       blk_insert_request(host->oob_q, crq->rq, 1, crq);
 
        return 0;
 
@@ -653,7 +658,7 @@ static int carm_send_special (struct carm_host *host, carm_sspc_t func)
        crq->msg_bucket = (u32) rc;
 
        DPRINTK("blk_insert_request, tag == %u\n", idx);
-       blk_insert_request(host->oob_q, crq->rq, 1, crq, 0);
+       blk_insert_request(host->oob_q, crq->rq, 1, crq);
 
        return 0;
 }
@@ -746,7 +751,7 @@ static inline void carm_end_request_queued(struct carm_host *host,
        rc = end_that_request_first(req, uptodate, req->hard_nr_sectors);
        assert(rc == 0);
 
-       end_that_request_last(req);
+       end_that_request_last(req, uptodate);
 
        rc = carm_put_request(host, crq);
        assert(rc == 0);
@@ -790,7 +795,7 @@ static inline void carm_end_rq(struct carm_host *host, struct carm_request *crq,
                        int is_ok)
 {
        carm_end_request_queued(host, crq, is_ok);
-       if (CARM_MAX_Q == 1)
+       if (max_queue == 1)
                carm_round_robin(host);
        else if ((host->n_msgs <= CARM_MSG_LOW_WATER) &&
                 (host->hw_sg_used <= CARM_SG_LOW_WATER)) {
@@ -1341,7 +1346,7 @@ static void carm_fsm_task (void *_data)
        }
 
        case HST_PROBE_FINISHED:
-               up(&host->probe_sem);
+               complete(&host->probe_comp);
                break;
 
        case HST_ERROR:
@@ -1581,10 +1586,10 @@ static int carm_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
        if (rc)
                goto err_out;
 
-#if IF_64BIT_DMA_IS_POSSIBLE /* grrrr... */
-       rc = pci_set_dma_mask(pdev, 0xffffffffffffffffULL);
+#ifdef IF_64BIT_DMA_IS_POSSIBLE /* grrrr... */
+       rc = pci_set_dma_mask(pdev, DMA_64BIT_MASK);
        if (!rc) {
-               rc = pci_set_consistent_dma_mask(pdev, 0xffffffffffffffffULL);
+               rc = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
                if (rc) {
                        printk(KERN_ERR DRV_NAME "(%s): consistent DMA mask failure\n",
                                pci_name(pdev));
@@ -1593,14 +1598,14 @@ static int carm_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
                pci_dac = 1;
        } else {
 #endif
-               rc = pci_set_dma_mask(pdev, 0xffffffffULL);
+               rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
                if (rc) {
                        printk(KERN_ERR DRV_NAME "(%s): DMA mask failure\n",
                                pci_name(pdev));
                        goto err_out_regions;
                }
                pci_dac = 0;
-#if IF_64BIT_DMA_IS_POSSIBLE /* grrrr... */
+#ifdef IF_64BIT_DMA_IS_POSSIBLE /* grrrr... */
        }
 #endif
 
@@ -1617,7 +1622,7 @@ static int carm_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
        host->flags = pci_dac ? FL_DAC : 0;
        spin_lock_init(&host->lock);
        INIT_WORK(&host->fsm_task, carm_fsm_task, host);
-       init_MUTEX_LOCKED(&host->probe_sem);
+       init_completion(&host->probe_comp);
 
        for (i = 0; i < ARRAY_SIZE(host->req); i++)
                host->req[i].tag = i;
@@ -1686,8 +1691,8 @@ static int carm_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
        if (rc)
                goto err_out_free_irq;
 
-       DPRINTK("waiting for probe_sem\n");
-       down(&host->probe_sem);
+       DPRINTK("waiting for probe_comp\n");
+       wait_for_completion(&host->probe_comp);
 
        printk(KERN_INFO "%s: pci %s, ports %d, io %lx, irq %u, major %d\n",
               host->name, pci_name(pdev), (int) CARM_MAX_PORTS,
@@ -1750,7 +1755,7 @@ static void carm_remove_one (struct pci_dev *pdev)
 
 static int __init carm_init(void)
 {
-       return pci_module_init(&carm_driver);
+       return pci_register_driver(&carm_driver);
 }
 
 static void __exit carm_exit(void)