diff options
author | Xiangliang Yu <yuxiangl@marvell.com> | 2011-04-26 09:36:51 -0400 |
---|---|---|
committer | James Bottomley <James.Bottomley@suse.de> | 2011-05-01 13:08:03 -0400 |
commit | 0b15fb1fdfd403726542cb6111bc916b7a9f7fad (patch) | |
tree | 3f3d2d7516aad34f7ce68cbb317781e7aa7fd41a /drivers/scsi/mvsas | |
parent | 8214028344b4a38aabf73d95347e1e35538c75f6 (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/Kconfig | 1 | ||||
-rw-r--r-- | drivers/scsi/mvsas/Makefile | 1 | ||||
-rw-r--r-- | drivers/scsi/mvsas/mv_64xx.c | 1 | ||||
-rw-r--r-- | drivers/scsi/mvsas/mv_64xx.h | 1 | ||||
-rw-r--r-- | drivers/scsi/mvsas/mv_94xx.c | 1 | ||||
-rw-r--r-- | drivers/scsi/mvsas/mv_94xx.h | 1 | ||||
-rw-r--r-- | drivers/scsi/mvsas/mv_chips.h | 1 | ||||
-rw-r--r-- | drivers/scsi/mvsas/mv_defs.h | 1 | ||||
-rw-r--r-- | drivers/scsi/mvsas/mv_init.c | 47 | ||||
-rw-r--r-- | drivers/scsi/mvsas/mv_sas.c | 383 | ||||
-rw-r--r-- | drivers/scsi/mvsas/mv_sas.h | 8 |
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 | ||
29 | static int lldd_max_execute_num = 1; | ||
30 | module_param_named(collector, lldd_max_execute_num, int, S_IRUGO); | ||
31 | MODULE_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 | |||
28 | static struct scsi_transport_template *mvs_stt; | 37 | static struct scsi_transport_template *mvs_stt; |
38 | struct kmem_cache *mvs_task_list_cache; | ||
29 | static const struct mvs_chip_info mvs_chips[] = { | 39 | static 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 | ||
110 | static void mvs_free(struct mvs_info *mvi) | 120 | static 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) | |||
215 | static int __devinit mvs_alloc(struct mvs_info *mvi, struct Scsi_Host *shost) | 220 | static 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 | ||
731 | module_init(mvs_init); | 742 | module_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))) |
865 | static int mvs_task_exec(struct sas_task *task, const int num, gfp_t gfp_flags, | 866 | static 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 | ||
996 | err_out_slot_buf: | ||
997 | pci_pool_free(mvi->dma_pool, slot->buf, slot->buf_dma); | ||
1019 | err_out_tag: | 998 | err_out_tag: |
1020 | mvs_tag_free(mvi, tag); | 999 | mvs_tag_free(mvi, tag); |
1021 | err_out: | 1000 | err_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); |
1028 | out_done: | 1007 | prep_out: |
1008 | return rc; | ||
1009 | } | ||
1010 | |||
1011 | static 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 | |||
1032 | static 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 | |||
1047 | static 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 | |||
1078 | static 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 | |||
1129 | free_list: | ||
1130 | if (mvs_list) | ||
1131 | mvs_task_free_list(mvs_list); | ||
1132 | |||
1030 | return rc; | 1133 | return rc; |
1031 | } | 1134 | } |
1032 | 1135 | ||
1033 | int mvs_queue_command(struct sas_task *task, const int num, | 1136 | int 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 | ||
1039 | static void mvs_slot_free(struct mvs_info *mvi, u32 rx_desc) | 1148 | static 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; | |||
67 | extern struct mvs_info *tgt_mvi; | 68 | extern struct mvs_info *tgt_mvi; |
68 | extern const struct mvs_dispatch mvs_64xx_dispatch; | 69 | extern const struct mvs_dispatch mvs_64xx_dispatch; |
69 | extern const struct mvs_dispatch mvs_94xx_dispatch; | 70 | extern const struct mvs_dispatch mvs_94xx_dispatch; |
71 | extern 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 | ||
373 | struct mvs_task_list { | ||
374 | struct sas_task *task; | ||
375 | struct list_head list; | ||
376 | }; | ||
377 | |||
370 | 378 | ||
371 | /******************** function prototype *********************/ | 379 | /******************** function prototype *********************/ |
372 | void mvs_get_sas_addr(void *buf, u32 buflen); | 380 | void mvs_get_sas_addr(void *buf, u32 buflen); |