Merge branch 'for-3.10/drivers' of git://git.kernel.dk/linux-block
[linux-3.10.git] / drivers / block / mtip32xx / mtip32xx.c
index 32c6780..847107e 100644 (file)
@@ -728,7 +728,10 @@ static void mtip_async_complete(struct mtip_port *port,
        atomic_set(&port->commands[tag].active, 0);
        release_slot(port, tag);
 
-       up(&port->cmd_slot);
+       if (unlikely(command->unaligned))
+               up(&port->cmd_slot_unal);
+       else
+               up(&port->cmd_slot);
 }
 
 /*
@@ -1560,10 +1563,12 @@ static int mtip_get_identify(struct mtip_port *port, void __user *user_buffer)
        }
 #endif
 
+#ifdef MTIP_TRIM /* Disabling TRIM support temporarily */
        /* Demux ID.DRAT & ID.RZAT to determine trim support */
        if (port->identify[69] & (1 << 14) && port->identify[69] & (1 << 5))
                port->dd->trim_supp = true;
        else
+#endif
                port->dd->trim_supp = false;
 
        /* Set the identify buffer as valid. */
@@ -2557,7 +2562,7 @@ static int mtip_hw_ioctl(struct driver_data *dd, unsigned int cmd,
  */
 static void mtip_hw_submit_io(struct driver_data *dd, sector_t sector,
                              int nsect, int nents, int tag, void *callback,
-                             void *data, int dir)
+                             void *data, int dir, int unaligned)
 {
        struct host_to_dev_fis  *fis;
        struct mtip_port *port = dd->port;
@@ -2570,6 +2575,7 @@ static void mtip_hw_submit_io(struct driver_data *dd, sector_t sector,
 
        command->scatter_ents = nents;
 
+       command->unaligned = unaligned;
        /*
         * The number of retries for this command before it is
         * reported as a failure to the upper layers.
@@ -2598,6 +2604,9 @@ static void mtip_hw_submit_io(struct driver_data *dd, sector_t sector,
        fis->res3        = 0;
        fill_command_sg(dd, command, nents);
 
+       if (unaligned)
+               fis->device |= 1 << 7;
+
        /* Populate the command header */
        command->command_header->opts =
                        __force_bit2int cpu_to_le32(
@@ -2644,9 +2653,13 @@ static void mtip_hw_submit_io(struct driver_data *dd, sector_t sector,
  * return value
  *      None
  */
-static void mtip_hw_release_scatterlist(struct driver_data *dd, int tag)
+static void mtip_hw_release_scatterlist(struct driver_data *dd, int tag,
+                                                               int unaligned)
 {
+       struct semaphore *sem = unaligned ? &dd->port->cmd_slot_unal :
+                                                       &dd->port->cmd_slot;
        release_slot(dd->port, tag);
+       up(sem);
 }
 
 /*
@@ -2661,22 +2674,25 @@ static void mtip_hw_release_scatterlist(struct driver_data *dd, int tag)
  *     or NULL if no command slots are available.
  */
 static struct scatterlist *mtip_hw_get_scatterlist(struct driver_data *dd,
-                                                  int *tag)
+                                                  int *tag, int unaligned)
 {
+       struct semaphore *sem = unaligned ? &dd->port->cmd_slot_unal :
+                                                       &dd->port->cmd_slot;
+
        /*
         * It is possible that, even with this semaphore, a thread
         * may think that no command slots are available. Therefore, we
         * need to make an attempt to get_slot().
         */
-       down(&dd->port->cmd_slot);
+       down(sem);
        *tag = get_slot(dd->port);
 
        if (unlikely(test_bit(MTIP_DDF_REMOVE_PENDING_BIT, &dd->dd_flag))) {
-               up(&dd->port->cmd_slot);
+               up(sem);
                return NULL;
        }
        if (unlikely(*tag < 0)) {
-               up(&dd->port->cmd_slot);
+               up(sem);
                return NULL;
        }
 
@@ -3010,6 +3026,11 @@ static inline void hba_setup(struct driver_data *dd)
                dd->mmio + HOST_HSORG);
 }
 
+static int mtip_device_unaligned_constrained(struct driver_data *dd)
+{
+       return (dd->pdev->device == P420M_DEVICE_ID ? 1 : 0);
+}
+
 /*
  * Detect the details of the product, and store anything needed
  * into the driver data structure.  This includes product type and
@@ -3232,8 +3253,15 @@ static int mtip_hw_init(struct driver_data *dd)
        for (i = 0; i < MTIP_MAX_SLOT_GROUPS; i++)
                dd->work[i].port = dd->port;
 
+       /* Enable unaligned IO constraints for some devices */
+       if (mtip_device_unaligned_constrained(dd))
+               dd->unal_qdepth = MTIP_MAX_UNALIGNED_SLOTS;
+       else
+               dd->unal_qdepth = 0;
+
        /* Counting semaphore to track command slot usage */
-       sema_init(&dd->port->cmd_slot, num_command_slots - 1);
+       sema_init(&dd->port->cmd_slot, num_command_slots - 1 - dd->unal_qdepth);
+       sema_init(&dd->port->cmd_slot_unal, dd->unal_qdepth);
 
        /* Spinlock to prevent concurrent issue */
        for (i = 0; i < MTIP_MAX_SLOT_GROUPS; i++)
@@ -3836,7 +3864,7 @@ static void mtip_make_request(struct request_queue *queue, struct bio *bio)
        struct scatterlist *sg;
        struct bio_vec *bvec;
        int nents = 0;
-       int tag = 0;
+       int tag = 0, unaligned = 0;
 
        if (unlikely(dd->dd_flag & MTIP_DDF_STOP_IO)) {
                if (unlikely(test_bit(MTIP_DDF_REMOVE_PENDING_BIT,
@@ -3872,7 +3900,15 @@ static void mtip_make_request(struct request_queue *queue, struct bio *bio)
                return;
        }
 
-       sg = mtip_hw_get_scatterlist(dd, &tag);
+       if (bio_data_dir(bio) == WRITE && bio_sectors(bio) <= 64 &&
+                                                       dd->unal_qdepth) {
+               if (bio->bi_sector % 8 != 0) /* Unaligned on 4k boundaries */
+                       unaligned = 1;
+               else if (bio_sectors(bio) % 8 != 0) /* Aligned but not 4k/8k */
+                       unaligned = 1;
+       }
+
+       sg = mtip_hw_get_scatterlist(dd, &tag, unaligned);
        if (likely(sg != NULL)) {
                blk_queue_bounce(queue, &bio);
 
@@ -3880,7 +3916,7 @@ static void mtip_make_request(struct request_queue *queue, struct bio *bio)
                        dev_warn(&dd->pdev->dev,
                                "Maximum number of SGL entries exceeded\n");
                        bio_io_error(bio);
-                       mtip_hw_release_scatterlist(dd, tag);
+                       mtip_hw_release_scatterlist(dd, tag, unaligned);
                        return;
                }
 
@@ -3900,7 +3936,8 @@ static void mtip_make_request(struct request_queue *queue, struct bio *bio)
                                tag,
                                bio_endio,
                                bio,
-                               bio_data_dir(bio));
+                               bio_data_dir(bio),
+                               unaligned);
        } else
                bio_io_error(bio);
 }
@@ -4156,26 +4193,24 @@ static int mtip_block_remove(struct driver_data *dd)
  */
 static int mtip_block_shutdown(struct driver_data *dd)
 {
-       dev_info(&dd->pdev->dev,
-               "Shutting down %s ...\n", dd->disk->disk_name);
-
        /* Delete our gendisk structure, and cleanup the blk queue. */
        if (dd->disk) {
-               if (dd->disk->queue)
+               dev_info(&dd->pdev->dev,
+                       "Shutting down %s ...\n", dd->disk->disk_name);
+
+               if (dd->disk->queue) {
                        del_gendisk(dd->disk);
-               else
+                       blk_cleanup_queue(dd->queue);
+               } else
                        put_disk(dd->disk);
+               dd->disk  = NULL;
+               dd->queue = NULL;
        }
 
-
        spin_lock(&rssd_index_lock);
        ida_remove(&rssd_index_ida, dd->index);
        spin_unlock(&rssd_index_lock);
 
-       blk_cleanup_queue(dd->queue);
-       dd->disk  = NULL;
-       dd->queue = NULL;
-
        mtip_hw_shutdown(dd);
        return 0;
 }