aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/mvsas
diff options
context:
space:
mode:
authorXiangliang Yu <yuxiangl@marvell.com>2011-04-26 09:36:51 -0400
committerJames Bottomley <James.Bottomley@suse.de>2011-05-01 13:08:03 -0400
commit0b15fb1fdfd403726542cb6111bc916b7a9f7fad (patch)
tree3f3d2d7516aad34f7ce68cbb317781e7aa7fd41a /drivers/scsi/mvsas
parent8214028344b4a38aabf73d95347e1e35538c75f6 (diff)
[SCSI] mvsas: add support for Task collector mode and fixed relative bugs
1. Add support for Task collector mode. 2. Fixed relative collector mode bug: - I/O failed when disks is on two ports - system hang when hotplug disk - system hang when unplug disk during run IO 3. Unlock ap->lock within .lldd_execute_task for direct mode to improve performance Signed-off-by: Xiangliang Yu <yuxiangl@marvell.com> Signed-off-by: James Bottomley <James.Bottomley@suse.de>
Diffstat (limited to 'drivers/scsi/mvsas')
-rw-r--r--drivers/scsi/mvsas/Kconfig1
-rw-r--r--drivers/scsi/mvsas/Makefile1
-rw-r--r--drivers/scsi/mvsas/mv_64xx.c1
-rw-r--r--drivers/scsi/mvsas/mv_64xx.h1
-rw-r--r--drivers/scsi/mvsas/mv_94xx.c1
-rw-r--r--drivers/scsi/mvsas/mv_94xx.h1
-rw-r--r--drivers/scsi/mvsas/mv_chips.h1
-rw-r--r--drivers/scsi/mvsas/mv_defs.h1
-rw-r--r--drivers/scsi/mvsas/mv_init.c47
-rw-r--r--drivers/scsi/mvsas/mv_sas.c383
-rw-r--r--drivers/scsi/mvsas/mv_sas.h8
11 files changed, 294 insertions, 152 deletions
diff --git a/drivers/scsi/mvsas/Kconfig b/drivers/scsi/mvsas/Kconfig
index 6de7af27e507..c82b012aba37 100644
--- a/drivers/scsi/mvsas/Kconfig
+++ b/drivers/scsi/mvsas/Kconfig
@@ -3,6 +3,7 @@
3# 3#
4# Copyright 2007 Red Hat, Inc. 4# Copyright 2007 Red Hat, Inc.
5# Copyright 2008 Marvell. <kewei@marvell.com> 5# Copyright 2008 Marvell. <kewei@marvell.com>
6# Copyright 2009-20011 Marvell. <yuxiangl@marvell.com>
6# 7#
7# This file is licensed under GPLv2. 8# This file is licensed under GPLv2.
8# 9#
diff --git a/drivers/scsi/mvsas/Makefile b/drivers/scsi/mvsas/Makefile
index ffbf759e46f1..87b231a5bd5e 100644
--- a/drivers/scsi/mvsas/Makefile
+++ b/drivers/scsi/mvsas/Makefile
@@ -3,6 +3,7 @@
3# 3#
4# Copyright 2007 Red Hat, Inc. 4# Copyright 2007 Red Hat, Inc.
5# Copyright 2008 Marvell. <kewei@marvell.com> 5# Copyright 2008 Marvell. <kewei@marvell.com>
6# Copyright 2009-2011 Marvell. <yuxiangl@marvell.com>
6# 7#
7# This file is licensed under GPLv2. 8# This file is licensed under GPLv2.
8# 9#
diff --git a/drivers/scsi/mvsas/mv_64xx.c b/drivers/scsi/mvsas/mv_64xx.c
index afc7f6f3a13e..13c960481391 100644
--- a/drivers/scsi/mvsas/mv_64xx.c
+++ b/drivers/scsi/mvsas/mv_64xx.c
@@ -3,6 +3,7 @@
3 * 3 *
4 * Copyright 2007 Red Hat, Inc. 4 * Copyright 2007 Red Hat, Inc.
5 * Copyright 2008 Marvell. <kewei@marvell.com> 5 * Copyright 2008 Marvell. <kewei@marvell.com>
6 * Copyright 2009-2011 Marvell. <yuxiangl@marvell.com>
6 * 7 *
7 * This file is licensed under GPLv2. 8 * This file is licensed under GPLv2.
8 * 9 *
diff --git a/drivers/scsi/mvsas/mv_64xx.h b/drivers/scsi/mvsas/mv_64xx.h
index 42e947d9795e..545889bd9753 100644
--- a/drivers/scsi/mvsas/mv_64xx.h
+++ b/drivers/scsi/mvsas/mv_64xx.h
@@ -3,6 +3,7 @@
3 * 3 *
4 * Copyright 2007 Red Hat, Inc. 4 * Copyright 2007 Red Hat, Inc.
5 * Copyright 2008 Marvell. <kewei@marvell.com> 5 * Copyright 2008 Marvell. <kewei@marvell.com>
6 * Copyright 2009-2011 Marvell. <yuxiangl@marvell.com>
6 * 7 *
7 * This file is licensed under GPLv2. 8 * This file is licensed under GPLv2.
8 * 9 *
diff --git a/drivers/scsi/mvsas/mv_94xx.c b/drivers/scsi/mvsas/mv_94xx.c
index eed4c5c72013..78162c3c36e6 100644
--- a/drivers/scsi/mvsas/mv_94xx.c
+++ b/drivers/scsi/mvsas/mv_94xx.c
@@ -3,6 +3,7 @@
3 * 3 *
4 * Copyright 2007 Red Hat, Inc. 4 * Copyright 2007 Red Hat, Inc.
5 * Copyright 2008 Marvell. <kewei@marvell.com> 5 * Copyright 2008 Marvell. <kewei@marvell.com>
6 * Copyright 2009-2011 Marvell. <yuxiangl@marvell.com>
6 * 7 *
7 * This file is licensed under GPLv2. 8 * This file is licensed under GPLv2.
8 * 9 *
diff --git a/drivers/scsi/mvsas/mv_94xx.h b/drivers/scsi/mvsas/mv_94xx.h
index 23ed9b164669..8835befe2c0e 100644
--- a/drivers/scsi/mvsas/mv_94xx.h
+++ b/drivers/scsi/mvsas/mv_94xx.h
@@ -3,6 +3,7 @@
3 * 3 *
4 * Copyright 2007 Red Hat, Inc. 4 * Copyright 2007 Red Hat, Inc.
5 * Copyright 2008 Marvell. <kewei@marvell.com> 5 * Copyright 2008 Marvell. <kewei@marvell.com>
6 * Copyright 2009-2011 Marvell. <yuxiangl@marvell.com>
6 * 7 *
7 * This file is licensed under GPLv2. 8 * This file is licensed under GPLv2.
8 * 9 *
diff --git a/drivers/scsi/mvsas/mv_chips.h b/drivers/scsi/mvsas/mv_chips.h
index a67e1c4172f9..1753a6fc42d0 100644
--- a/drivers/scsi/mvsas/mv_chips.h
+++ b/drivers/scsi/mvsas/mv_chips.h
@@ -3,6 +3,7 @@
3 * 3 *
4 * Copyright 2007 Red Hat, Inc. 4 * Copyright 2007 Red Hat, Inc.
5 * Copyright 2008 Marvell. <kewei@marvell.com> 5 * Copyright 2008 Marvell. <kewei@marvell.com>
6 * Copyright 2009-2011 Marvell. <yuxiangl@marvell.com>
6 * 7 *
7 * This file is licensed under GPLv2. 8 * This file is licensed under GPLv2.
8 * 9 *
diff --git a/drivers/scsi/mvsas/mv_defs.h b/drivers/scsi/mvsas/mv_defs.h
index 880613fce1dd..bc00c940743c 100644
--- a/drivers/scsi/mvsas/mv_defs.h
+++ b/drivers/scsi/mvsas/mv_defs.h
@@ -3,6 +3,7 @@
3 * 3 *
4 * Copyright 2007 Red Hat, Inc. 4 * Copyright 2007 Red Hat, Inc.
5 * Copyright 2008 Marvell. <kewei@marvell.com> 5 * Copyright 2008 Marvell. <kewei@marvell.com>
6 * Copyright 2009-2011 Marvell. <yuxiangl@marvell.com>
6 * 7 *
7 * This file is licensed under GPLv2. 8 * This file is licensed under GPLv2.
8 * 9 *
diff --git a/drivers/scsi/mvsas/mv_init.c b/drivers/scsi/mvsas/mv_init.c
index 0123c6b6db96..90b636611cde 100644
--- a/drivers/scsi/mvsas/mv_init.c
+++ b/drivers/scsi/mvsas/mv_init.c
@@ -3,6 +3,7 @@
3 * 3 *
4 * Copyright 2007 Red Hat, Inc. 4 * Copyright 2007 Red Hat, Inc.
5 * Copyright 2008 Marvell. <kewei@marvell.com> 5 * Copyright 2008 Marvell. <kewei@marvell.com>
6 * Copyright 2009-2011 Marvell. <yuxiangl@marvell.com>
6 * 7 *
7 * This file is licensed under GPLv2. 8 * This file is licensed under GPLv2.
8 * 9 *
@@ -25,7 +26,16 @@
25 26
26#include "mv_sas.h" 27#include "mv_sas.h"
27 28
29static int lldd_max_execute_num = 1;
30module_param_named(collector, lldd_max_execute_num, int, S_IRUGO);
31MODULE_PARM_DESC(collector, "\n"
32 "\tIf greater than one, tells the SAS Layer to run in Task Collector\n"
33 "\tMode. If 1 or 0, tells the SAS Layer to run in Direct Mode.\n"
34 "\tThe mvsas SAS LLDD supports both modes.\n"
35 "\tDefault: 1 (Direct Mode).\n");
36
28static struct scsi_transport_template *mvs_stt; 37static struct scsi_transport_template *mvs_stt;
38struct kmem_cache *mvs_task_list_cache;
29static const struct mvs_chip_info mvs_chips[] = { 39static const struct mvs_chip_info mvs_chips[] = {
30 [chip_6320] = { 1, 2, 0x400, 17, 16, 9, &mvs_64xx_dispatch, }, 40 [chip_6320] = { 1, 2, 0x400, 17, 16, 9, &mvs_64xx_dispatch, },
31 [chip_6440] = { 1, 4, 0x400, 17, 16, 9, &mvs_64xx_dispatch, }, 41 [chip_6440] = { 1, 4, 0x400, 17, 16, 9, &mvs_64xx_dispatch, },
@@ -109,7 +119,6 @@ static void __devinit mvs_phy_init(struct mvs_info *mvi, int phy_id)
109 119
110static void mvs_free(struct mvs_info *mvi) 120static void mvs_free(struct mvs_info *mvi)
111{ 121{
112 int i;
113 struct mvs_wq *mwq; 122 struct mvs_wq *mwq;
114 int slot_nr; 123 int slot_nr;
115 124
@@ -121,12 +130,8 @@ static void mvs_free(struct mvs_info *mvi)
121 else 130 else
122 slot_nr = MVS_SLOTS; 131 slot_nr = MVS_SLOTS;
123 132
124 for (i = 0; i < mvi->tags_num; i++) { 133 if (mvi->dma_pool)
125 struct mvs_slot_info *slot = &mvi->slot_info[i]; 134 pci_pool_destroy(mvi->dma_pool);
126 if (slot->buf)
127 dma_free_coherent(mvi->dev, MVS_SLOT_BUF_SZ,
128 slot->buf, slot->buf_dma);
129 }
130 135
131 if (mvi->tx) 136 if (mvi->tx)
132 dma_free_coherent(mvi->dev, 137 dma_free_coherent(mvi->dev,
@@ -215,6 +220,7 @@ static irqreturn_t mvs_interrupt(int irq, void *opaque)
215static int __devinit mvs_alloc(struct mvs_info *mvi, struct Scsi_Host *shost) 220static int __devinit mvs_alloc(struct mvs_info *mvi, struct Scsi_Host *shost)
216{ 221{
217 int i = 0, slot_nr; 222 int i = 0, slot_nr;
223 char pool_name[32];
218 224
219 if (mvi->flags & MVF_FLAG_SOC) 225 if (mvi->flags & MVF_FLAG_SOC)
220 slot_nr = MVS_SOC_SLOTS; 226 slot_nr = MVS_SOC_SLOTS;
@@ -274,18 +280,14 @@ static int __devinit mvs_alloc(struct mvs_info *mvi, struct Scsi_Host *shost)
274 if (!mvi->bulk_buffer) 280 if (!mvi->bulk_buffer)
275 goto err_out; 281 goto err_out;
276#endif 282#endif
277 for (i = 0; i < slot_nr; i++) { 283 sprintf(pool_name, "%s%d", "mvs_dma_pool", mvi->id);
278 struct mvs_slot_info *slot = &mvi->slot_info[i]; 284 mvi->dma_pool = pci_pool_create(pool_name, mvi->pdev, MVS_SLOT_BUF_SZ, 16, 0);
279 285 if (!mvi->dma_pool) {
280 slot->buf = dma_alloc_coherent(mvi->dev, MVS_SLOT_BUF_SZ, 286 printk(KERN_DEBUG "failed to create dma pool %s.\n", pool_name);
281 &slot->buf_dma, GFP_KERNEL);
282 if (!slot->buf) {
283 printk(KERN_DEBUG"failed to allocate slot->buf.\n");
284 goto err_out; 287 goto err_out;
285 }
286 memset(slot->buf, 0, MVS_SLOT_BUF_SZ);
287 ++mvi->tags_num;
288 } 288 }
289 mvi->tags_num = slot_nr;
290
289 /* Initialize tags */ 291 /* Initialize tags */
290 mvs_tag_init(mvi); 292 mvs_tag_init(mvi);
291 return 0; 293 return 0;
@@ -486,7 +488,7 @@ static void __devinit mvs_post_sas_ha_init(struct Scsi_Host *shost,
486 488
487 sha->num_phys = nr_core * chip_info->n_phy; 489 sha->num_phys = nr_core * chip_info->n_phy;
488 490
489 sha->lldd_max_execute_num = 1; 491 sha->lldd_max_execute_num = lldd_max_execute_num;
490 492
491 if (mvi->flags & MVF_FLAG_SOC) 493 if (mvi->flags & MVF_FLAG_SOC)
492 can_queue = MVS_SOC_CAN_QUEUE; 494 can_queue = MVS_SOC_CAN_QUEUE;
@@ -710,6 +712,14 @@ static int __init mvs_init(void)
710 if (!mvs_stt) 712 if (!mvs_stt)
711 return -ENOMEM; 713 return -ENOMEM;
712 714
715 mvs_task_list_cache = kmem_cache_create("mvs_task_list", sizeof(struct mvs_task_list),
716 0, SLAB_HWCACHE_ALIGN, NULL);
717 if (!mvs_task_list_cache) {
718 rc = -ENOMEM;
719 mv_printk("%s: mvs_task_list_cache alloc failed! \n", __func__);
720 goto err_out;
721 }
722
713 rc = pci_register_driver(&mvs_pci_driver); 723 rc = pci_register_driver(&mvs_pci_driver);
714 724
715 if (rc) 725 if (rc)
@@ -726,6 +736,7 @@ static void __exit mvs_exit(void)
726{ 736{
727 pci_unregister_driver(&mvs_pci_driver); 737 pci_unregister_driver(&mvs_pci_driver);
728 sas_release_transport(mvs_stt); 738 sas_release_transport(mvs_stt);
739 kmem_cache_destroy(mvs_task_list_cache);
729} 740}
730 741
731module_init(mvs_init); 742module_init(mvs_init);
diff --git a/drivers/scsi/mvsas/mv_sas.c b/drivers/scsi/mvsas/mv_sas.c
index adedaa916ecb..0ef27425c447 100644
--- a/drivers/scsi/mvsas/mv_sas.c
+++ b/drivers/scsi/mvsas/mv_sas.c
@@ -3,6 +3,7 @@
3 * 3 *
4 * Copyright 2007 Red Hat, Inc. 4 * Copyright 2007 Red Hat, Inc.
5 * Copyright 2008 Marvell. <kewei@marvell.com> 5 * Copyright 2008 Marvell. <kewei@marvell.com>
6 * Copyright 2009-2011 Marvell. <yuxiangl@marvell.com>
6 * 7 *
7 * This file is licensed under GPLv2. 8 * This file is licensed under GPLv2.
8 * 9 *
@@ -862,178 +863,286 @@ static int mvs_task_prep_ssp(struct mvs_info *mvi,
862} 863}
863 864
864#define DEV_IS_GONE(mvi_dev) ((!mvi_dev || (mvi_dev->dev_type == NO_DEVICE))) 865#define DEV_IS_GONE(mvi_dev) ((!mvi_dev || (mvi_dev->dev_type == NO_DEVICE)))
865static int mvs_task_exec(struct sas_task *task, const int num, gfp_t gfp_flags, 866static int mvs_task_prep(struct sas_task *task, struct mvs_info *mvi, int is_tmf,
866 struct completion *completion,int is_tmf, 867 struct mvs_tmf_task *tmf, int *pass)
867 struct mvs_tmf_task *tmf)
868{ 868{
869 struct domain_device *dev = task->dev; 869 struct domain_device *dev = task->dev;
870 struct mvs_device *mvi_dev = (struct mvs_device *)dev->lldd_dev; 870 struct mvs_device *mvi_dev = dev->lldd_dev;
871 struct mvs_info *mvi = mvi_dev->mvi_info;
872 struct mvs_task_exec_info tei; 871 struct mvs_task_exec_info tei;
873 struct sas_task *t = task;
874 struct mvs_slot_info *slot; 872 struct mvs_slot_info *slot;
875 u32 tag = 0xdeadbeef, rc, n_elem = 0; 873 u32 tag = 0xdeadbeef, n_elem = 0;
876 u32 n = num, pass = 0; 874 int rc = 0;
877 unsigned long flags = 0, flags_libsas = 0;
878 875
879 if (!dev->port) { 876 if (!dev->port) {
880 struct task_status_struct *tsm = &t->task_status; 877 struct task_status_struct *tsm = &task->task_status;
881 878
882 tsm->resp = SAS_TASK_UNDELIVERED; 879 tsm->resp = SAS_TASK_UNDELIVERED;
883 tsm->stat = SAS_PHY_DOWN; 880 tsm->stat = SAS_PHY_DOWN;
881 /*
882 * libsas will use dev->port, should
883 * not call task_done for sata
884 */
884 if (dev->dev_type != SATA_DEV) 885 if (dev->dev_type != SATA_DEV)
885 t->task_done(t); 886 task->task_done(task);
886 return 0; 887 return rc;
887 } 888 }
888 889
889 spin_lock_irqsave(&mvi->lock, flags); 890 if (DEV_IS_GONE(mvi_dev)) {
890 do { 891 if (mvi_dev)
891 dev = t->dev; 892 mv_dprintk("device %d not ready.\n",
892 mvi_dev = dev->lldd_dev; 893 mvi_dev->device_id);
893 if (DEV_IS_GONE(mvi_dev)) { 894 else
894 if (mvi_dev) 895 mv_dprintk("device %016llx not ready.\n",
895 mv_dprintk("device %d not ready.\n", 896 SAS_ADDR(dev->sas_addr));
896 mvi_dev->device_id);
897 else
898 mv_dprintk("device %016llx not ready.\n",
899 SAS_ADDR(dev->sas_addr));
900 897
901 rc = SAS_PHY_DOWN; 898 rc = SAS_PHY_DOWN;
902 goto out_done; 899 return rc;
903 } 900 }
901 tei.port = dev->port->lldd_port;
902 if (tei.port && !tei.port->port_attached && !tmf) {
903 if (sas_protocol_ata(task->task_proto)) {
904 struct task_status_struct *ts = &task->task_status;
905 mv_dprintk("SATA/STP port %d does not attach"
906 "device.\n", dev->port->id);
907 ts->resp = SAS_TASK_COMPLETE;
908 ts->stat = SAS_PHY_DOWN;
904 909
905 if (dev->port->id >= mvi->chip->n_phy) 910 task->task_done(task);
906 tei.port = &mvi->port[dev->port->id - mvi->chip->n_phy];
907 else
908 tei.port = &mvi->port[dev->port->id];
909
910 if (tei.port && !tei.port->port_attached) {
911 if (sas_protocol_ata(t->task_proto)) {
912 struct task_status_struct *ts = &t->task_status;
913
914 mv_dprintk("port %d does not"
915 "attached device.\n", dev->port->id);
916 ts->stat = SAS_PROTO_RESPONSE;
917 ts->stat = SAS_PHY_DOWN;
918 spin_unlock_irqrestore(dev->sata_dev.ap->lock,
919 flags_libsas);
920 spin_unlock_irqrestore(&mvi->lock, flags);
921 t->task_done(t);
922 spin_lock_irqsave(&mvi->lock, flags);
923 spin_lock_irqsave(dev->sata_dev.ap->lock,
924 flags_libsas);
925 if (n > 1)
926 t = list_entry(t->list.next,
927 struct sas_task, list);
928 continue;
929 } else {
930 struct task_status_struct *ts = &t->task_status;
931 ts->resp = SAS_TASK_UNDELIVERED;
932 ts->stat = SAS_PHY_DOWN;
933 t->task_done(t);
934 if (n > 1)
935 t = list_entry(t->list.next,
936 struct sas_task, list);
937 continue;
938 }
939 }
940 911
941 if (!sas_protocol_ata(t->task_proto)) {
942 if (t->num_scatter) {
943 n_elem = dma_map_sg(mvi->dev,
944 t->scatter,
945 t->num_scatter,
946 t->data_dir);
947 if (!n_elem) {
948 rc = -ENOMEM;
949 goto err_out;
950 }
951 }
952 } else { 912 } else {
953 n_elem = t->num_scatter; 913 struct task_status_struct *ts = &task->task_status;
914 mv_dprintk("SAS port %d does not attach"
915 "device.\n", dev->port->id);
916 ts->resp = SAS_TASK_UNDELIVERED;
917 ts->stat = SAS_PHY_DOWN;
918 task->task_done(task);
954 } 919 }
920 return rc;
921 }
955 922
956 rc = mvs_tag_alloc(mvi, &tag); 923 if (!sas_protocol_ata(task->task_proto)) {
957 if (rc) 924 if (task->num_scatter) {
958 goto err_out; 925 n_elem = dma_map_sg(mvi->dev,
926 task->scatter,
927 task->num_scatter,
928 task->data_dir);
929 if (!n_elem) {
930 rc = -ENOMEM;
931 goto prep_out;
932 }
933 }
934 } else {
935 n_elem = task->num_scatter;
936 }
959 937
960 slot = &mvi->slot_info[tag]; 938 rc = mvs_tag_alloc(mvi, &tag);
939 if (rc)
940 goto err_out;
961 941
942 slot = &mvi->slot_info[tag];
962 943
963 t->lldd_task = NULL; 944 task->lldd_task = NULL;
964 slot->n_elem = n_elem; 945 slot->n_elem = n_elem;
965 slot->slot_tag = tag; 946 slot->slot_tag = tag;
966 memset(slot->buf, 0, MVS_SLOT_BUF_SZ); 947
948 slot->buf = pci_pool_alloc(mvi->dma_pool, GFP_ATOMIC, &slot->buf_dma);
949 if (!slot->buf)
950 goto err_out_tag;
951 memset(slot->buf, 0, MVS_SLOT_BUF_SZ);
952
953 tei.task = task;
954 tei.hdr = &mvi->slot[tag];
955 tei.tag = tag;
956 tei.n_elem = n_elem;
957 switch (task->task_proto) {
958 case SAS_PROTOCOL_SMP:
959 rc = mvs_task_prep_smp(mvi, &tei);
960 break;
961 case SAS_PROTOCOL_SSP:
962 rc = mvs_task_prep_ssp(mvi, &tei, is_tmf, tmf);
963 break;
964 case SAS_PROTOCOL_SATA:
965 case SAS_PROTOCOL_STP:
966 case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP:
967 rc = mvs_task_prep_ata(mvi, &tei);
968 break;
969 default:
970 dev_printk(KERN_ERR, mvi->dev,
971 "unknown sas_task proto: 0x%x\n",
972 task->task_proto);
973 rc = -EINVAL;
974 break;
975 }
967 976
968 tei.task = t; 977 if (rc) {
969 tei.hdr = &mvi->slot[tag]; 978 mv_dprintk("rc is %x\n", rc);
970 tei.tag = tag; 979 goto err_out_slot_buf;
971 tei.n_elem = n_elem; 980 }
972 switch (t->task_proto) { 981 slot->task = task;
973 case SAS_PROTOCOL_SMP: 982 slot->port = tei.port;
974 rc = mvs_task_prep_smp(mvi, &tei); 983 task->lldd_task = slot;
975 break; 984 list_add_tail(&slot->entry, &tei.port->list);
976 case SAS_PROTOCOL_SSP: 985 spin_lock(&task->task_state_lock);
977 rc = mvs_task_prep_ssp(mvi, &tei, is_tmf, tmf); 986 task->task_state_flags |= SAS_TASK_AT_INITIATOR;
978 break; 987 spin_unlock(&task->task_state_lock);
979 case SAS_PROTOCOL_SATA:
980 case SAS_PROTOCOL_STP:
981 case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP:
982 rc = mvs_task_prep_ata(mvi, &tei);
983 break;
984 default:
985 dev_printk(KERN_ERR, mvi->dev,
986 "unknown sas_task proto: 0x%x\n",
987 t->task_proto);
988 rc = -EINVAL;
989 break;
990 }
991 988
992 if (rc) { 989 mvs_hba_memory_dump(mvi, tag, task->task_proto);
993 mv_dprintk("rc is %x\n", rc); 990 mvi_dev->running_req++;
994 goto err_out_tag; 991 ++(*pass);
995 } 992 mvi->tx_prod = (mvi->tx_prod + 1) & (MVS_CHIP_SLOT_SZ - 1);
996 slot->task = t;
997 slot->port = tei.port;
998 t->lldd_task = slot;
999 list_add_tail(&slot->entry, &tei.port->list);
1000 /* TODO: select normal or high priority */
1001 spin_lock(&t->task_state_lock);
1002 t->task_state_flags |= SAS_TASK_AT_INITIATOR;
1003 spin_unlock(&t->task_state_lock);
1004
1005 mvs_hba_memory_dump(mvi, tag, t->task_proto);
1006 mvi_dev->running_req++;
1007 ++pass;
1008 mvi->tx_prod = (mvi->tx_prod + 1) & (MVS_CHIP_SLOT_SZ - 1);
1009 if (n > 1)
1010 t = list_entry(t->list.next, struct sas_task, list);
1011 if (likely(pass))
1012 MVS_CHIP_DISP->start_delivery(mvi, (mvi->tx_prod - 1) &
1013 (MVS_CHIP_SLOT_SZ - 1));
1014 993
1015 } while (--n); 994 return rc;
1016 rc = 0;
1017 goto out_done;
1018 995
996err_out_slot_buf:
997 pci_pool_free(mvi->dma_pool, slot->buf, slot->buf_dma);
1019err_out_tag: 998err_out_tag:
1020 mvs_tag_free(mvi, tag); 999 mvs_tag_free(mvi, tag);
1021err_out: 1000err_out:
1022 1001
1023 dev_printk(KERN_ERR, mvi->dev, "mvsas exec failed[%d]!\n", rc); 1002 dev_printk(KERN_ERR, mvi->dev, "mvsas prep failed[%d]!\n", rc);
1024 if (!sas_protocol_ata(t->task_proto)) 1003 if (!sas_protocol_ata(task->task_proto))
1025 if (n_elem) 1004 if (n_elem)
1026 dma_unmap_sg(mvi->dev, t->scatter, n_elem, 1005 dma_unmap_sg(mvi->dev, task->scatter, n_elem,
1027 t->data_dir); 1006 task->data_dir);
1028out_done: 1007prep_out:
1008 return rc;
1009}
1010
1011static struct mvs_task_list *mvs_task_alloc_list(int *num, gfp_t gfp_flags)
1012{
1013 struct mvs_task_list *first = NULL;
1014
1015 for (; *num > 0; --*num) {
1016 struct mvs_task_list *mvs_list = kmem_cache_zalloc(mvs_task_list_cache, gfp_flags);
1017
1018 if (!mvs_list)
1019 break;
1020
1021 INIT_LIST_HEAD(&mvs_list->list);
1022 if (!first)
1023 first = mvs_list;
1024 else
1025 list_add_tail(&mvs_list->list, &first->list);
1026
1027 }
1028
1029 return first;
1030}
1031
1032static inline void mvs_task_free_list(struct mvs_task_list *mvs_list)
1033{
1034 LIST_HEAD(list);
1035 struct list_head *pos, *a;
1036 struct mvs_task_list *mlist = NULL;
1037
1038 __list_add(&list, mvs_list->list.prev, &mvs_list->list);
1039
1040 list_for_each_safe(pos, a, &list) {
1041 list_del_init(pos);
1042 mlist = list_entry(pos, struct mvs_task_list, list);
1043 kmem_cache_free(mvs_task_list_cache, mlist);
1044 }
1045}
1046
1047static int mvs_task_exec(struct sas_task *task, const int num, gfp_t gfp_flags,
1048 struct completion *completion, int is_tmf,
1049 struct mvs_tmf_task *tmf)
1050{
1051 struct domain_device *dev = task->dev;
1052 struct mvs_info *mvi = NULL;
1053 u32 rc = 0;
1054 u32 pass = 0;
1055 unsigned long flags = 0;
1056
1057 mvi = ((struct mvs_device *)task->dev->lldd_dev)->mvi_info;
1058
1059 if ((dev->dev_type == SATA_DEV) && (dev->sata_dev.ap != NULL))
1060 spin_unlock_irq(dev->sata_dev.ap->lock);
1061
1062 spin_lock_irqsave(&mvi->lock, flags);
1063 rc = mvs_task_prep(task, mvi, is_tmf, tmf, &pass);
1064 if (rc)
1065 dev_printk(KERN_ERR, mvi->dev, "mvsas exec failed[%d]!\n", rc);
1066
1067 if (likely(pass))
1068 MVS_CHIP_DISP->start_delivery(mvi, (mvi->tx_prod - 1) &
1069 (MVS_CHIP_SLOT_SZ - 1));
1029 spin_unlock_irqrestore(&mvi->lock, flags); 1070 spin_unlock_irqrestore(&mvi->lock, flags);
1071
1072 if ((dev->dev_type == SATA_DEV) && (dev->sata_dev.ap != NULL))
1073 spin_lock_irq(dev->sata_dev.ap->lock);
1074
1075 return rc;
1076}
1077
1078static int mvs_collector_task_exec(struct sas_task *task, const int num, gfp_t gfp_flags,
1079 struct completion *completion, int is_tmf,
1080 struct mvs_tmf_task *tmf)
1081{
1082 struct domain_device *dev = task->dev;
1083 struct mvs_prv_info *mpi = dev->port->ha->lldd_ha;
1084 struct mvs_info *mvi = NULL;
1085 struct sas_task *t = task;
1086 struct mvs_task_list *mvs_list = NULL, *a;
1087 LIST_HEAD(q);
1088 int pass[2] = {0};
1089 u32 rc = 0;
1090 u32 n = num;
1091 unsigned long flags = 0;
1092
1093 mvs_list = mvs_task_alloc_list(&n, gfp_flags);
1094 if (n) {
1095 printk(KERN_ERR "%s: mvs alloc list failed.\n", __func__);
1096 rc = -ENOMEM;
1097 goto free_list;
1098 }
1099
1100 __list_add(&q, mvs_list->list.prev, &mvs_list->list);
1101
1102 list_for_each_entry(a, &q, list) {
1103 a->task = t;
1104 t = list_entry(t->list.next, struct sas_task, list);
1105 }
1106
1107 list_for_each_entry(a, &q , list) {
1108
1109 t = a->task;
1110 mvi = ((struct mvs_device *)t->dev->lldd_dev)->mvi_info;
1111
1112 spin_lock_irqsave(&mvi->lock, flags);
1113 rc = mvs_task_prep(t, mvi, is_tmf, tmf, &pass[mvi->id]);
1114 if (rc)
1115 dev_printk(KERN_ERR, mvi->dev, "mvsas exec failed[%d]!\n", rc);
1116 spin_unlock_irqrestore(&mvi->lock, flags);
1117 }
1118
1119 if (likely(pass[0]))
1120 MVS_CHIP_DISP->start_delivery(mpi->mvi[0],
1121 (mpi->mvi[0]->tx_prod - 1) & (MVS_CHIP_SLOT_SZ - 1));
1122
1123 if (likely(pass[1]))
1124 MVS_CHIP_DISP->start_delivery(mpi->mvi[1],
1125 (mpi->mvi[1]->tx_prod - 1) & (MVS_CHIP_SLOT_SZ - 1));
1126
1127 list_del_init(&q);
1128
1129free_list:
1130 if (mvs_list)
1131 mvs_task_free_list(mvs_list);
1132
1030 return rc; 1133 return rc;
1031} 1134}
1032 1135
1033int mvs_queue_command(struct sas_task *task, const int num, 1136int mvs_queue_command(struct sas_task *task, const int num,
1034 gfp_t gfp_flags) 1137 gfp_t gfp_flags)
1035{ 1138{
1036 return mvs_task_exec(task, num, gfp_flags, NULL, 0, NULL); 1139 struct mvs_device *mvi_dev = task->dev->lldd_dev;
1140 struct sas_ha_struct *sas = mvi_dev->mvi_info->sas;
1141
1142 if (sas->lldd_max_execute_num < 2)
1143 return mvs_task_exec(task, num, gfp_flags, NULL, 0, NULL);
1144 else
1145 return mvs_collector_task_exec(task, num, gfp_flags, NULL, 0, NULL);
1037} 1146}
1038 1147
1039static void mvs_slot_free(struct mvs_info *mvi, u32 rx_desc) 1148static void mvs_slot_free(struct mvs_info *mvi, u32 rx_desc)
@@ -1067,6 +1176,11 @@ static void mvs_slot_task_free(struct mvs_info *mvi, struct sas_task *task,
1067 /* do nothing */ 1176 /* do nothing */
1068 break; 1177 break;
1069 } 1178 }
1179
1180 if (slot->buf) {
1181 pci_pool_free(mvi->dma_pool, slot->buf, slot->buf_dma);
1182 slot->buf = NULL;
1183 }
1070 list_del_init(&slot->entry); 1184 list_del_init(&slot->entry);
1071 task->lldd_task = NULL; 1185 task->lldd_task = NULL;
1072 slot->task = NULL; 1186 slot->task = NULL;
@@ -1255,6 +1369,7 @@ static void mvs_port_notify_formed(struct asd_sas_phy *sas_phy, int lock)
1255 spin_lock_irqsave(&mvi->lock, flags); 1369 spin_lock_irqsave(&mvi->lock, flags);
1256 port->port_attached = 1; 1370 port->port_attached = 1;
1257 phy->port = port; 1371 phy->port = port;
1372 sas_port->lldd_port = port;
1258 if (phy->phy_type & PORT_TYPE_SAS) { 1373 if (phy->phy_type & PORT_TYPE_SAS) {
1259 port->wide_port_phymap = sas_port->phy_mask; 1374 port->wide_port_phymap = sas_port->phy_mask;
1260 mv_printk("set wide port phy map %x\n", sas_port->phy_mask); 1375 mv_printk("set wide port phy map %x\n", sas_port->phy_mask);
diff --git a/drivers/scsi/mvsas/mv_sas.h b/drivers/scsi/mvsas/mv_sas.h
index 77ddc7c1e5f2..1367d8b9350d 100644
--- a/drivers/scsi/mvsas/mv_sas.h
+++ b/drivers/scsi/mvsas/mv_sas.h
@@ -3,6 +3,7 @@
3 * 3 *
4 * Copyright 2007 Red Hat, Inc. 4 * Copyright 2007 Red Hat, Inc.
5 * Copyright 2008 Marvell. <kewei@marvell.com> 5 * Copyright 2008 Marvell. <kewei@marvell.com>
6 * Copyright 2009-2011 Marvell. <yuxiangl@marvell.com>
6 * 7 *
7 * This file is licensed under GPLv2. 8 * This file is licensed under GPLv2.
8 * 9 *
@@ -67,6 +68,7 @@ extern struct mvs_tgt_initiator mvs_tgt;
67extern struct mvs_info *tgt_mvi; 68extern struct mvs_info *tgt_mvi;
68extern const struct mvs_dispatch mvs_64xx_dispatch; 69extern const struct mvs_dispatch mvs_64xx_dispatch;
69extern const struct mvs_dispatch mvs_94xx_dispatch; 70extern const struct mvs_dispatch mvs_94xx_dispatch;
71extern struct kmem_cache *mvs_task_list_cache;
70 72
71#define DEV_IS_EXPANDER(type) \ 73#define DEV_IS_EXPANDER(type) \
72 ((type == EDGE_DEV) || (type == FANOUT_DEV)) 74 ((type == EDGE_DEV) || (type == FANOUT_DEV))
@@ -341,6 +343,7 @@ struct mvs_info {
341 dma_addr_t bulk_buffer_dma; 343 dma_addr_t bulk_buffer_dma;
342#define TRASH_BUCKET_SIZE 0x20000 344#define TRASH_BUCKET_SIZE 0x20000
343#endif 345#endif
346 void *dma_pool;
344 struct mvs_slot_info slot_info[0]; 347 struct mvs_slot_info slot_info[0];
345}; 348};
346 349
@@ -367,6 +370,11 @@ struct mvs_task_exec_info {
367 int n_elem; 370 int n_elem;
368}; 371};
369 372
373struct mvs_task_list {
374 struct sas_task *task;
375 struct list_head list;
376};
377
370 378
371/******************** function prototype *********************/ 379/******************** function prototype *********************/
372void mvs_get_sas_addr(void *buf, u32 buflen); 380void mvs_get_sas_addr(void *buf, u32 buflen);