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>
This commit is contained in:
Asai Thambi S P 2013-04-29 21:19:49 +02:00 committed by Jens Axboe
parent 68466cbf92
commit 2077d94726
2 changed files with 58 additions and 12 deletions

View file

@ -712,7 +712,10 @@ static void mtip_async_complete(struct mtip_port *port,
atomic_set(&port->commands[tag].active, 0); atomic_set(&port->commands[tag].active, 0);
release_slot(port, tag); release_slot(port, tag);
up(&port->cmd_slot); if (unlikely(command->unaligned))
up(&port->cmd_slot_unal);
else
up(&port->cmd_slot);
} }
/* /*
@ -2557,7 +2560,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, static void mtip_hw_submit_io(struct driver_data *dd, sector_t sector,
int nsect, int nents, int tag, void *callback, 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 host_to_dev_fis *fis;
struct mtip_port *port = dd->port; struct mtip_port *port = dd->port;
@ -2570,6 +2573,7 @@ static void mtip_hw_submit_io(struct driver_data *dd, sector_t sector,
command->scatter_ents = nents; command->scatter_ents = nents;
command->unaligned = unaligned;
/* /*
* The number of retries for this command before it is * The number of retries for this command before it is
* reported as a failure to the upper layers. * 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,
fis->res3 = 0; fis->res3 = 0;
fill_command_sg(dd, command, nents); fill_command_sg(dd, command, nents);
if (unaligned)
fis->device |= 1 << 7;
/* Populate the command header */ /* Populate the command header */
command->command_header->opts = command->command_header->opts =
__force_bit2int cpu_to_le32( __force_bit2int cpu_to_le32(
@ -2644,9 +2651,13 @@ static void mtip_hw_submit_io(struct driver_data *dd, sector_t sector,
* return value * return value
* None * 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); release_slot(dd->port, tag);
up(sem);
} }
/* /*
@ -2661,22 +2672,25 @@ static void mtip_hw_release_scatterlist(struct driver_data *dd, int tag)
* or NULL if no command slots are available. * or NULL if no command slots are available.
*/ */
static struct scatterlist *mtip_hw_get_scatterlist(struct driver_data *dd, 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 * It is possible that, even with this semaphore, a thread
* may think that no command slots are available. Therefore, we * may think that no command slots are available. Therefore, we
* need to make an attempt to get_slot(). * need to make an attempt to get_slot().
*/ */
down(&dd->port->cmd_slot); down(sem);
*tag = get_slot(dd->port); *tag = get_slot(dd->port);
if (unlikely(test_bit(MTIP_DDF_REMOVE_PENDING_BIT, &dd->dd_flag))) { if (unlikely(test_bit(MTIP_DDF_REMOVE_PENDING_BIT, &dd->dd_flag))) {
up(&dd->port->cmd_slot); up(sem);
return NULL; return NULL;
} }
if (unlikely(*tag < 0)) { if (unlikely(*tag < 0)) {
up(&dd->port->cmd_slot); up(sem);
return NULL; return NULL;
} }
@ -2909,6 +2923,11 @@ static inline void hba_setup(struct driver_data *dd)
dd->mmio + HOST_HSORG); 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 * Detect the details of the product, and store anything needed
* into the driver data structure. This includes product type and * into the driver data structure. This includes product type and
@ -3131,8 +3150,15 @@ static int mtip_hw_init(struct driver_data *dd)
for (i = 0; i < MTIP_MAX_SLOT_GROUPS; i++) for (i = 0; i < MTIP_MAX_SLOT_GROUPS; i++)
dd->work[i].port = dd->port; 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 */ /* 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 */ /* Spinlock to prevent concurrent issue */
for (i = 0; i < MTIP_MAX_SLOT_GROUPS; i++) 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)
struct scatterlist *sg; struct scatterlist *sg;
struct bio_vec *bvec; struct bio_vec *bvec;
int nents = 0; int nents = 0;
int tag = 0; int tag = 0, unaligned = 0;
if (unlikely(dd->dd_flag & MTIP_DDF_STOP_IO)) { if (unlikely(dd->dd_flag & MTIP_DDF_STOP_IO)) {
if (unlikely(test_bit(MTIP_DDF_REMOVE_PENDING_BIT, 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)
return; 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)) { if (likely(sg != NULL)) {
blk_queue_bounce(queue, &bio); blk_queue_bounce(queue, &bio);
@ -3779,7 +3813,7 @@ static void mtip_make_request(struct request_queue *queue, struct bio *bio)
dev_warn(&dd->pdev->dev, dev_warn(&dd->pdev->dev,
"Maximum number of SGL entries exceeded\n"); "Maximum number of SGL entries exceeded\n");
bio_io_error(bio); bio_io_error(bio);
mtip_hw_release_scatterlist(dd, tag); mtip_hw_release_scatterlist(dd, tag, unaligned);
return; return;
} }
@ -3799,7 +3833,8 @@ static void mtip_make_request(struct request_queue *queue, struct bio *bio)
tag, tag,
bio_endio, bio_endio,
bio, bio,
bio_data_dir(bio)); bio_data_dir(bio),
unaligned);
} else } else
bio_io_error(bio); bio_io_error(bio);
} }

View file

@ -52,6 +52,9 @@
#define MTIP_FTL_REBUILD_MAGIC 0xED51 #define MTIP_FTL_REBUILD_MAGIC 0xED51
#define MTIP_FTL_REBUILD_TIMEOUT_MS 2400000 #define MTIP_FTL_REBUILD_TIMEOUT_MS 2400000
/* unaligned IO handling */
#define MTIP_MAX_UNALIGNED_SLOTS 8
/* Macro to extract the tag bit number from a tag value. */ /* Macro to extract the tag bit number from a tag value. */
#define MTIP_TAG_BIT(tag) (tag & 0x1F) #define MTIP_TAG_BIT(tag) (tag & 0x1F)
@ -333,6 +336,8 @@ struct mtip_cmd {
int scatter_ents; /* Number of scatter list entries used */ int scatter_ents; /* Number of scatter list entries used */
int unaligned; /* command is unaligned on 4k boundary */
struct scatterlist sg[MTIP_MAX_SG]; /* Scatter list entries */ struct scatterlist sg[MTIP_MAX_SG]; /* Scatter list entries */
int retries; /* The number of retries left for this command. */ int retries; /* The number of retries left for this command. */
@ -452,6 +457,10 @@ struct mtip_port {
* command slots available. * command slots available.
*/ */
struct semaphore cmd_slot; struct semaphore cmd_slot;
/* Semaphore to control queue depth of unaligned IOs */
struct semaphore cmd_slot_unal;
/* Spinlock for working around command-issue bug. */ /* Spinlock for working around command-issue bug. */
spinlock_t cmd_issue_lock[MTIP_MAX_SLOT_GROUPS]; spinlock_t cmd_issue_lock[MTIP_MAX_SLOT_GROUPS];
}; };
@ -501,6 +510,8 @@ struct driver_data {
atomic_t irq_workers_active; atomic_t irq_workers_active;
int isr_binding; int isr_binding;
int unal_qdepth; /* qdepth of unaligned IO queue */
}; };
#endif #endif