aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/block/mtip32xx
diff options
context:
space:
mode:
authorSam Bradshaw <sbradshaw@micron.com>2014-03-13 17:33:30 -0400
committerJens Axboe <axboe@fb.com>2014-03-13 17:59:09 -0400
commit5eb9291c36c7d71d7c6c832d5a4f551eb8ac015d (patch)
tree4916b96db3ecccf343edc4bb9f181b5ffc89ba00 /drivers/block/mtip32xx
parent368c89d7ac70f937c93cd6f3b65bcfdfb3ba794f (diff)
mtip32xx: mtip_async_complete() bug fixes
This patch fixes 2 issues in the fast completion path: 1) Possible double completions / double dma_unmap_sg() calls due to lack of atomicity in the check and subsequent dereference of the upper layer callback function. Fixed with cmpxchg before unmap and callback. 2) Regression in unaligned IO constraining workaround for p420m devices. Fixed by checking if IO is unaligned and using proper semaphore if so. Signed-off-by: Sam Bradshaw <sbradshaw@micron.com> Cc: stable@kernel.org Signed-off-by: Jens Axboe <axboe@fb.com>
Diffstat (limited to 'drivers/block/mtip32xx')
-rw-r--r--drivers/block/mtip32xx/mtip32xx.c87
-rw-r--r--drivers/block/mtip32xx/mtip32xx.h2
2 files changed, 50 insertions, 39 deletions
diff --git a/drivers/block/mtip32xx/mtip32xx.c b/drivers/block/mtip32xx/mtip32xx.c
index b2012b76a0b6..624e9d9c139f 100644
--- a/drivers/block/mtip32xx/mtip32xx.c
+++ b/drivers/block/mtip32xx/mtip32xx.c
@@ -252,38 +252,45 @@ static void mtip_async_complete(struct mtip_port *port,
252 void *data, 252 void *data,
253 int status) 253 int status)
254{ 254{
255 struct mtip_cmd *command; 255 struct mtip_cmd *cmd;
256 struct driver_data *dd = data; 256 struct driver_data *dd = data;
257 int cb_status = status ? -EIO : 0; 257 int unaligned, cb_status = status ? -EIO : 0;
258 void (*func)(void *, int);
258 259
259 if (unlikely(!dd) || unlikely(!port)) 260 if (unlikely(!dd) || unlikely(!port))
260 return; 261 return;
261 262
262 command = &port->commands[tag]; 263 cmd = &port->commands[tag];
263 264
264 if (unlikely(status == PORT_IRQ_TF_ERR)) { 265 if (unlikely(status == PORT_IRQ_TF_ERR)) {
265 dev_warn(&port->dd->pdev->dev, 266 dev_warn(&port->dd->pdev->dev,
266 "Command tag %d failed due to TFE\n", tag); 267 "Command tag %d failed due to TFE\n", tag);
267 } 268 }
268 269
269 /* Unmap the DMA scatter list entries */ 270 /* Clear the active flag */
270 dma_unmap_sg(&dd->pdev->dev, 271 atomic_set(&port->commands[tag].active, 0);
271 command->sg,
272 command->scatter_ents,
273 command->direction);
274 272
275 /* Upper layer callback */ 273 /* Upper layer callback */
276 if (likely(command->async_callback)) 274 func = cmd->async_callback;
277 command->async_callback(command->async_data, cb_status); 275 if (likely(func && cmpxchg(&cmd->async_callback, func, 0) == func)) {
278 276
279 command->async_callback = NULL; 277 /* Unmap the DMA scatter list entries */
280 command->comp_func = NULL; 278 dma_unmap_sg(&dd->pdev->dev,
279 cmd->sg,
280 cmd->scatter_ents,
281 cmd->direction);
281 282
282 /* Clear the allocated and active bits for the command */ 283 func(cmd->async_data, cb_status);
283 atomic_set(&port->commands[tag].active, 0); 284 unaligned = cmd->unaligned;
284 release_slot(port, tag);
285 285
286 up(&port->cmd_slot); 286 /* Clear the allocated bit for the command */
287 release_slot(port, tag);
288
289 if (unlikely(unaligned))
290 up(&port->cmd_slot_unal);
291 else
292 up(&port->cmd_slot);
293 }
287} 294}
288 295
289/* 296/*
@@ -660,11 +667,12 @@ static void mtip_timeout_function(unsigned long int data)
660{ 667{
661 struct mtip_port *port = (struct mtip_port *) data; 668 struct mtip_port *port = (struct mtip_port *) data;
662 struct host_to_dev_fis *fis; 669 struct host_to_dev_fis *fis;
663 struct mtip_cmd *command; 670 struct mtip_cmd *cmd;
664 int tag, cmdto_cnt = 0; 671 int unaligned, tag, cmdto_cnt = 0;
665 unsigned int bit, group; 672 unsigned int bit, group;
666 unsigned int num_command_slots; 673 unsigned int num_command_slots;
667 unsigned long to, tagaccum[SLOTBITS_IN_LONGS]; 674 unsigned long to, tagaccum[SLOTBITS_IN_LONGS];
675 void (*func)(void *, int);
668 676
669 if (unlikely(!port)) 677 if (unlikely(!port))
670 return; 678 return;
@@ -694,8 +702,8 @@ static void mtip_timeout_function(unsigned long int data)
694 group = tag >> 5; 702 group = tag >> 5;
695 bit = tag & 0x1F; 703 bit = tag & 0x1F;
696 704
697 command = &port->commands[tag]; 705 cmd = &port->commands[tag];
698 fis = (struct host_to_dev_fis *) command->command; 706 fis = (struct host_to_dev_fis *) cmd->command;
699 707
700 set_bit(tag, tagaccum); 708 set_bit(tag, tagaccum);
701 cmdto_cnt++; 709 cmdto_cnt++;
@@ -709,27 +717,30 @@ static void mtip_timeout_function(unsigned long int data)
709 */ 717 */
710 writel(1 << bit, port->completed[group]); 718 writel(1 << bit, port->completed[group]);
711 719
712 /* Unmap the DMA scatter list entries */ 720 /* Clear the active flag for the command */
713 dma_unmap_sg(&port->dd->pdev->dev, 721 atomic_set(&port->commands[tag].active, 0);
714 command->sg,
715 command->scatter_ents,
716 command->direction);
717 722
718 /* Call the async completion callback. */ 723 func = cmd->async_callback;
719 if (likely(command->async_callback)) 724 if (func &&
720 command->async_callback(command->async_data, 725 cmpxchg(&cmd->async_callback, func, 0) == func) {
721 -EIO);
722 command->async_callback = NULL;
723 command->comp_func = NULL;
724 726
725 /* 727 /* Unmap the DMA scatter list entries */
726 * Clear the allocated bit and active tag for the 728 dma_unmap_sg(&port->dd->pdev->dev,
727 * command. 729 cmd->sg,
728 */ 730 cmd->scatter_ents,
729 atomic_set(&port->commands[tag].active, 0); 731 cmd->direction);
730 release_slot(port, tag);
731 732
732 up(&port->cmd_slot); 733 func(cmd->async_data, -EIO);
734 unaligned = cmd->unaligned;
735
736 /* Clear the allocated bit for the command. */
737 release_slot(port, tag);
738
739 if (unaligned)
740 up(&port->cmd_slot_unal);
741 else
742 up(&port->cmd_slot);
743 }
733 } 744 }
734 } 745 }
735 746
diff --git a/drivers/block/mtip32xx/mtip32xx.h b/drivers/block/mtip32xx/mtip32xx.h
index b52e9a6d6aad..db5925840f67 100644
--- a/drivers/block/mtip32xx/mtip32xx.h
+++ b/drivers/block/mtip32xx/mtip32xx.h
@@ -92,7 +92,7 @@
92 92
93/* Driver name and version strings */ 93/* Driver name and version strings */
94#define MTIP_DRV_NAME "mtip32xx" 94#define MTIP_DRV_NAME "mtip32xx"
95#define MTIP_DRV_VERSION "1.3.0" 95#define MTIP_DRV_VERSION "1.3.1"
96 96
97/* Maximum number of minor device numbers per device. */ 97/* Maximum number of minor device numbers per device. */
98#define MTIP_MAX_MINORS 16 98#define MTIP_MAX_MINORS 16