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 | |
| 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>
| -rw-r--r-- | drivers/block/mtip32xx/mtip32xx.c | 59 | ||||
| -rw-r--r-- | drivers/block/mtip32xx/mtip32xx.h | 11 |
2 files changed, 58 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 | } |
diff --git a/drivers/block/mtip32xx/mtip32xx.h b/drivers/block/mtip32xx/mtip32xx.h index 3bffff5f670c..579fb84bdd95 100644 --- a/drivers/block/mtip32xx/mtip32xx.h +++ b/drivers/block/mtip32xx/mtip32xx.h | |||
| @@ -52,6 +52,9 @@ | |||
| 52 | #define MTIP_FTL_REBUILD_MAGIC 0xED51 | 52 | #define MTIP_FTL_REBUILD_MAGIC 0xED51 |
| 53 | #define MTIP_FTL_REBUILD_TIMEOUT_MS 2400000 | 53 | #define MTIP_FTL_REBUILD_TIMEOUT_MS 2400000 |
| 54 | 54 | ||
| 55 | /* unaligned IO handling */ | ||
| 56 | #define MTIP_MAX_UNALIGNED_SLOTS 8 | ||
| 57 | |||
| 55 | /* Macro to extract the tag bit number from a tag value. */ | 58 | /* Macro to extract the tag bit number from a tag value. */ |
| 56 | #define MTIP_TAG_BIT(tag) (tag & 0x1F) | 59 | #define MTIP_TAG_BIT(tag) (tag & 0x1F) |
| 57 | 60 | ||
| @@ -333,6 +336,8 @@ struct mtip_cmd { | |||
| 333 | 336 | ||
| 334 | int scatter_ents; /* Number of scatter list entries used */ | 337 | int scatter_ents; /* Number of scatter list entries used */ |
| 335 | 338 | ||
| 339 | int unaligned; /* command is unaligned on 4k boundary */ | ||
| 340 | |||
| 336 | struct scatterlist sg[MTIP_MAX_SG]; /* Scatter list entries */ | 341 | struct scatterlist sg[MTIP_MAX_SG]; /* Scatter list entries */ |
| 337 | 342 | ||
| 338 | int retries; /* The number of retries left for this command. */ | 343 | int retries; /* The number of retries left for this command. */ |
| @@ -452,6 +457,10 @@ struct mtip_port { | |||
| 452 | * command slots available. | 457 | * command slots available. |
| 453 | */ | 458 | */ |
| 454 | struct semaphore cmd_slot; | 459 | struct semaphore cmd_slot; |
| 460 | |||
| 461 | /* Semaphore to control queue depth of unaligned IOs */ | ||
| 462 | struct semaphore cmd_slot_unal; | ||
| 463 | |||
| 455 | /* Spinlock for working around command-issue bug. */ | 464 | /* Spinlock for working around command-issue bug. */ |
| 456 | spinlock_t cmd_issue_lock[MTIP_MAX_SLOT_GROUPS]; | 465 | spinlock_t cmd_issue_lock[MTIP_MAX_SLOT_GROUPS]; |
| 457 | }; | 466 | }; |
| @@ -501,6 +510,8 @@ struct driver_data { | |||
| 501 | atomic_t irq_workers_active; | 510 | atomic_t irq_workers_active; |
| 502 | 511 | ||
| 503 | int isr_binding; | 512 | int isr_binding; |
| 513 | |||
| 514 | int unal_qdepth; /* qdepth of unaligned IO queue */ | ||
| 504 | }; | 515 | }; |
| 505 | 516 | ||
| 506 | #endif | 517 | #endif |
