aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/mvsas/mv_sas.c
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/mv_sas.c
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/mv_sas.c')
-rw-r--r--drivers/scsi/mvsas/mv_sas.c383
1 files changed, 249 insertions, 134 deletions
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);