diff options
author | Asai Thambi S P <asamymuthupa@micron.com> | 2013-04-29 15:19:49 -0400 |
---|---|---|
committer | Jens Axboe <axboe@kernel.dk> | 2013-04-29 15:19:49 -0400 |
commit | 2077d947260c620550ba06f76aa4affd0106f4da (patch) | |
tree | 1c81837535f27e94ff0fb6d57db47c0c5cf61bde /drivers/block/mtip32xx/mtip32xx.c | |
parent | 68466cbf92367c0808bfd2c64bc6faddd7a97b6f (diff) |
mtip32xx: Workaround for unaligned writes
Workaround for handling unaligned writes: limit number of outstanding
unaligned writes
Signed-off-by: Sam Bradshaw <sbradshaw@micron.com>
Signed-off-by: Asai Thambi S P <asamymuthupa@micron.com>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
Diffstat (limited to 'drivers/block/mtip32xx/mtip32xx.c')
-rw-r--r-- | drivers/block/mtip32xx/mtip32xx.c | 59 |
1 files changed, 47 insertions, 12 deletions
diff --git a/drivers/block/mtip32xx/mtip32xx.c b/drivers/block/mtip32xx/mtip32xx.c index 30a03ab7efc9..c0d38734041c 100644 --- a/drivers/block/mtip32xx/mtip32xx.c +++ b/drivers/block/mtip32xx/mtip32xx.c | |||
@@ -712,7 +712,10 @@ static void mtip_async_complete(struct mtip_port *port, | |||
712 | atomic_set(&port->commands[tag].active, 0); | 712 | atomic_set(&port->commands[tag].active, 0); |
713 | release_slot(port, tag); | 713 | release_slot(port, tag); |
714 | 714 | ||
715 | up(&port->cmd_slot); | 715 | if (unlikely(command->unaligned)) |
716 | up(&port->cmd_slot_unal); | ||
717 | else | ||
718 | up(&port->cmd_slot); | ||
716 | } | 719 | } |
717 | 720 | ||
718 | /* | 721 | /* |
@@ -2557,7 +2560,7 @@ static int mtip_hw_ioctl(struct driver_data *dd, unsigned int cmd, | |||
2557 | */ | 2560 | */ |
2558 | static void mtip_hw_submit_io(struct driver_data *dd, sector_t sector, | 2561 | static void mtip_hw_submit_io(struct driver_data *dd, sector_t sector, |
2559 | int nsect, int nents, int tag, void *callback, | 2562 | int nsect, int nents, int tag, void *callback, |
2560 | void *data, int dir) | 2563 | void *data, int dir, int unaligned) |
2561 | { | 2564 | { |
2562 | struct host_to_dev_fis *fis; | 2565 | struct host_to_dev_fis *fis; |
2563 | struct mtip_port *port = dd->port; | 2566 | struct mtip_port *port = dd->port; |
@@ -2570,6 +2573,7 @@ static void mtip_hw_submit_io(struct driver_data *dd, sector_t sector, | |||
2570 | 2573 | ||
2571 | command->scatter_ents = nents; | 2574 | command->scatter_ents = nents; |
2572 | 2575 | ||
2576 | command->unaligned = unaligned; | ||
2573 | /* | 2577 | /* |
2574 | * The number of retries for this command before it is | 2578 | * The number of retries for this command before it is |
2575 | * reported as a failure to the upper layers. | 2579 | * reported as a failure to the upper layers. |
@@ -2598,6 +2602,9 @@ static void mtip_hw_submit_io(struct driver_data *dd, sector_t sector, | |||
2598 | fis->res3 = 0; | 2602 | fis->res3 = 0; |
2599 | fill_command_sg(dd, command, nents); | 2603 | fill_command_sg(dd, command, nents); |
2600 | 2604 | ||
2605 | if (unaligned) | ||
2606 | fis->device |= 1 << 7; | ||
2607 | |||
2601 | /* Populate the command header */ | 2608 | /* Populate the command header */ |
2602 | command->command_header->opts = | 2609 | command->command_header->opts = |
2603 | __force_bit2int cpu_to_le32( | 2610 | __force_bit2int cpu_to_le32( |
@@ -2644,9 +2651,13 @@ static void mtip_hw_submit_io(struct driver_data *dd, sector_t sector, | |||
2644 | * return value | 2651 | * return value |
2645 | * None | 2652 | * None |
2646 | */ | 2653 | */ |
2647 | static void mtip_hw_release_scatterlist(struct driver_data *dd, int tag) | 2654 | static void mtip_hw_release_scatterlist(struct driver_data *dd, int tag, |
2655 | int unaligned) | ||
2648 | { | 2656 | { |
2657 | struct semaphore *sem = unaligned ? &dd->port->cmd_slot_unal : | ||
2658 | &dd->port->cmd_slot; | ||
2649 | release_slot(dd->port, tag); | 2659 | release_slot(dd->port, tag); |
2660 | up(sem); | ||
2650 | } | 2661 | } |
2651 | 2662 | ||
2652 | /* | 2663 | /* |
@@ -2661,22 +2672,25 @@ static void mtip_hw_release_scatterlist(struct driver_data *dd, int tag) | |||
2661 | * or NULL if no command slots are available. | 2672 | * or NULL if no command slots are available. |
2662 | */ | 2673 | */ |
2663 | static struct scatterlist *mtip_hw_get_scatterlist(struct driver_data *dd, | 2674 | static struct scatterlist *mtip_hw_get_scatterlist(struct driver_data *dd, |
2664 | int *tag) | 2675 | int *tag, int unaligned) |
2665 | { | 2676 | { |
2677 | struct semaphore *sem = unaligned ? &dd->port->cmd_slot_unal : | ||
2678 | &dd->port->cmd_slot; | ||
2679 | |||
2666 | /* | 2680 | /* |
2667 | * It is possible that, even with this semaphore, a thread | 2681 | * It is possible that, even with this semaphore, a thread |
2668 | * may think that no command slots are available. Therefore, we | 2682 | * may think that no command slots are available. Therefore, we |
2669 | * need to make an attempt to get_slot(). | 2683 | * need to make an attempt to get_slot(). |
2670 | */ | 2684 | */ |
2671 | down(&dd->port->cmd_slot); | 2685 | down(sem); |
2672 | *tag = get_slot(dd->port); | 2686 | *tag = get_slot(dd->port); |
2673 | 2687 | ||
2674 | if (unlikely(test_bit(MTIP_DDF_REMOVE_PENDING_BIT, &dd->dd_flag))) { | 2688 | if (unlikely(test_bit(MTIP_DDF_REMOVE_PENDING_BIT, &dd->dd_flag))) { |
2675 | up(&dd->port->cmd_slot); | 2689 | up(sem); |
2676 | return NULL; | 2690 | return NULL; |
2677 | } | 2691 | } |
2678 | if (unlikely(*tag < 0)) { | 2692 | if (unlikely(*tag < 0)) { |
2679 | up(&dd->port->cmd_slot); | 2693 | up(sem); |
2680 | return NULL; | 2694 | return NULL; |
2681 | } | 2695 | } |
2682 | 2696 | ||
@@ -2909,6 +2923,11 @@ static inline void hba_setup(struct driver_data *dd) | |||
2909 | dd->mmio + HOST_HSORG); | 2923 | dd->mmio + HOST_HSORG); |
2910 | } | 2924 | } |
2911 | 2925 | ||
2926 | static int mtip_device_unaligned_constrained(struct driver_data *dd) | ||
2927 | { | ||
2928 | return (dd->pdev->device == P420M_DEVICE_ID ? 1 : 0); | ||
2929 | } | ||
2930 | |||
2912 | /* | 2931 | /* |
2913 | * Detect the details of the product, and store anything needed | 2932 | * Detect the details of the product, and store anything needed |
2914 | * into the driver data structure. This includes product type and | 2933 | * into the driver data structure. This includes product type and |
@@ -3131,8 +3150,15 @@ static int mtip_hw_init(struct driver_data *dd) | |||
3131 | for (i = 0; i < MTIP_MAX_SLOT_GROUPS; i++) | 3150 | for (i = 0; i < MTIP_MAX_SLOT_GROUPS; i++) |
3132 | dd->work[i].port = dd->port; | 3151 | dd->work[i].port = dd->port; |
3133 | 3152 | ||
3153 | /* Enable unaligned IO constraints for some devices */ | ||
3154 | if (mtip_device_unaligned_constrained(dd)) | ||
3155 | dd->unal_qdepth = MTIP_MAX_UNALIGNED_SLOTS; | ||
3156 | else | ||
3157 | dd->unal_qdepth = 0; | ||
3158 | |||
3134 | /* Counting semaphore to track command slot usage */ | 3159 | /* Counting semaphore to track command slot usage */ |
3135 | sema_init(&dd->port->cmd_slot, num_command_slots - 1); | 3160 | sema_init(&dd->port->cmd_slot, num_command_slots - 1 - dd->unal_qdepth); |
3161 | sema_init(&dd->port->cmd_slot_unal, dd->unal_qdepth); | ||
3136 | 3162 | ||
3137 | /* Spinlock to prevent concurrent issue */ | 3163 | /* Spinlock to prevent concurrent issue */ |
3138 | for (i = 0; i < MTIP_MAX_SLOT_GROUPS; i++) | 3164 | for (i = 0; i < MTIP_MAX_SLOT_GROUPS; i++) |
@@ -3735,7 +3761,7 @@ static void mtip_make_request(struct request_queue *queue, struct bio *bio) | |||
3735 | struct scatterlist *sg; | 3761 | struct scatterlist *sg; |
3736 | struct bio_vec *bvec; | 3762 | struct bio_vec *bvec; |
3737 | int nents = 0; | 3763 | int nents = 0; |
3738 | int tag = 0; | 3764 | int tag = 0, unaligned = 0; |
3739 | 3765 | ||
3740 | if (unlikely(dd->dd_flag & MTIP_DDF_STOP_IO)) { | 3766 | if (unlikely(dd->dd_flag & MTIP_DDF_STOP_IO)) { |
3741 | if (unlikely(test_bit(MTIP_DDF_REMOVE_PENDING_BIT, | 3767 | if (unlikely(test_bit(MTIP_DDF_REMOVE_PENDING_BIT, |
@@ -3771,7 +3797,15 @@ static void mtip_make_request(struct request_queue *queue, struct bio *bio) | |||
3771 | return; | 3797 | return; |
3772 | } | 3798 | } |
3773 | 3799 | ||
3774 | sg = mtip_hw_get_scatterlist(dd, &tag); | 3800 | if (bio_data_dir(bio) == WRITE && bio_sectors(bio) <= 64 && |
3801 | dd->unal_qdepth) { | ||
3802 | if (bio->bi_sector % 8 != 0) /* Unaligned on 4k boundaries */ | ||
3803 | unaligned = 1; | ||
3804 | else if (bio_sectors(bio) % 8 != 0) /* Aligned but not 4k/8k */ | ||
3805 | unaligned = 1; | ||
3806 | } | ||
3807 | |||
3808 | sg = mtip_hw_get_scatterlist(dd, &tag, unaligned); | ||
3775 | if (likely(sg != NULL)) { | 3809 | if (likely(sg != NULL)) { |
3776 | blk_queue_bounce(queue, &bio); | 3810 | blk_queue_bounce(queue, &bio); |
3777 | 3811 | ||
@@ -3779,7 +3813,7 @@ static void mtip_make_request(struct request_queue *queue, struct bio *bio) | |||
3779 | dev_warn(&dd->pdev->dev, | 3813 | dev_warn(&dd->pdev->dev, |
3780 | "Maximum number of SGL entries exceeded\n"); | 3814 | "Maximum number of SGL entries exceeded\n"); |
3781 | bio_io_error(bio); | 3815 | bio_io_error(bio); |
3782 | mtip_hw_release_scatterlist(dd, tag); | 3816 | mtip_hw_release_scatterlist(dd, tag, unaligned); |
3783 | return; | 3817 | return; |
3784 | } | 3818 | } |
3785 | 3819 | ||
@@ -3799,7 +3833,8 @@ static void mtip_make_request(struct request_queue *queue, struct bio *bio) | |||
3799 | tag, | 3833 | tag, |
3800 | bio_endio, | 3834 | bio_endio, |
3801 | bio, | 3835 | bio, |
3802 | bio_data_dir(bio)); | 3836 | bio_data_dir(bio), |
3837 | unaligned); | ||
3803 | } else | 3838 | } else |
3804 | bio_io_error(bio); | 3839 | bio_io_error(bio); |
3805 | } | 3840 | } |